New schema for pixels and links.

This commit is contained in:
Mike Cao 2025-08-13 20:27:54 -07:00
parent c60e8b3d23
commit 88639dfe83
67 changed files with 993 additions and 208 deletions

View file

@ -7,21 +7,13 @@ import semver from 'semver';
import { PrismaClient } from '@prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
const MIN_VERSION = '9.4.0';
if (process.env.SKIP_DB_CHECK) {
console.log('Skipping database check.');
process.exit(0);
}
function getDatabaseType(url = process.env.DATABASE_URL) {
const type = url && url.split(':')[0];
if (type === 'postgres') {
return 'postgresql';
}
return type;
}
const url = new URL(process.env.DATABASE_URL);
const adapter = new PrismaPg(
@ -61,35 +53,15 @@ async function checkDatabaseVersion() {
const query = await prisma.$queryRaw`select version() as version`;
const version = semver.valid(semver.coerce(query[0].version));
const databaseType = getDatabaseType();
const minVersion = databaseType === 'postgresql' ? '9.4.0' : '5.7.0';
if (semver.lt(version, minVersion)) {
if (semver.lt(version, MIN_VERSION)) {
throw new Error(
`Database version is not compatible. Please upgrade ${databaseType} version to ${minVersion} or greater`,
`Database version is not compatible. Please upgrade to ${MIN_VERSION} or greater.`,
);
}
success('Database version check successful.');
}
async function checkV1Tables() {
try {
// check for v1 migrations before v2 release date
const record =
await prisma.$queryRaw`select * from _prisma_migrations where started_at < '2023-04-17'`;
if (record.length > 0) {
error(
'Umami v1 tables detected. For how to upgrade from v1 to v2 go to https://umami.is/docs/migrate-v1-v2.',
);
process.exit(1);
}
} catch {
// Ignore
}
}
async function applyMigration() {
if (!process.env.SKIP_DB_MIGRATION) {
console.log(execSync('prisma migrate deploy').toString());
@ -100,13 +72,7 @@ async function applyMigration() {
(async () => {
let err = false;
for (const fn of [
checkEnv,
checkConnection,
checkDatabaseVersion,
checkV1Tables,
applyMigration,
]) {
for (const fn of [checkEnv, checkConnection, checkDatabaseVersion, applyMigration]) {
try {
await fn();
} catch (e) {

View file

@ -1,32 +0,0 @@
/* eslint-disable no-console */
import 'dotenv/config';
import fse from 'fs-extra';
import path from 'node:path';
import del from 'del';
function getDatabaseType(url = process.env.DATABASE_URL) {
const type = process.env.DATABASE_TYPE || (url && url.split(':')[0]);
if (type === 'postgres') {
return 'postgresql';
}
return type;
}
const databaseType = getDatabaseType();
if (!databaseType || !['mysql', 'postgresql'].includes(databaseType)) {
throw new Error('Missing or invalid database');
}
console.log(`Database type detected: ${databaseType}`);
const src = path.resolve(process.cwd(), `db/${databaseType}`);
const dest = path.resolve(process.cwd(), 'prisma');
del.sync(dest);
fse.copySync(src, dest);
console.log(`Copied ${src} to ${dest}`);

View file

@ -1,49 +0,0 @@
-----------------------------------------------------
-- PostgreSQL
-----------------------------------------------------
UPDATE "website_event" we
SET fbclid = LEFT(url.fbclid, 255),
gclid = LEFT(url.gclid, 255),
li_fat_id = LEFT(url.li_fat_id, 255),
msclkid = LEFT(url.msclkid, 255),
ttclid = LEFT(url.ttclid, 255),
twclid = LEFT(url.twclid, 255),
utm_campaign = LEFT(url.utm_campaign, 255),
utm_content = LEFT(url.utm_content, 255),
utm_medium = LEFT(url.utm_medium, 255),
utm_source = LEFT(url.utm_source, 255),
utm_term = LEFT(url.utm_term, 255)
FROM (SELECT event_id, website_id, session_id,
(regexp_matches(url_query, '(?:[&?]|^)fbclid=([^&]+)', 'i'))[1] AS fbclid,
(regexp_matches(url_query, '(?:[&?]|^)gclid=([^&]+)', 'i'))[1] AS gclid,
(regexp_matches(url_query, '(?:[&?]|^)li_fat_id=([^&]+)', 'i'))[1] AS li_fat_id,
(regexp_matches(url_query, '(?:[&?]|^)msclkid=([^&]+)', 'i'))[1] AS msclkid,
(regexp_matches(url_query, '(?:[&?]|^)ttclid=([^&]+)', 'i'))[1] AS ttclid,
(regexp_matches(url_query, '(?:[&?]|^)twclid=([^&]+)', 'i'))[1] AS twclid,
(regexp_matches(url_query, '(?:[&?]|^)utm_campaign=([^&]+)', 'i'))[1] AS utm_campaign,
(regexp_matches(url_query, '(?:[&?]|^)utm_content=([^&]+)', 'i'))[1] AS utm_content,
(regexp_matches(url_query, '(?:[&?]|^)utm_medium=([^&]+)', 'i'))[1] AS utm_medium,
(regexp_matches(url_query, '(?:[&?]|^)utm_source=([^&]+)', 'i'))[1] AS utm_source,
(regexp_matches(url_query, '(?:[&?]|^)utm_term=([^&]+)', 'i'))[1] AS utm_term
FROM "website_event"
WHERE url_query IS NOT NULL) url
WHERE we.event_id = url.event_id
and we.session_id = url.session_id
and we.website_id = url.website_id;
-----------------------------------------------------
-- MySQL
-----------------------------------------------------
UPDATE `website_event`
SET fbclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)fbclid=[^&]+'), '=', -1), '&', 1), 255),
gclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)gclid=[^&]+'), '=', -1), '&', 1), 255),
li_fat_id = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)li_fat_id=[^&]+'), '=', -1), '&', 1), 255),
msclkid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)msclkid=[^&]+'), '=', -1), '&', 1), 255),
ttclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)ttclid=[^&]+'), '=', -1), '&', 1), 255),
twclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)twclid=[^&]+'), '=', -1), '&', 1), 255),
utm_campaign = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_campaign=[^&]+'), '=', -1), '&', 1), 255),
utm_content = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_content=[^&]+'), '=', -1), '&', 1), 255),
utm_medium = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_medium=[^&]+'), '=', -1), '&', 1), 255),
utm_source = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_source=[^&]+'), '=', -1), '&', 1), 255),
utm_term = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_term=[^&]+'), '=', -1), '&', 1), 255)
WHERE url_query IS NOT NULL;

View file

@ -1,41 +0,0 @@
-----------------------------------------------------
-- PostgreSQL
-----------------------------------------------------
INSERT INTO "revenue"
SELECT gen_random_uuid() revenue_id,
ed.website_id,
we.session_id,
we.event_id,
we.event_name,
currency.string_value currency,
coalesce(ed.number_value, cast(ed.string_value as numeric(19,4))) revenue,
ed.created_at
FROM event_data ed
JOIN website_event we
ON we.event_id = ed.website_event_id
JOIN (SELECT website_event_id, string_value
FROM event_data
WHERE data_key ilike '%currency%') currency
ON currency.website_event_id = ed.website_event_id
WHERE ed.data_key ilike '%revenue%';
-----------------------------------------------------
-- MySQL
-----------------------------------------------------
INSERT INTO `revenue`
SELECT UUID() revenue_id,
ed.website_id,
we.session_id,
we.event_id,
we.event_name,
currency.string_value currency,
coalesce(ed.number_value, cast(ed.string_value as decimal(19,4))) revenue,
ed.created_at
FROM event_data ed
JOIN website_event we
ON we.event_id = ed.website_event_id
JOIN (SELECT website_event_id, string_value
FROM event_data
WHERE data_key like '%currency%') currency
ON currency.website_event_id = ed.website_event_id
WHERE ed.data_key like '%revenue%';