From b46a0c179f917bd39e4144448896d0a5f0a28974 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 2 Jan 2023 16:34:58 -0800 Subject: [PATCH 01/25] add migration node script --- scripts/migration.js | 127 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 scripts/migration.js diff --git a/scripts/migration.js b/scripts/migration.js new file mode 100644 index 00000000..d07a8292 --- /dev/null +++ b/scripts/migration.js @@ -0,0 +1,127 @@ +/* eslint-disable no-console */ +require('dotenv').config(); +const { PrismaClient } = require('@prisma/client'); +const chalk = require('chalk'); +// const spawn = require('cross-spawn'); +// const { execSync } = require('child_process'); + +const prisma = new PrismaClient(); + +function success(msg) { + console.log(chalk.greenBright(`✓ ${msg}`)); +} + +// function error(msg) { +// console.log(chalk.redBright(`✗ ${msg}`)); +// } + +async function checkEnv() { + if (!process.env.DATABASE_URL) { + throw new Error('DATABASE_URL is not defined.'); + } else { + success('DATABASE_URL is defined.'); + } +} + +async function checkConnection() { + try { + await prisma.$connect(); + + success('Database connection successful.'); + } catch (e) { + throw new Error('Unable to connect to the database.'); + } +} + +async function checkTables() { + try { + await prisma.$queryRaw`select * from user limit 1`; + + success('Database tables found.'); + } catch (e) { + throw new Error('Database tables not found.'); + } +} + +async function dropKeys() { + try { + // drop keys + await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`; + + success('Dropped v1 database keys.'); + } catch (e) { + throw new Error('Failed to drop v1 database keys.'); + } +} + +async function renameTables() { + try { + // rename tables + await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "_prisma_migrations_v1";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "account_v1";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "event_v1";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "event_data_v1";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "pageview_v1";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "session_v1";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "website_v1";`; + + success('Renamed v1 database tables.'); + } catch (e) { + throw new Error('Failed to rename v1 database tables.'); + } +} + +async function dropIndexes() { + try { + // drop indexes + await prisma.$executeRaw`DROP INDEX IF EXISTS "account_account_uuid_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "event_created_at_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "event_event_uuid_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "event_session_id_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "event_website_id_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_created_at_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_session_id_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_website_id_created_at_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_website_id_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_website_id_session_id_created_at_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_uuid_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_uuid_idx";`; + + success('Dropped v1 database indexes.'); + } catch (e) { + throw new Error('Failed to drop v1 database indexes.'); + } +} + +// async function checkNewTables() { +// try { +// await prisma.$queryRaw`select * from website_event limit 1`; + +// success('Database v2 tables found.'); +// } catch (e) { +// throw new Error('Database v2 tables not found.'); +// } +// } + +(async () => { + let err = false; + for (let fn of [checkEnv, checkConnection, checkTables, dropKeys, renameTables, dropIndexes]) { + try { + await fn(); + } catch (e) { + console.log(chalk.red(`✗ ${e.message}`)); + err = true; + } finally { + await prisma.$disconnect(); + if (err) { + process.exit(1); + } + } + } +})(); From 660c810ec1b6e98b08fccbe28534ed7ddc01b324 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 2 Jan 2023 16:47:48 -0800 Subject: [PATCH 02/25] add prisma table PK --- scripts/migration.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/migration.js b/scripts/migration.js index d07a8292..6a5b4867 100644 --- a/scripts/migration.js +++ b/scripts/migration.js @@ -46,6 +46,7 @@ async function checkTables() { async function dropKeys() { try { // drop keys + await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`; await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`; await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`; await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`; From 82e6728e1e9c291c52918b766e2c5b9dbd389039 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 2 Jan 2023 16:53:20 -0800 Subject: [PATCH 03/25] fix index drop --- scripts/migration.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/scripts/migration.js b/scripts/migration.js index 6a5b4867..6c27497c 100644 --- a/scripts/migration.js +++ b/scripts/migration.js @@ -78,21 +78,15 @@ async function renameTables() { async function dropIndexes() { try { // drop indexes - await prisma.$executeRaw`DROP INDEX IF EXISTS "account_account_uuid_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "event_created_at_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "event_event_uuid_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "event_session_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "event_website_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_created_at_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_session_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_website_id_created_at_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_website_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "pageview_website_id_session_id_created_at_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "user_user_id_key";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "user_username_key";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`; await prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_uuid_idx";`; await prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_uuid_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`; success('Dropped v1 database indexes.'); } catch (e) { From 8f686db116d8cbff6b2cda383ea4fc0e3a4cd243 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 2 Jan 2023 16:58:52 -0800 Subject: [PATCH 04/25] fix rename to v1_ --- scripts/migration.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/migration.js b/scripts/migration.js index 6c27497c..b02e8897 100644 --- a/scripts/migration.js +++ b/scripts/migration.js @@ -61,13 +61,13 @@ async function dropKeys() { async function renameTables() { try { // rename tables - await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "_prisma_migrations_v1";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "account_v1";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "event_v1";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "event_data_v1";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "pageview_v1";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "session_v1";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "website_v1";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`; success('Renamed v1 database tables.'); } catch (e) { From 2a5927e345308313aa06b667eabaaab3ec394cd4 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 3 Jan 2023 09:32:32 -0800 Subject: [PATCH 05/25] update migrations --- scripts/migration.js | 46 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/scripts/migration.js b/scripts/migration.js index b02e8897..50961ea2 100644 --- a/scripts/migration.js +++ b/scripts/migration.js @@ -35,7 +35,7 @@ async function checkConnection() { async function checkTables() { try { - await prisma.$queryRaw`select * from user limit 1`; + await prisma.$queryRaw`select * from account limit 1`; success('Database tables found.'); } catch (e) { @@ -94,6 +94,39 @@ async function dropIndexes() { } } +async function createPrismaTable() { + try { + // drop / recreate _prisma_migrations table + await prisma.$executeRaw`DROP TABLE IF EXISTS "_prisma_migrations";`; + await prisma.$executeRaw`CREATE TABLE "_prisma_migrations" + ( + id varchar(36) not null + constraint "_prisma_migrations_pkey" + primary key, + "checksum" varchar(64) not null, + "finished_at" timestamp with time zone, + "migration_name" varchar(255) not null, + "logs" text, + "rolled_back_at" timestamp with time zone, + "started_at" timestamp with time zone default now() not null, + "applied_steps_count" integer default 0 not null + );`; + + success('Created Prisma migrations table.'); + } catch (e) { + throw new Error('Failed to create Prisma migrations table.'); + } +} + +// async function prismaMigrate() { +// try { + +// success('Created Prisma migrations table.'); +// } catch (e) { +// throw new Error('Failed to create Prisma migrations table.'); +// } +// } + // async function checkNewTables() { // try { // await prisma.$queryRaw`select * from website_event limit 1`; @@ -106,7 +139,16 @@ async function dropIndexes() { (async () => { let err = false; - for (let fn of [checkEnv, checkConnection, checkTables, dropKeys, renameTables, dropIndexes]) { + for (let fn of [ + checkEnv, + checkConnection, + checkTables, + dropKeys, + renameTables, + dropIndexes, + createPrismaTable, + ]) { + // for (let fn of [checkEnv, checkConnection, createPrismaTable]) { try { await fn(); } catch (e) { From 0a731e34087dc7564a6907f4c7f54e3284caf427 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 3 Jan 2023 12:50:08 -0800 Subject: [PATCH 06/25] run rawsql for 01_init --- package.json | 1 + scripts/{migration.js => migrate-db.js} | 108 ++++++++++++------------ 2 files changed, 54 insertions(+), 55 deletions(-) rename scripts/{migration.js => migrate-db.js} (64%) diff --git a/package.json b/package.json index f28eb038..a63d8c72 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "update-tracker": "node scripts/update-tracker.js", "update-db": "prisma migrate deploy", "check-db": "node scripts/check-db.js", + "migrate-db": "node scripts/migrate-db.js", "copy-db-files": "node scripts/copy-db-files.js", "generate-lang": "npm-run-all extract-lang merge-lang", "extract-lang": "formatjs extract \"{pages,components}/**/*.js\" --out-file build/messages.json", diff --git a/scripts/migration.js b/scripts/migrate-db.js similarity index 64% rename from scripts/migration.js rename to scripts/migrate-db.js index 50961ea2..43bfdb4d 100644 --- a/scripts/migration.js +++ b/scripts/migrate-db.js @@ -1,9 +1,10 @@ /* eslint-disable no-console */ require('dotenv').config(); +const fs = require('fs'); +const path = require('path'); const { PrismaClient } = require('@prisma/client'); const chalk = require('chalk'); -// const spawn = require('cross-spawn'); -// const { execSync } = require('child_process'); +const { execSync } = require('child_process'); const prisma = new PrismaClient(); @@ -11,9 +12,9 @@ function success(msg) { console.log(chalk.greenBright(`✓ ${msg}`)); } -// function error(msg) { -// console.log(chalk.redBright(`✗ ${msg}`)); -// } +function error(msg) { + console.log(chalk.redBright(`✗ ${msg}`)); +} async function checkEnv() { if (!process.env.DATABASE_URL) { @@ -33,13 +34,35 @@ async function checkConnection() { } } -async function checkTables() { +async function checkV1Tables() { try { await prisma.$queryRaw`select * from account limit 1`; - success('Database tables found.'); + success('Database v1 tables found.'); + console.log('Preparing v1 tables for migration'); + + // alter v1 tables + await dropKeys(); + await renameTables(); + await dropIndexes(); } catch (e) { - throw new Error('Database tables not found.'); + error('Database v1 tables not found.'); + } +} + +async function checkV2Tables() { + try { + await prisma.$queryRaw`select * from website_event limit 1`; + + success('Database v2 tables found.'); + } catch (e) { + error('Database v2 tables not found.'); + console.log('Adding v2 tables...'); + + // run v2 prisma migration steps + await runInitMigration(); + console.log(execSync('prisma migrate resolve --applied 01_init').toString()); + console.log(execSync('prisma migrate deploy').toString()); } } @@ -87,6 +110,7 @@ async function dropIndexes() { await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`; await prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`; await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`; + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`; success('Dropped v1 database indexes.'); } catch (e) { @@ -94,61 +118,35 @@ async function dropIndexes() { } } -async function createPrismaTable() { +async function runInitMigration() { try { - // drop / recreate _prisma_migrations table - await prisma.$executeRaw`DROP TABLE IF EXISTS "_prisma_migrations";`; - await prisma.$executeRaw`CREATE TABLE "_prisma_migrations" - ( - id varchar(36) not null - constraint "_prisma_migrations_pkey" - primary key, - "checksum" varchar(64) not null, - "finished_at" timestamp with time zone, - "migration_name" varchar(255) not null, - "logs" text, - "rolled_back_at" timestamp with time zone, - "started_at" timestamp with time zone default now() not null, - "applied_steps_count" integer default 0 not null - );`; + const rawSql = await fs.promises.readFile( + path.join(__dirname, '../prisma/migrations/01_init/migration.sql'), + ); - success('Created Prisma migrations table.'); + const sqlStatements = rawSql + .toString() + .split('\n') + .filter(line => !line.startsWith('--')) // remove comments-only lines + .join('\n') + .replace(/\r\n|\n|\r/g, ' ') // remove newlines + .replace(/\s+/g, ' ') // excess white space + .split(';'); + + for (const sql of sqlStatements) { + await prisma.$executeRawUnsafe(sql); + } + + success('Ran 01_init migration.'); } catch (e) { - throw new Error('Failed to create Prisma migrations table.'); + console.error(e); + throw new Error('Failed to run 01_init migration.'); } } -// async function prismaMigrate() { -// try { - -// success('Created Prisma migrations table.'); -// } catch (e) { -// throw new Error('Failed to create Prisma migrations table.'); -// } -// } - -// async function checkNewTables() { -// try { -// await prisma.$queryRaw`select * from website_event limit 1`; - -// success('Database v2 tables found.'); -// } catch (e) { -// throw new Error('Database v2 tables not found.'); -// } -// } - (async () => { let err = false; - for (let fn of [ - checkEnv, - checkConnection, - checkTables, - dropKeys, - renameTables, - dropIndexes, - createPrismaTable, - ]) { - // for (let fn of [checkEnv, checkConnection, createPrismaTable]) { + for (let fn of [checkEnv, checkConnection, checkV1Tables, checkV2Tables]) { try { await fn(); } catch (e) { From c24f8cb985d90669fb1f5e407579b37a8d89bc81 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 3 Jan 2023 13:16:29 -0800 Subject: [PATCH 07/25] add data migration script --- db/postgresql/migration_v2.sql | 80 ++++++++++++++++++++++++++++++++++ scripts/migrate-db.js | 14 +++--- 2 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 db/postgresql/migration_v2.sql diff --git a/db/postgresql/migration_v2.sql b/db/postgresql/migration_v2.sql new file mode 100644 index 00000000..92240bb8 --- /dev/null +++ b/db/postgresql/migration_v2.sql @@ -0,0 +1,80 @@ +-- account +DELETE FROM "user" +WHERE username = 'admin'; + +INSERT INTO "user" +(user_id, username, password, role, created_at, updated_at, deleted_at) +SELECT account_uuid, + username, + password, + CASE WHEN is_admin = true THEN 'admin' ELSE 'user' END, + created_at, + updated_at, + NULL +FROM v1_account; + +-- website +INSERT INTO website +(website_id, name, domain, share_id, rev_id, user_id, team_id, created_at) +SELECT website_uuid, + name, + domain, + share_id, + 0 rev_id, + a.account_uuid, + NULL team_id, + a.created_at +FROM v1_website w +JOIN v1_account a +ON a.user_id = w.user_id; + +-- session +INSERT INTO session +(session_id, website_id, hostname, browser, os, device, screen, language, country) +SELECT session_uuid, + w.website_uuid, + hostname, + browser, + os, + device, + screen, + language, + country +FROM v1_session s +JOIN v1_website w +ON w.website_id = s.website_id; + +-- pageview +INSERT INTO website_event +(event_id, website_id, session_id, created_at, url, referrer, event_type) +SELECT gen_random_uuid() event_id, + w.website_uuid, + s.session_uuid, + p.created_at, + p.url, + p.referrer, + 1 event_type +FROM v1_pageview p +JOIN v1_session s +ON s.session_id = s.session_id +JOIN v1_website w +ON w.website_id = s.website_id; + +-- event / event_data +INSERT INTO website_event +(event_id, website_id, session_id, created_at, url, event_type, event_name, event_data) +SELECT e.event_uuid, + w.website_uuid, + s.session_uuid, + e.created_at, + e.url, + 1 event_type, + e.event_name, + ed.event_data +FROM v1_event e +JOIN v1_session s +ON s.session_id = s.session_id +JOIN v1_website w +ON w.website_id = s.website_id +LEFT JOIN v1_event_data ed +ON ed.event_id = e.event_id; \ No newline at end of file diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 43bfdb4d..5fd06cb4 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -60,9 +60,10 @@ async function checkV2Tables() { console.log('Adding v2 tables...'); // run v2 prisma migration steps - await runInitMigration(); + await runSqlFile('../prisma/migrations/01_init/migration.sql'); console.log(execSync('prisma migrate resolve --applied 01_init').toString()); console.log(execSync('prisma migrate deploy').toString()); + await runSqlFile('../db/postgresql/migration_v2.sql'); } } @@ -118,11 +119,9 @@ async function dropIndexes() { } } -async function runInitMigration() { +async function runSqlFile(filePath) { try { - const rawSql = await fs.promises.readFile( - path.join(__dirname, '../prisma/migrations/01_init/migration.sql'), - ); + const rawSql = await fs.promises.readFile(path.join(__dirname, filePath)); const sqlStatements = rawSql .toString() @@ -136,11 +135,12 @@ async function runInitMigration() { for (const sql of sqlStatements) { await prisma.$executeRawUnsafe(sql); } + filePath; - success('Ran 01_init migration.'); + success(`Ran sql file ${filePath}.`); } catch (e) { console.error(e); - throw new Error('Failed to run 01_init migration.'); + throw new Error(`Failed to run sql file ${filePath}.`); } } From 3cf061736662a27dc33af5de2aaf89b1f464a3b1 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 4 Jan 2023 00:26:31 -0800 Subject: [PATCH 08/25] add warning message during data transfer --- db/postgresql/migration_v2.sql | 6 +++--- scripts/migrate-db.js | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/db/postgresql/migration_v2.sql b/db/postgresql/migration_v2.sql index 92240bb8..ab95836d 100644 --- a/db/postgresql/migration_v2.sql +++ b/db/postgresql/migration_v2.sql @@ -56,7 +56,7 @@ SELECT gen_random_uuid() event_id, 1 event_type FROM v1_pageview p JOIN v1_session s -ON s.session_id = s.session_id +ON s.session_id = p.session_id JOIN v1_website w ON w.website_id = s.website_id; @@ -68,12 +68,12 @@ SELECT e.event_uuid, s.session_uuid, e.created_at, e.url, - 1 event_type, + 2 event_type, e.event_name, ed.event_data FROM v1_event e JOIN v1_session s -ON s.session_id = s.session_id +ON s.session_id = e.session_id JOIN v1_website w ON w.website_id = s.website_id LEFT JOIN v1_event_data ed diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 5fd06cb4..db89ecc1 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -63,6 +63,9 @@ async function checkV2Tables() { await runSqlFile('../prisma/migrations/01_init/migration.sql'); console.log(execSync('prisma migrate resolve --applied 01_init').toString()); console.log(execSync('prisma migrate deploy').toString()); + console.log( + 'Starting v2 data migration. Please do no cancel this process, it may take a while.', + ); await runSqlFile('../db/postgresql/migration_v2.sql'); } } From 1cd195d89553745bd713d310ee41f1574bb12e81 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 4 Jan 2023 10:07:58 -0800 Subject: [PATCH 09/25] add delete v1 table prompt --- scripts/migrate-db.js | 70 +++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index db89ecc1..d06dfabf 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -5,6 +5,7 @@ const path = require('path'); const { PrismaClient } = require('@prisma/client'); const chalk = require('chalk'); const { execSync } = require('child_process'); +const prompts = require('prompts'); const prisma = new PrismaClient(); @@ -42,9 +43,9 @@ async function checkV1Tables() { console.log('Preparing v1 tables for migration'); // alter v1 tables - await dropKeys(); - await renameTables(); - await dropIndexes(); + await dropV1Keys(); + await renameV1Tables(); + await dropV1Indexes(); } catch (e) { error('Database v1 tables not found.'); } @@ -70,14 +71,14 @@ async function checkV2Tables() { } } -async function dropKeys() { +async function dropV1Keys() { try { // drop keys - await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`; success('Dropped v1 database keys.'); } catch (e) { @@ -85,16 +86,16 @@ async function dropKeys() { } } -async function renameTables() { +async function renameV1Tables() { try { // rename tables - await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "account" RENAME TO "v1_account";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "event" RENAME TO "v1_event";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "session" RENAME TO "v1_session";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "website" RENAME TO "v1_website";`; success('Renamed v1 database tables.'); } catch (e) { @@ -102,7 +103,7 @@ async function renameTables() { } } -async function dropIndexes() { +async function dropV1Indexes() { try { // drop indexes await prisma.$executeRaw`DROP INDEX IF EXISTS "user_user_id_key";`; @@ -122,6 +123,36 @@ async function dropIndexes() { } } +async function deleteV1TablesPrompt() { + const response = await prompts({ + type: 'text', + name: 'value', + message: 'Do you want to delete V1 database tables? (Y/N)', + validate: value => (value !== 'Y' && value !== 'N' ? `Please enter Y or N.` : true), + }); + + if (response.value === 'Y') { + await deleteV1Tables(); + } +} + +async function deleteV1Tables() { + try { + // drop tables + await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_prisma_migrations";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_account";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event_data";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_pageview";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_session";`; + await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_website";`; + + success('Dropped v1 database tables.'); + } catch (e) { + throw new Error('Failed to drop v1 database tables.'); + } +} + async function runSqlFile(filePath) { try { const rawSql = await fs.promises.readFile(path.join(__dirname, filePath)); @@ -149,9 +180,10 @@ async function runSqlFile(filePath) { (async () => { let err = false; - for (let fn of [checkEnv, checkConnection, checkV1Tables, checkV2Tables]) { + for (let fn of [checkEnv, checkConnection, checkV1Tables, checkV2Tables, deleteV1TablesPrompt]) { try { await fn(); + success('Migration successfully completed.'); } catch (e) { console.log(chalk.red(`✗ ${e.message}`)); err = true; From b845ae547d5c93c07bb5746606299afb48345e69 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 4 Jan 2023 11:03:28 -0800 Subject: [PATCH 10/25] fix v1 replace bug --- scripts/migrate-db.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index d06dfabf..e3fff8f6 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -74,11 +74,11 @@ async function checkV2Tables() { async function dropV1Keys() { try { // drop keys - await prisma.$executeRaw`DROP TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`; success('Dropped v1 database keys.'); } catch (e) { @@ -89,13 +89,13 @@ async function dropV1Keys() { async function renameV1Tables() { try { // rename tables - await prisma.$executeRaw`DROP TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "account" RENAME TO "v1_account";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "event" RENAME TO "v1_event";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "session" RENAME TO "v1_session";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "website" RENAME TO "v1_website";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`; + await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`; success('Renamed v1 database tables.'); } catch (e) { @@ -173,7 +173,7 @@ async function runSqlFile(filePath) { success(`Ran sql file ${filePath}.`); } catch (e) { - console.error(e); + console.log(e); throw new Error(`Failed to run sql file ${filePath}.`); } } @@ -183,7 +183,6 @@ async function runSqlFile(filePath) { for (let fn of [checkEnv, checkConnection, checkV1Tables, checkV2Tables, deleteV1TablesPrompt]) { try { await fn(); - success('Migration successfully completed.'); } catch (e) { console.log(chalk.red(`✗ ${e.message}`)); err = true; From 5f159ed5ce4fdd9c9bf26b8269509c1817fda6f0 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 4 Jan 2023 11:15:19 -0800 Subject: [PATCH 11/25] add final success prompt --- scripts/migrate-db.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index e3fff8f6..fdbb948d 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -134,6 +134,8 @@ async function deleteV1TablesPrompt() { if (response.value === 'Y') { await deleteV1Tables(); } + + success('Migration successfully completed.'); } async function deleteV1Tables() { From f10694d07eeeb3609c214270d772245168e8d835 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 5 Jan 2023 11:13:49 -0800 Subject: [PATCH 12/25] create new mysql schema file --- db/mysql/schema.prisma | 155 ++++++++++++++++++++----------------- db/mysql/schema_old.prisma | 116 +++++++++++++++++++++++++++ 2 files changed, 200 insertions(+), 71 deletions(-) create mode 100644 db/mysql/schema_old.prisma diff --git a/db/mysql/schema.prisma b/db/mysql/schema.prisma index bdfafd43..7e4e20d1 100644 --- a/db/mysql/schema.prisma +++ b/db/mysql/schema.prisma @@ -3,101 +3,114 @@ generator client { } datasource db { - provider = "mysql" + provider = "postgresql" url = env("DATABASE_URL") + relationMode = "prisma" } -model account { - id Int @id @default(autoincrement()) @map("user_id") @db.UnsignedInt - username String @unique() @db.VarChar(255) - password String @db.VarChar(60) - isAdmin Boolean @default(false) @map("is_admin") - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) - updatedAt DateTime? @default(now()) @map("updated_at") @db.Timestamp(0) - accountUuid String @unique() @map("account_uuid") @db.VarChar(36) - website website[] +model User { + id String @id @unique @map("user_id") @db.Uuid + username String @unique @db.VarChar(255) + password String @db.VarChar(60) + role String @map("role") @db.VarChar(50) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) - @@index([accountUuid]) + teamUser TeamUser[] + Website Website[] + + @@map("user") } -model event { - id Int @id @default(autoincrement()) @map("event_id") @db.UnsignedInt - websiteId Int @map("website_id") @db.UnsignedInt - sessionId Int @map("session_id") @db.UnsignedInt - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) - url String @db.VarChar(500) - eventName String @map("event_name") @db.VarChar(50) - eventUuid String @unique() @map("event_uuid") @db.VarChar(36) - session session @relation(fields: [sessionId], references: [id]) - website website @relation(fields: [websiteId], references: [id]) - eventData eventData? +model Session { + id String @id @unique @map("session_id") @db.Uuid + websiteId String @map("website_id") @db.Uuid + hostname String? @db.VarChar(100) + browser String? @db.VarChar(20) + os String? @db.VarChar(20) + device String? @db.VarChar(20) + screen String? @db.VarChar(11) + language String? @db.VarChar(35) + country String? @db.Char(2) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) @@index([createdAt]) - @@index([sessionId]) @@index([websiteId]) - @@index([eventUuid]) + @@map("session") } -model eventData { - id Int @id @default(autoincrement()) @map("event_data_id") @db.UnsignedInt - eventId Int @unique @map("event_id") @db.UnsignedInt - eventData Json @map("event_data") - event event @relation(fields: [eventId], references: [id]) +model Website { + id String @id @unique @map("website_id") @db.Uuid + name String @db.VarChar(100) + domain String? @db.VarChar(500) + shareId String? @unique @map("share_id") @db.VarChar(50) + revId Int @default(0) @map("rev_id") @db.Integer + userId String? @map("user_id") @db.Uuid + teamId String? @map("team_id") @db.Uuid + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) - @@map("event_data") + team Team? @relation(fields: [teamId], references: [id]) + user User? @relation(fields: [userId], references: [id]) + + @@index([teamId]) + @@index([userId]) + @@index([createdAt]) + @@index([shareId]) + @@map("website") } -model pageview { - id Int @id @default(autoincrement()) @map("view_id") @db.UnsignedInt - websiteId Int @map("website_id") @db.UnsignedInt - sessionId Int @map("session_id") @db.UnsignedInt - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) +model WebsiteEvent { + id String @id() @map("event_id") @db.Uuid + websiteId String @map("website_id") @db.Uuid + sessionId String @map("session_id") @db.Uuid + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) url String @db.VarChar(500) referrer String? @db.VarChar(500) - session session @relation(fields: [sessionId], references: [id]) - website website @relation(fields: [websiteId], references: [id]) + eventType Int @default(1) @map("event_type") @db.Integer + eventName String? @map("event_name") @db.VarChar(50) + eventData Json? @map("event_data") @@index([createdAt]) @@index([sessionId]) + @@index([websiteId]) @@index([websiteId, createdAt]) - @@index([websiteId]) @@index([websiteId, sessionId, createdAt]) + @@map("website_event") } -model session { - id Int @id @default(autoincrement()) @map("session_id") @db.UnsignedInt - sessionUuid String @unique() @map("session_uuid") @db.VarChar(36) - websiteId Int @map("website_id") @db.UnsignedInt - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) - hostname String? @db.VarChar(100) - browser String? @db.VarChar(20) - os String? @db.VarChar(20) - device String? @db.VarChar(20) - screen String? @db.VarChar(11) - language String? @db.VarChar(35) - country String? @db.Char(2) - website website @relation(fields: [websiteId], references: [id]) - event event[] - pageview pageview[] +model Team { + id String @id() @unique() @map("team_id") @db.Uuid + name String @db.VarChar(50) + userId String @map("user_id") @db.Uuid + accessCode String? @unique @map("access_code") @db.VarChar(50) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) - @@index([createdAt]) - @@index([websiteId]) - @@index([sessionUuid]) -} - -model website { - id Int @id @default(autoincrement()) @map("website_id") @db.UnsignedInt - websiteUuid String @unique() @map("website_uuid") @db.VarChar(36) - userId Int @map("user_id") @db.UnsignedInt - name String @db.VarChar(100) - domain String? @db.VarChar(500) - shareId String? @unique() @map("share_id") @db.VarChar(64) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) - account account @relation(fields: [userId], references: [id]) - event event[] - pageview pageview[] - session session[] + teamUsers TeamUser[] + Website Website[] @@index([userId]) - @@index([websiteUuid]) + @@index([accessCode]) + @@map("team") +} + +model TeamUser { + id String @id() @unique() @map("team_user_id") @db.Uuid + teamId String @map("team_id") @db.Uuid + userId String @map("user_id") @db.Uuid + role String @map("role") @db.VarChar(50) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) + + team Team @relation(fields: [teamId], references: [id]) + user User @relation(fields: [userId], references: [id]) + + @@index([teamId]) + @@index([userId]) + @@map("team_user") } diff --git a/db/mysql/schema_old.prisma b/db/mysql/schema_old.prisma new file mode 100644 index 00000000..57f09e30 --- /dev/null +++ b/db/mysql/schema_old.prisma @@ -0,0 +1,116 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "mysql" + url = env("DATABASE_URL") + relationMode = "prisma" +} + +model User { + id String @id @unique @map("user_id") @db.VarChar(36) + username String @unique @db.VarChar(255) + password String @db.VarChar(60) + role String @map("role") @db.VarChar(50) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) + + teamUser TeamUser[] + Website Website[] + + @@map("user") +} + +model Session { + id String @id @unique @map("session_id") @db.VarChar(36) + websiteId String @map("website_id") @db.VarChar(36) + hostname String? @db.VarChar(100) + browser String? @db.VarChar(20) + os String? @db.VarChar(20) + device String? @db.VarChar(20) + screen String? @db.VarChar(11) + language String? @db.VarChar(35) + country String? @db.Char(2) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) + + @@index([createdAt]) + @@index([websiteId]) + @@map("session") +} + +model Website { + id String @id @unique @map("website_id") @db.VarChar(36) + name String @db.VarChar(100) + domain String? @db.VarChar(500) + shareId String? @unique @map("share_id") @db.VarChar(50) + revId Int @default(0) @map("rev_id") @db.UnsignedInt + userId String? @map("user_id") @db.VarChar(36) + teamId String? @map("team_id") @db.VarChar(36) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) + + team Team? @relation(fields: [teamId], references: [id]) + user User? @relation(fields: [userId], references: [id]) + + @@index([teamId]) + @@index([userId]) + @@index([createdAt]) + @@index([shareId]) + @@map("website") +} + +model WebsiteEvent { + id String @id() @map("event_id") @db.VarChar(36) + websiteId String @map("website_id") @db.VarChar(36) + sessionId String @map("session_id") @db.VarChar(36) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) + url String @db.VarChar(500) + referrer String? @db.VarChar(500) + eventType Int @default(1) @map("event_type") @db.UnsignedInt + eventName String? @map("event_name") @db.VarChar(50) + eventData Json? @map("event_data") + + @@index([createdAt]) + @@index([sessionId]) + @@index([websiteId]) + @@index([websiteId, createdAt]) + @@index([websiteId, sessionId, createdAt]) + @@map("website_event") +} + +model Team { + id String @id() @unique() @map("team_id") @db.VarChar(36) + name String @db.VarChar(50) + userId String @map("user_id") @db.VarChar(36) + accessCode String? @unique @map("access_code") @db.VarChar(50) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) + + teamUsers TeamUser[] + Website Website[] + + @@index([userId]) + @@index([accessCode]) + @@map("team") +} + +model TeamUser { + id String @id() @unique() @map("team_user_id") @db.VarChar(36) + teamId String @map("team_id") @db.VarChar(36) + userId String @map("user_id") @db.VarChar(36) + role String @map("role") @db.VarChar(50) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) + updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) + + team Team @relation(fields: [teamId], references: [id]) + user User @relation(fields: [userId], references: [id]) + + @@index([teamId]) + @@index([userId]) + @@map("team_user") +} From 19166e580ec2854b07d4cac0ec2d121cdf70041d Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 5 Jan 2023 14:40:34 -0800 Subject: [PATCH 13/25] add mysql schema file --- db/mysql/migrations/01_init/migration.sql | 140 +++++++++--------- .../02_add_event_data/migration.sql | 90 ----------- .../03_remove_cascade_delete/migration.sql | 35 ----- db/mysql/migrations/04_add_uuid/migration.sql | 35 ----- db/mysql/schema.prisma | 62 ++++---- db/mysql/schema_old.prisma | 116 --------------- 6 files changed, 104 insertions(+), 374 deletions(-) delete mode 100644 db/mysql/migrations/02_add_event_data/migration.sql delete mode 100644 db/mysql/migrations/03_remove_cascade_delete/migration.sql delete mode 100644 db/mysql/migrations/04_add_uuid/migration.sql delete mode 100644 db/mysql/schema_old.prisma diff --git a/db/mysql/migrations/01_init/migration.sql b/db/mysql/migrations/01_init/migration.sql index 0ae7775a..e549ffec 100644 --- a/db/mysql/migrations/01_init/migration.sql +++ b/db/mysql/migrations/01_init/migration.sql @@ -1,55 +1,22 @@ -- CreateTable -CREATE TABLE `account` ( - `user_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, +CREATE TABLE `user` ( + `user_id` VARCHAR(36) NOT NULL, `username` VARCHAR(255) NOT NULL, `password` VARCHAR(60) NOT NULL, - `is_admin` BOOLEAN NOT NULL DEFAULT false, + `role` VARCHAR(50) NOT NULL, `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), - `updated_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `updated_at` TIMESTAMP(0) NULL, + `deleted_at` TIMESTAMP(0) NULL, - UNIQUE INDEX `username`(`username`), + UNIQUE INDEX `user_user_id_key`(`user_id`), + UNIQUE INDEX `user_username_key`(`username`), PRIMARY KEY (`user_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- CreateTable -CREATE TABLE `event` ( - `event_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - `website_id` INTEGER UNSIGNED NOT NULL, - `session_id` INTEGER UNSIGNED NOT NULL, - `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), - `url` VARCHAR(500) NOT NULL, - `event_type` VARCHAR(50) NOT NULL, - `event_value` VARCHAR(50) NOT NULL, - - INDEX `event_created_at_idx`(`created_at`), - INDEX `event_session_id_idx`(`session_id`), - INDEX `event_website_id_idx`(`website_id`), - PRIMARY KEY (`event_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- CreateTable -CREATE TABLE `pageview` ( - `view_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - `website_id` INTEGER UNSIGNED NOT NULL, - `session_id` INTEGER UNSIGNED NOT NULL, - `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), - `url` VARCHAR(500) NOT NULL, - `referrer` VARCHAR(500) NULL, - - INDEX `pageview_created_at_idx`(`created_at`), - INDEX `pageview_session_id_idx`(`session_id`), - INDEX `pageview_website_id_created_at_idx`(`website_id`, `created_at`), - INDEX `pageview_website_id_idx`(`website_id`), - INDEX `pageview_website_id_session_id_created_at_idx`(`website_id`, `session_id`, `created_at`), - PRIMARY KEY (`view_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `session` ( - `session_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - `session_uuid` VARCHAR(36) NOT NULL, - `website_id` INTEGER UNSIGNED NOT NULL, - `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `session_id` VARCHAR(36) NOT NULL, + `website_id` VARCHAR(36) NOT NULL, `hostname` VARCHAR(100) NULL, `browser` VARCHAR(20) NULL, `os` VARCHAR(20) NULL, @@ -57,46 +24,85 @@ CREATE TABLE `session` ( `screen` VARCHAR(11) NULL, `language` VARCHAR(35) NULL, `country` CHAR(2) NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), - UNIQUE INDEX `session_uuid`(`session_uuid`), + UNIQUE INDEX `session_session_id_key`(`session_id`), INDEX `session_created_at_idx`(`created_at`), INDEX `session_website_id_idx`(`website_id`), PRIMARY KEY (`session_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `website` ( - `website_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - `website_uuid` VARCHAR(36) NOT NULL, - `user_id` INTEGER UNSIGNED NOT NULL, + `website_id` VARCHAR(36) NOT NULL, `name` VARCHAR(100) NOT NULL, `domain` VARCHAR(500) NULL, - `share_id` VARCHAR(64) NULL, + `share_id` VARCHAR(50) NULL, + `rev_id` INTEGER UNSIGNED NOT NULL DEFAULT 0, + `user_id` VARCHAR(36) NULL, + `team_id` VARCHAR(36) NULL, `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `updated_at` TIMESTAMP(0) NULL, + `deleted_at` TIMESTAMP(0) NULL, - UNIQUE INDEX `website_uuid`(`website_uuid`), - UNIQUE INDEX `share_id`(`share_id`), + UNIQUE INDEX `website_website_id_key`(`website_id`), + UNIQUE INDEX `website_share_id_key`(`share_id`), + INDEX `website_team_id_idx`(`team_id`), INDEX `website_user_id_idx`(`user_id`), + INDEX `website_created_at_idx`(`created_at`), + INDEX `website_share_id_idx`(`share_id`), PRIMARY KEY (`website_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; --- AddForeignKey -ALTER TABLE `event` ADD CONSTRAINT `event_ibfk_2` FOREIGN KEY (`session_id`) REFERENCES `session`(`session_id`) ON DELETE CASCADE ON UPDATE NO ACTION; +-- CreateTable +CREATE TABLE `website_event` ( + `event_id` VARCHAR(36) NOT NULL, + `website_id` VARCHAR(36) NOT NULL, + `session_id` VARCHAR(36) NOT NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `url` VARCHAR(500) NOT NULL, + `referrer` VARCHAR(500) NULL, + `event_type` INTEGER UNSIGNED NOT NULL DEFAULT 1, + `event_name` VARCHAR(50) NULL, + `event_data` JSON NULL, --- AddForeignKey -ALTER TABLE `event` ADD CONSTRAINT `event_ibfk_1` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE CASCADE ON UPDATE NO ACTION; + INDEX `website_event_created_at_idx`(`created_at`), + INDEX `website_event_session_id_idx`(`session_id`), + INDEX `website_event_website_id_idx`(`website_id`), + INDEX `website_event_website_id_created_at_idx`(`website_id`, `created_at`), + INDEX `website_event_website_id_session_id_created_at_idx`(`website_id`, `session_id`, `created_at`), + PRIMARY KEY (`event_id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; --- AddForeignKey -ALTER TABLE `pageview` ADD CONSTRAINT `pageview_ibfk_2` FOREIGN KEY (`session_id`) REFERENCES `session`(`session_id`) ON DELETE CASCADE ON UPDATE NO ACTION; +-- CreateTable +CREATE TABLE `team` ( + `team_id` VARCHAR(36) NOT NULL, + `name` VARCHAR(50) NOT NULL, + `user_id` VARCHAR(36) NOT NULL, + `access_code` VARCHAR(50) NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `updated_at` TIMESTAMP(0) NULL, + `deleted_at` TIMESTAMP(0) NULL, --- AddForeignKey -ALTER TABLE `pageview` ADD CONSTRAINT `pageview_ibfk_1` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE CASCADE ON UPDATE NO ACTION; + UNIQUE INDEX `team_team_id_key`(`team_id`), + UNIQUE INDEX `team_access_code_key`(`access_code`), + INDEX `team_user_id_idx`(`user_id`), + INDEX `team_access_code_idx`(`access_code`), + PRIMARY KEY (`team_id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; --- AddForeignKey -ALTER TABLE `session` ADD CONSTRAINT `session_ibfk_1` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE CASCADE ON UPDATE NO ACTION; +-- CreateTable +CREATE TABLE `team_user` ( + `team_user_id` VARCHAR(36) NOT NULL, + `team_id` VARCHAR(36) NOT NULL, + `user_id` VARCHAR(36) NOT NULL, + `role` VARCHAR(50) NOT NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `updated_at` TIMESTAMP(0) NULL, + `deleted_at` TIMESTAMP(0) NULL, --- AddForeignKey -ALTER TABLE `website` ADD CONSTRAINT `website_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `account`(`user_id`) ON DELETE CASCADE ON UPDATE NO ACTION; - --- CreateAdminUser -INSERT INTO account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true); + UNIQUE INDEX `team_user_team_user_id_key`(`team_user_id`), + INDEX `team_user_team_id_idx`(`team_id`), + INDEX `team_user_user_id_idx`(`user_id`), + PRIMARY KEY (`team_user_id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/db/mysql/migrations/02_add_event_data/migration.sql b/db/mysql/migrations/02_add_event_data/migration.sql deleted file mode 100644 index b781984c..00000000 --- a/db/mysql/migrations/02_add_event_data/migration.sql +++ /dev/null @@ -1,90 +0,0 @@ --- DropForeignKey -ALTER TABLE `event` DROP FOREIGN KEY `event_ibfk_1`; -ALTER TABLE `event` DROP FOREIGN KEY `event_ibfk_2`; - -DROP INDEX `event_created_at_idx` ON `event`; -DROP INDEX `event_session_id_idx` ON `event`; -DROP INDEX `event_website_id_idx` ON `event`; - -CREATE INDEX `event_old_created_at_idx` ON `event` (created_at); -CREATE INDEX `event_old_session_id_idx` ON `event` (session_id); -CREATE INDEX `event_old_website_id_idx` ON `event` (website_id); - --- RenameTable -RENAME TABLE `event` TO `_event_old`; - --- CreateTable -CREATE TABLE `event` -( - `event_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, - `website_id` INTEGER UNSIGNED NOT NULL, - `session_id` INTEGER UNSIGNED NOT NULL, - `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), - `url` VARCHAR(500) NOT NULL, - `event_name` VARCHAR(50) NOT NULL, - - INDEX `event_created_at_idx`(`created_at`), - INDEX `event_session_id_idx`(`session_id`), - INDEX `event_website_id_idx`(`website_id`), - PRIMARY KEY (`event_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- AddForeignKey -ALTER TABLE `event` ADD CONSTRAINT `event_ibfk_2` FOREIGN KEY (`session_id`) REFERENCES `session`(`session_id`) ON DELETE CASCADE ON UPDATE NO ACTION; - --- AddForeignKey -ALTER TABLE `event` ADD CONSTRAINT `event_ibfk_1` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE CASCADE ON UPDATE NO ACTION; - - --- CreateTable -CREATE TABLE `event_data` ( - `event_data_id` INTEGER NOT NULL AUTO_INCREMENT, - `event_id` INTEGER UNSIGNED NOT NULL, - `event_data` JSON NOT NULL, - - UNIQUE INDEX `event_data_event_id_key`(`event_id`), - PRIMARY KEY (`event_data_id`) -) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- AddForeignKey -ALTER TABLE `event_data` ADD CONSTRAINT `event_data_event_id_fkey` FOREIGN KEY (`event_id`) REFERENCES `event`(`event_id`) ON DELETE RESTRICT ON UPDATE CASCADE; - --- CreateProcedureRenameIndex -CREATE PROCEDURE `UmamiRenameIndexIfExists`( - IN i_table_name VARCHAR(128), - IN i_current_index_name VARCHAR(128), - IN i_new_index_name VARCHAR(128) - ) - BEGIN - - SET @tableName = i_table_name; - SET @currentIndexName = i_current_index_name; - SET @newIndexName = i_new_index_name; - SET @indexExists = 0; - - SELECT - 1 - INTO @indexExists FROM - INFORMATION_SCHEMA.STATISTICS - WHERE - TABLE_NAME = @tableName - AND INDEX_NAME = @currentIndexName; - - SET @query = CONCAT( - 'ALTER TABLE `', @tableName, '` RENAME INDEX `', @currentIndexName, '` TO `', @newIndexName, '`;' - ); - IF @indexExists THEN - PREPARE stmt FROM @query; - EXECUTE stmt; - DEALLOCATE PREPARE stmt; - END IF; -END; - --- RenameIndex -CALL UmamiRenameIndexIfExists('account', 'username', 'account_username_key'); -CALL UmamiRenameIndexIfExists('session', 'session_uuid', 'session_session_uuid_key'); -CALL UmamiRenameIndexIfExists('website', 'share_id', 'website_share_id_key'); -CALL UmamiRenameIndexIfExists('website', 'website_uuid', 'website_website_uuid_key'); - --- Drop CreateProcedureRenameIndex -drop procedure `UmamiRenameIndexIfExists`; \ No newline at end of file diff --git a/db/mysql/migrations/03_remove_cascade_delete/migration.sql b/db/mysql/migrations/03_remove_cascade_delete/migration.sql deleted file mode 100644 index 542784a9..00000000 --- a/db/mysql/migrations/03_remove_cascade_delete/migration.sql +++ /dev/null @@ -1,35 +0,0 @@ --- DropForeignKey -ALTER TABLE `event` DROP FOREIGN KEY `event_ibfk_2`; - --- DropForeignKey -ALTER TABLE `event` DROP FOREIGN KEY `event_ibfk_1`; - --- DropForeignKey -ALTER TABLE `pageview` DROP FOREIGN KEY `pageview_ibfk_2`; - --- DropForeignKey -ALTER TABLE `pageview` DROP FOREIGN KEY `pageview_ibfk_1`; - --- DropForeignKey -ALTER TABLE `session` DROP FOREIGN KEY `session_ibfk_1`; - --- DropForeignKey -ALTER TABLE `website` DROP FOREIGN KEY `website_ibfk_1`; - --- AddForeignKey -ALTER TABLE `event` ADD CONSTRAINT `event_session_id_fkey` FOREIGN KEY (`session_id`) REFERENCES `session`(`session_id`) ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE `event` ADD CONSTRAINT `event_website_id_fkey` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE `pageview` ADD CONSTRAINT `pageview_session_id_fkey` FOREIGN KEY (`session_id`) REFERENCES `session`(`session_id`) ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE `pageview` ADD CONSTRAINT `pageview_website_id_fkey` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE `session` ADD CONSTRAINT `session_website_id_fkey` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE `website` ADD CONSTRAINT `website_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `account`(`user_id`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/db/mysql/migrations/04_add_uuid/migration.sql b/db/mysql/migrations/04_add_uuid/migration.sql deleted file mode 100644 index 137ee2e3..00000000 --- a/db/mysql/migrations/04_add_uuid/migration.sql +++ /dev/null @@ -1,35 +0,0 @@ --- AlterTable -ALTER TABLE `account` ADD COLUMN `account_uuid` VARCHAR(36); - --- Backfill UUID -UPDATE `account` SET account_uuid=(SELECT uuid()); - --- AlterTable -ALTER TABLE `account` MODIFY `account_uuid` VARCHAR(36) NOT NULL; - --- CreateIndex -CREATE UNIQUE INDEX `account_account_uuid_key` ON `account`(`account_uuid`); - --- AlterTable -ALTER TABLE `event` ADD COLUMN `event_uuid` VARCHAR(36); - --- Backfill UUID -UPDATE `event` SET event_uuid=(SELECT uuid()); - --- AlterTable -ALTER TABLE `event` MODIFY `event_uuid` VARCHAR(36) NOT NULL; - --- CreateIndex -CREATE UNIQUE INDEX `event_event_uuid_key` ON `event`(`event_uuid`); - --- CreateIndex -CREATE INDEX `account_account_uuid_idx` ON `account`(`account_uuid`); - --- CreateIndex -CREATE INDEX `session_session_uuid_idx` ON `session`(`session_uuid`); - --- CreateIndex -CREATE INDEX `website_website_uuid_idx` ON `website`(`website_uuid`); - --- CreateIndex -CREATE INDEX `event_event_uuid_idx` ON `event`(`event_uuid`); \ No newline at end of file diff --git a/db/mysql/schema.prisma b/db/mysql/schema.prisma index 7e4e20d1..ba035ab5 100644 --- a/db/mysql/schema.prisma +++ b/db/mysql/schema.prisma @@ -3,19 +3,19 @@ generator client { } datasource db { - provider = "postgresql" + provider = "mysql" url = env("DATABASE_URL") relationMode = "prisma" } model User { - id String @id @unique @map("user_id") @db.Uuid + id String @id @unique @map("user_id") @db.VarChar(36) username String @unique @db.VarChar(255) password String @db.VarChar(60) role String @map("role") @db.VarChar(50) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) + updatedAt DateTime? @map("updated_at") @db.Timestamp(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) teamUser TeamUser[] Website Website[] @@ -24,8 +24,8 @@ model User { } model Session { - id String @id @unique @map("session_id") @db.Uuid - websiteId String @map("website_id") @db.Uuid + id String @id @unique @map("session_id") @db.VarChar(36) + websiteId String @map("website_id") @db.VarChar(36) hostname String? @db.VarChar(100) browser String? @db.VarChar(20) os String? @db.VarChar(20) @@ -33,7 +33,7 @@ model Session { screen String? @db.VarChar(11) language String? @db.VarChar(35) country String? @db.Char(2) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) @@index([createdAt]) @@index([websiteId]) @@ -41,16 +41,16 @@ model Session { } model Website { - id String @id @unique @map("website_id") @db.Uuid + id String @id @unique @map("website_id") @db.VarChar(36) name String @db.VarChar(100) domain String? @db.VarChar(500) shareId String? @unique @map("share_id") @db.VarChar(50) - revId Int @default(0) @map("rev_id") @db.Integer - userId String? @map("user_id") @db.Uuid - teamId String? @map("team_id") @db.Uuid - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) + revId Int @default(0) @map("rev_id") @db.UnsignedInt + userId String? @map("user_id") @db.VarChar(36) + teamId String? @map("team_id") @db.VarChar(36) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) + updatedAt DateTime? @map("updated_at") @db.Timestamp(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) team Team? @relation(fields: [teamId], references: [id]) user User? @relation(fields: [userId], references: [id]) @@ -63,13 +63,13 @@ model Website { } model WebsiteEvent { - id String @id() @map("event_id") @db.Uuid - websiteId String @map("website_id") @db.Uuid - sessionId String @map("session_id") @db.Uuid - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) + id String @id() @map("event_id") @db.VarChar(36) + websiteId String @map("website_id") @db.VarChar(36) + sessionId String @map("session_id") @db.VarChar(36) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) url String @db.VarChar(500) referrer String? @db.VarChar(500) - eventType Int @default(1) @map("event_type") @db.Integer + eventType Int @default(1) @map("event_type") @db.UnsignedInt eventName String? @map("event_name") @db.VarChar(50) eventData Json? @map("event_data") @@ -82,13 +82,13 @@ model WebsiteEvent { } model Team { - id String @id() @unique() @map("team_id") @db.Uuid + id String @id() @unique() @map("team_id") @db.VarChar(36) name String @db.VarChar(50) - userId String @map("user_id") @db.Uuid + userId String @map("user_id") @db.VarChar(36) accessCode String? @unique @map("access_code") @db.VarChar(50) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) + updatedAt DateTime? @map("updated_at") @db.Timestamp(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) teamUsers TeamUser[] Website Website[] @@ -99,13 +99,13 @@ model Team { } model TeamUser { - id String @id() @unique() @map("team_user_id") @db.Uuid - teamId String @map("team_id") @db.Uuid - userId String @map("user_id") @db.Uuid + id String @id() @unique() @map("team_user_id") @db.VarChar(36) + teamId String @map("team_id") @db.VarChar(36) + userId String @map("user_id") @db.VarChar(36) role String @map("role") @db.VarChar(50) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(6) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) + updatedAt DateTime? @map("updated_at") @db.Timestamp(0) + deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) team Team @relation(fields: [teamId], references: [id]) user User @relation(fields: [userId], references: [id]) diff --git a/db/mysql/schema_old.prisma b/db/mysql/schema_old.prisma deleted file mode 100644 index 57f09e30..00000000 --- a/db/mysql/schema_old.prisma +++ /dev/null @@ -1,116 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "mysql" - url = env("DATABASE_URL") - relationMode = "prisma" -} - -model User { - id String @id @unique @map("user_id") @db.VarChar(36) - username String @unique @db.VarChar(255) - password String @db.VarChar(60) - role String @map("role") @db.VarChar(50) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) - - teamUser TeamUser[] - Website Website[] - - @@map("user") -} - -model Session { - id String @id @unique @map("session_id") @db.VarChar(36) - websiteId String @map("website_id") @db.VarChar(36) - hostname String? @db.VarChar(100) - browser String? @db.VarChar(20) - os String? @db.VarChar(20) - device String? @db.VarChar(20) - screen String? @db.VarChar(11) - language String? @db.VarChar(35) - country String? @db.Char(2) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) - - @@index([createdAt]) - @@index([websiteId]) - @@map("session") -} - -model Website { - id String @id @unique @map("website_id") @db.VarChar(36) - name String @db.VarChar(100) - domain String? @db.VarChar(500) - shareId String? @unique @map("share_id") @db.VarChar(50) - revId Int @default(0) @map("rev_id") @db.UnsignedInt - userId String? @map("user_id") @db.VarChar(36) - teamId String? @map("team_id") @db.VarChar(36) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) - - team Team? @relation(fields: [teamId], references: [id]) - user User? @relation(fields: [userId], references: [id]) - - @@index([teamId]) - @@index([userId]) - @@index([createdAt]) - @@index([shareId]) - @@map("website") -} - -model WebsiteEvent { - id String @id() @map("event_id") @db.VarChar(36) - websiteId String @map("website_id") @db.VarChar(36) - sessionId String @map("session_id") @db.VarChar(36) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) - url String @db.VarChar(500) - referrer String? @db.VarChar(500) - eventType Int @default(1) @map("event_type") @db.UnsignedInt - eventName String? @map("event_name") @db.VarChar(50) - eventData Json? @map("event_data") - - @@index([createdAt]) - @@index([sessionId]) - @@index([websiteId]) - @@index([websiteId, createdAt]) - @@index([websiteId, sessionId, createdAt]) - @@map("website_event") -} - -model Team { - id String @id() @unique() @map("team_id") @db.VarChar(36) - name String @db.VarChar(50) - userId String @map("user_id") @db.VarChar(36) - accessCode String? @unique @map("access_code") @db.VarChar(50) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) - - teamUsers TeamUser[] - Website Website[] - - @@index([userId]) - @@index([accessCode]) - @@map("team") -} - -model TeamUser { - id String @id() @unique() @map("team_user_id") @db.VarChar(36) - teamId String @map("team_id") @db.VarChar(36) - userId String @map("user_id") @db.VarChar(36) - role String @map("role") @db.VarChar(50) - createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(0) - updatedAt DateTime? @map("updated_at") @db.Timestamptz(0) - deletedAt DateTime? @map("deleted_at") @db.Timestamptz(0) - - team Team @relation(fields: [teamId], references: [id]) - user User @relation(fields: [userId], references: [id]) - - @@index([teamId]) - @@index([userId]) - @@map("team_user") -} From 0cb33a9c73987292fccd81393e4928b2f520259d Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 9 Jan 2023 13:14:30 -0800 Subject: [PATCH 14/25] add check migration, use prisma transaction --- scripts/migrate-db.js | 68 ++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index fdbb948d..8c2be954 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -37,7 +37,7 @@ async function checkConnection() { async function checkV1Tables() { try { - await prisma.$queryRaw`select * from account limit 1`; + await prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`; success('Database v1 tables found.'); console.log('Preparing v1 tables for migration'); @@ -74,11 +74,13 @@ async function checkV2Tables() { async function dropV1Keys() { try { // drop keys - await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`; + await prisma.$transaction([ + await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`, + ]); success('Dropped v1 database keys.'); } catch (e) { @@ -89,13 +91,15 @@ async function dropV1Keys() { async function renameV1Tables() { try { // rename tables - await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`; - await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`; + await prisma.$transaction([ + await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`, + await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`, + ]); success('Renamed v1 database tables.'); } catch (e) { @@ -106,16 +110,18 @@ async function renameV1Tables() { async function dropV1Indexes() { try { // drop indexes - await prisma.$executeRaw`DROP INDEX IF EXISTS "user_user_id_key";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "user_username_key";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`; - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`; + await prisma.$transaction([ + await prisma.$executeRaw`DROP INDEX IF EXISTS "user_user_id_key";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "user_username_key";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`, + await prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`, + ]); success('Dropped v1 database indexes.'); } catch (e) { @@ -141,13 +147,15 @@ async function deleteV1TablesPrompt() { async function deleteV1Tables() { try { // drop tables - await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_prisma_migrations";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_account";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event_data";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_pageview";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_session";`; - await prisma.$executeRaw`DROP TABLE IF EXISTS "v1_website";`; + await prisma.$transaction([ + prisma.$executeRaw`DROP TABLE IF EXISTS "v1_prisma_migrations";`, + prisma.$executeRaw`DROP TABLE IF EXISTS "v1_account";`, + prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event";`, + prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event_data";`, + prisma.$executeRaw`DROP TABLE IF EXISTS "v1_pageview";`, + prisma.$executeRaw`DROP TABLE IF EXISTS "v1_session";`, + prisma.$executeRaw`DROP TABLE IF EXISTS "v1_website";`, + ]); success('Dropped v1 database tables.'); } catch (e) { From 9cc0588175cece4dcfb5a89eb51280059767f90b Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 10 Jan 2023 09:54:16 -0800 Subject: [PATCH 15/25] fix transaction bug --- scripts/migrate-db.js | 77 ++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 8c2be954..5101d3c0 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -37,17 +37,27 @@ async function checkConnection() { async function checkV1Tables() { try { - await prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`; - - success('Database v1 tables found.'); + await prisma.$transaction([ + prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`, + prisma.$queryRaw`select * from account limit 1`, + ]); console.log('Preparing v1 tables for migration'); // alter v1 tables await dropV1Keys(); await renameV1Tables(); await dropV1Indexes(); + + success('Database v1 tables prepared for migration.'); } catch (e) { - error('Database v1 tables not found.'); + // check for V1 renamed tables + try { + await prisma.$queryRaw`select * from v1_account limit 1`; + + success('Database v1 tables ready for migration.'); + } catch (e) { + throw new Error('Database v1 tables not found.'); + } } } @@ -57,7 +67,7 @@ async function checkV2Tables() { success('Database v2 tables found.'); } catch (e) { - error('Database v2 tables not found.'); + console.log('Database v2 tables not found.'); console.log('Adding v2 tables...'); // run v2 prisma migration steps @@ -75,16 +85,17 @@ async function dropV1Keys() { try { // drop keys await prisma.$transaction([ - await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`, ]); success('Dropped v1 database keys.'); } catch (e) { - throw new Error('Failed to drop v1 database keys.'); + error('Failed to drop v1 database keys.'); + process.exit(1); } } @@ -92,18 +103,19 @@ async function renameV1Tables() { try { // rename tables await prisma.$transaction([ - await prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`, - await prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`, ]); success('Renamed v1 database tables.'); } catch (e) { - throw new Error('Failed to rename v1 database tables.'); + error('Failed to rename v1 database tables.'); + process.exit(1); } } @@ -111,21 +123,23 @@ async function dropV1Indexes() { try { // drop indexes await prisma.$transaction([ - await prisma.$executeRaw`DROP INDEX IF EXISTS "user_user_id_key";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "user_username_key";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`, - await prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "user_user_id_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "user_username_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx2";`, ]); success('Dropped v1 database indexes.'); } catch (e) { - throw new Error('Failed to drop v1 database indexes.'); + error('Failed to drop v1 database indexes.'); + process.exit(1); } } @@ -159,7 +173,8 @@ async function deleteV1Tables() { success('Dropped v1 database tables.'); } catch (e) { - throw new Error('Failed to drop v1 database tables.'); + error('Failed to drop v1 database tables.'); + process.exit(1); } } From b05b18e73603832c96bd8d5c9eb76bca4688f2a9 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 10 Jan 2023 15:01:41 -0800 Subject: [PATCH 16/25] update checkV1Tables check --- db/postgresql/migration_v2.sql | 15 ++++++++---- scripts/migrate-db.js | 42 ++++++++++++++++------------------ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/db/postgresql/migration_v2.sql b/db/postgresql/migration_v2.sql index ab95836d..3b8c1356 100644 --- a/db/postgresql/migration_v2.sql +++ b/db/postgresql/migration_v2.sql @@ -11,7 +11,8 @@ SELECT account_uuid, created_at, updated_at, NULL -FROM v1_account; +FROM v1_account +WHERE NOT EXISTS (SELECT 1 FROM "user"); -- website INSERT INTO website @@ -26,7 +27,8 @@ SELECT website_uuid, a.created_at FROM v1_website w JOIN v1_account a -ON a.user_id = w.user_id; +ON a.user_id = w.user_id +WHERE NOT EXISTS (SELECT 1 FROM website); -- session INSERT INTO session @@ -42,7 +44,8 @@ SELECT session_uuid, country FROM v1_session s JOIN v1_website w -ON w.website_id = s.website_id; +ON w.website_id = s.website_id +WHERE NOT EXISTS (SELECT 1 FROM session); -- pageview INSERT INTO website_event @@ -58,7 +61,8 @@ FROM v1_pageview p JOIN v1_session s ON s.session_id = p.session_id JOIN v1_website w -ON w.website_id = s.website_id; +ON w.website_id = s.website_id +WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 1); -- event / event_data INSERT INTO website_event @@ -77,4 +81,5 @@ ON s.session_id = e.session_id JOIN v1_website w ON w.website_id = s.website_id LEFT JOIN v1_event_data ed -ON ed.event_id = e.event_id; \ No newline at end of file +ON ed.event_id = e.event_id +WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 2); \ No newline at end of file diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 5101d3c0..cd50d777 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -36,28 +36,25 @@ async function checkConnection() { } async function checkV1Tables() { - try { - await prisma.$transaction([ - prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`, - prisma.$queryRaw`select * from account limit 1`, - ]); + const updateV1 = + await prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`; + + if (updateV1.length > 0) { console.log('Preparing v1 tables for migration'); // alter v1 tables await dropV1Keys(); await renameV1Tables(); await dropV1Indexes(); + } - success('Database v1 tables prepared for migration.'); + // check for V1 renamed tables + try { + await prisma.$queryRaw`select * from v1_account limit 1`; + + success('Database v1 tables ready for migration.'); } catch (e) { - // check for V1 renamed tables - try { - await prisma.$queryRaw`select * from v1_account limit 1`; - - success('Database v1 tables ready for migration.'); - } catch (e) { - throw new Error('Database v1 tables not found.'); - } + throw new Error('Database v1 tables not found.'); } } @@ -94,8 +91,8 @@ async function dropV1Keys() { success('Dropped v1 database keys.'); } catch (e) { - error('Failed to drop v1 database keys.'); - process.exit(1); + console.log(e); + throw new Error('Failed to drop v1 database keys.'); } } @@ -114,8 +111,8 @@ async function renameV1Tables() { success('Renamed v1 database tables.'); } catch (e) { - error('Failed to rename v1 database tables.'); - process.exit(1); + console.log(e); + throw new Error('Failed to rename v1 database tables.'); } } @@ -138,8 +135,8 @@ async function dropV1Indexes() { success('Dropped v1 database indexes.'); } catch (e) { - error('Failed to drop v1 database indexes.'); - process.exit(1); + console.log(e); + throw new Error('Failed to drop v1 database indexes.'); } } @@ -148,10 +145,11 @@ async function deleteV1TablesPrompt() { type: 'text', name: 'value', message: 'Do you want to delete V1 database tables? (Y/N)', - validate: value => (value !== 'Y' && value !== 'N' ? `Please enter Y or N.` : true), + validate: value => + value.toUpperCase() !== 'Y' && value.toUpperCase() !== 'N' ? `Please enter Y or N.` : true, }); - if (response.value === 'Y') { + if (response.value.toUpperCase() == 'Y') { await deleteV1Tables(); } From ac2b79c5cfc767ba754c3b025154dbcc0bcb0377 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 10 Jan 2023 16:03:44 -0800 Subject: [PATCH 17/25] move migrateData into its own function --- scripts/migrate-db.js | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index cd50d777..2f5ac761 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -9,13 +9,25 @@ const prompts = require('prompts'); const prisma = new PrismaClient(); +// 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(); + function success(msg) { console.log(chalk.greenBright(`✓ ${msg}`)); } -function error(msg) { - console.log(chalk.redBright(`✗ ${msg}`)); -} +// function error(msg) { +// console.log(chalk.redBright(`✗ ${msg}`)); +// } async function checkEnv() { if (!process.env.DATABASE_URL) { @@ -71,13 +83,16 @@ async function checkV2Tables() { await runSqlFile('../prisma/migrations/01_init/migration.sql'); console.log(execSync('prisma migrate resolve --applied 01_init').toString()); console.log(execSync('prisma migrate deploy').toString()); - console.log( - 'Starting v2 data migration. Please do no cancel this process, it may take a while.', - ); - await runSqlFile('../db/postgresql/migration_v2.sql'); } } +async function migrateData() { + console.log('Starting v2 data migration. Please do no cancel this process, it may take a while.'); + await runSqlFile('../db/postgresql/migration_v2.sql'); + + success('Data migration from V1 to V2 tables completed.'); +} + async function dropV1Keys() { try { // drop keys @@ -171,8 +186,7 @@ async function deleteV1Tables() { success('Dropped v1 database tables.'); } catch (e) { - error('Failed to drop v1 database tables.'); - process.exit(1); + throw new Error('Failed to drop v1 database tables.'); } } @@ -203,7 +217,14 @@ async function runSqlFile(filePath) { (async () => { let err = false; - for (let fn of [checkEnv, checkConnection, checkV1Tables, checkV2Tables, deleteV1TablesPrompt]) { + for (let fn of [ + checkEnv, + checkConnection, + checkV1Tables, + checkV2Tables, + migrateData, + deleteV1TablesPrompt, + ]) { try { await fn(); } catch (e) { From 96de650a67deb03b4b0976217e8e123e1721ba5e Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Wed, 11 Jan 2023 16:19:20 -0800 Subject: [PATCH 18/25] add logic for database type --- scripts/migrate-db.js | 96 ++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 2f5ac761..9b9fee08 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -9,17 +9,17 @@ const prompts = require('prompts'); const prisma = new PrismaClient(); -// function getDatabaseType(url = process.env.DATABASE_URL) { -// const type = process.env.DATABASE_TYPE || (url && url.split(':')[0]); +function getDatabaseType(url = process.env.DATABASE_URL) { + const type = process.env.DATABASE_TYPE || (url && url.split(':')[0]); -// if (type === 'postgres') { -// return 'postgresql'; -// } + if (type === 'postgres') { + return 'postgresql'; + } -// return type; -// } + return type; +} -// const databaseType = getDatabaseType(); +const databaseType = getDatabaseType(); function success(msg) { console.log(chalk.greenBright(`✓ ${msg}`)); @@ -47,7 +47,7 @@ async function checkConnection() { } } -async function checkV1Tables() { +async function checkV1Tables(databaseType) { const updateV1 = await prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`; @@ -55,9 +55,12 @@ async function checkV1Tables() { console.log('Preparing v1 tables for migration'); // alter v1 tables - await dropV1Keys(); - await renameV1Tables(); - await dropV1Indexes(); + if (databaseType === 'postgresql') { + await dropV1Keys(); + } + + await renameV1Tables(databaseType); + await dropV1Indexes(databaseType); } // check for V1 renamed tables @@ -111,18 +114,30 @@ async function dropV1Keys() { } } -async function renameV1Tables() { +async function renameV1Tables(databaseType) { try { // rename tables - await prisma.$transaction([ - prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`, - ]); + if (databaseType === 'postgresql') { + await prisma.$transaction([ + prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`, + ]); + } else { + await prisma.$transaction([ + prisma.$executeRaw`RENAME TABLE _prisma_migrations TO v1_prisma_migrations;`, + prisma.$executeRaw`RENAME TABLE account TO v1_account;`, + prisma.$executeRaw`RENAME TABLE event TO v1_event;`, + prisma.$executeRaw`RENAME TABLE event_data TO v1_event_data;`, + prisma.$executeRaw`RENAME TABLE pageview TO v1_pageview;`, + prisma.$executeRaw`RENAME TABLE session TO v1_session;`, + prisma.$executeRaw`RENAME TABLE website TO v1_website;`, + ]); + } success('Renamed v1 database tables.'); } catch (e) { @@ -131,22 +146,29 @@ async function renameV1Tables() { } } -async function dropV1Indexes() { +async function dropV1Indexes(databaseType) { try { // drop indexes - await prisma.$transaction([ - prisma.$executeRaw`DROP INDEX IF EXISTS "user_user_id_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "user_username_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx2";`, - ]); + if (databaseType === 'postgresql') { + await prisma.$transaction([ + prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`, + prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`, + ]); + } else { + await prisma.$transaction([ + prisma.$executeRaw`DROP INDEX session_session_uuid_key ON session;`, + prisma.$executeRaw`DROP INDEX session_created_at_idx ON session;`, + prisma.$executeRaw`DROP INDEX session_website_id_idx ON session;`, + prisma.$executeRaw`DROP INDEX website_share_id_key ON website;`, + prisma.$executeRaw`DROP INDEX website_website_uuid_key ON website;`, + ]); + } success('Dropped v1 database indexes.'); } catch (e) { @@ -226,7 +248,7 @@ async function runSqlFile(filePath) { deleteV1TablesPrompt, ]) { try { - await fn(); + fn.name === 'checkV1Tables' ? await fn(databaseType) : await fn(); } catch (e) { console.log(chalk.red(`✗ ${e.message}`)); err = true; From 65fe29c38553173e90bb272b3a62debf11c17d9e Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 13 Jan 2023 11:54:22 -0800 Subject: [PATCH 19/25] add mysql migration_v2 file, refactor migrate-db --- db/mysql/migration_v2.sql | 85 +++++++++++++++++++++++ db/mysql/migrations/01_init/migration.sql | 3 + scripts/migrate-db.js | 11 +-- 3 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 db/mysql/migration_v2.sql diff --git a/db/mysql/migration_v2.sql b/db/mysql/migration_v2.sql new file mode 100644 index 00000000..b59878fd --- /dev/null +++ b/db/mysql/migration_v2.sql @@ -0,0 +1,85 @@ +-- account +DELETE FROM `user` +WHERE username = 'admin'; + +INSERT INTO `user` +(user_id, username, password, role, created_at, updated_at, deleted_at) +SELECT account_uuid, + username, + password, + CASE WHEN is_admin = true THEN 'admin' ELSE 'user' END, + created_at, + updated_at, + NULL +FROM v1_account +WHERE NOT EXISTS (SELECT 1 FROM `user`); + +-- website +INSERT INTO website +(website_id, name, domain, share_id, rev_id, user_id, team_id, created_at) +SELECT website_uuid, + name, + domain, + share_id, + 0 rev_id, + a.account_uuid, + NULL team_id, + a.created_at +FROM v1_website w +JOIN v1_account a +ON a.user_id = w.user_id +WHERE NOT EXISTS (SELECT 1 FROM website); + +-- session +INSERT INTO session +(session_id, website_id, hostname, browser, os, device, screen, language, country) +SELECT session_uuid, + w.website_uuid, + hostname, + browser, + os, + device, + screen, + language, + country +FROM v1_session s +JOIN v1_website w +ON w.website_id = s.website_id +WHERE NOT EXISTS (SELECT 1 FROM session); + +-- pageview +INSERT INTO website_event +(event_id, website_id, session_id, created_at, url, referrer, event_type) +SELECT uuid() event_id, + w.website_uuid, + s.session_uuid, + p.created_at, + p.url, + p.referrer, + 1 event_type +FROM v1_pageview p +JOIN v1_session s +ON s.session_id = p.session_id +JOIN v1_website w +ON w.website_id = s.website_id +WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 1); + +-- event / event_data +INSERT INTO website_event +(event_id, website_id, session_id, created_at, url, event_type, event_name, event_data) +SELECT e.event_uuid, + w.website_uuid, + s.session_uuid, + e.created_at, + e.url, + 2 event_type, + e.event_name, + ed.event_data +FROM v1_event e +JOIN v1_session s +ON s.session_id = e.session_id +JOIN v1_website w +ON w.website_id = s.website_id +LEFT JOIN v1_event_data ed +ON ed.event_id = e.event_id +WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 2); \ No newline at end of file diff --git a/db/mysql/migrations/01_init/migration.sql b/db/mysql/migrations/01_init/migration.sql index e549ffec..52a6c0e7 100644 --- a/db/mysql/migrations/01_init/migration.sql +++ b/db/mysql/migrations/01_init/migration.sql @@ -106,3 +106,6 @@ CREATE TABLE `team_user` ( INDEX `team_user_user_id_idx`(`user_id`), PRIMARY KEY (`team_user_id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateAdminUser +INSERT INTO account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true); \ No newline at end of file diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 9b9fee08..0984901f 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -59,8 +59,8 @@ async function checkV1Tables(databaseType) { await dropV1Keys(); } - await renameV1Tables(databaseType); await dropV1Indexes(databaseType); + await renameV1Tables(databaseType); } // check for V1 renamed tables @@ -162,11 +162,12 @@ async function dropV1Indexes(databaseType) { ]); } else { await prisma.$transaction([ - prisma.$executeRaw`DROP INDEX session_session_uuid_key ON session;`, + prisma.$executeRaw`ALTER TABLE session DROP FOREIGN KEY session_website_id_fkey;`, prisma.$executeRaw`DROP INDEX session_created_at_idx ON session;`, prisma.$executeRaw`DROP INDEX session_website_id_idx ON session;`, + prisma.$executeRaw`ALTER TABLE website DROP FOREIGN KEY website_user_id_fkey;`, + prisma.$executeRaw`DROP INDEX website_user_id_idx ON website;`, prisma.$executeRaw`DROP INDEX website_share_id_key ON website;`, - prisma.$executeRaw`DROP INDEX website_website_uuid_key ON website;`, ]); } @@ -226,7 +227,9 @@ async function runSqlFile(filePath) { .split(';'); for (const sql of sqlStatements) { - await prisma.$executeRawUnsafe(sql); + if (sql.length > 0) { + await prisma.$executeRawUnsafe(sql); + } } filePath; From aba5b9362ea9079083e5d4a45e037759a72ea8ba Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 16 Jan 2023 11:59:55 -0800 Subject: [PATCH 20/25] refactor migrate-db --- scripts/migrate-db.js | 165 +++++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 76 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 0984901f..88e5336f 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -25,9 +25,9 @@ function success(msg) { console.log(chalk.greenBright(`✓ ${msg}`)); } -// function error(msg) { -// console.log(chalk.redBright(`✗ ${msg}`)); -// } +function error(msg) { + console.log(chalk.redBright(`✗ ${msg}`)); +} async function checkEnv() { if (!process.env.DATABASE_URL) { @@ -48,28 +48,19 @@ async function checkConnection() { } async function checkV1Tables(databaseType) { - const updateV1 = + try { await prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`; - if (updateV1.length > 0) { console.log('Preparing v1 tables for migration'); // alter v1 tables - if (databaseType === 'postgresql') { - await dropV1Keys(); - } - + await dropV1Keys(databaseType); await dropV1Indexes(databaseType); await renameV1Tables(databaseType); - } - - // check for V1 renamed tables - try { - await prisma.$queryRaw`select * from v1_account limit 1`; success('Database v1 tables ready for migration.'); } catch (e) { - throw new Error('Database v1 tables not found.'); + error('Database v1 tables is not up to date.'); } } @@ -85,32 +76,83 @@ async function checkV2Tables() { // run v2 prisma migration steps await runSqlFile('../prisma/migrations/01_init/migration.sql'); console.log(execSync('prisma migrate resolve --applied 01_init').toString()); - console.log(execSync('prisma migrate deploy').toString()); + // console.log(execSync('prisma migrate deploy').toString()); } } -async function migrateData() { +async function checkMigrationReady() { + try { + await prisma.$queryRaw`select * from website_event limit 1`; + await prisma.$queryRaw`select * from v1_account limit 1`; + + success('Database is ready for migration.'); + } catch (e) { + throw new Error('Database is not ready for migration.'); + } +} + +async function migrateData(databaseType) { + const filePath = `../db/${databaseType}/migration_v2.sql`; console.log('Starting v2 data migration. Please do no cancel this process, it may take a while.'); - await runSqlFile('../db/postgresql/migration_v2.sql'); + await runSqlFile(filePath); success('Data migration from V1 to V2 tables completed.'); } -async function dropV1Keys() { +async function dropV1Keys(databaseType) { try { // drop keys - await prisma.$transaction([ - prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" DROP CONSTRAINT IF EXISTS "_prisma_migrations_pkey" cascade;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "account" DROP CONSTRAINT IF EXISTS "account_pkey" cascade;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "event" DROP CONSTRAINT IF EXISTS "event_pkey" cascade;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "session" DROP CONSTRAINT IF EXISTS "session_pkey" cascade;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "website" DROP CONSTRAINT IF EXISTS "website_pkey" cascade;`, - ]); + if (databaseType === 'postgresql') { + await prisma.$transaction([ + prisma.$executeRaw`ALTER TABLE IF EXISTS _prisma_migrations DROP CONSTRAINT IF EXISTS _prisma_migrations_pkey CASCADE;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS account DROP CONSTRAINT IF EXISTS account_pkey CASCADE;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS event DROP CONSTRAINT IF EXISTS event_pkey CASCADE;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS session DROP CONSTRAINT IF EXISTS session_pkey CASCADE;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS website DROP CONSTRAINT IF EXISTS website_pkey CASCADE;`, + ]); + } else { + await prisma.$transaction([ + prisma.$executeRaw`ALTER TABLE session DROP FOREIGN KEY session_website_id_fkey;`, + prisma.$executeRaw`ALTER TABLE website DROP FOREIGN KEY website_user_id_fkey;`, + ]); + } success('Dropped v1 database keys.'); } catch (e) { console.log(e); - throw new Error('Failed to drop v1 database keys.'); + error('Failed to drop v1 database keys.'); + process.exit(1); + } +} + +async function dropV1Indexes(databaseType) { + try { + // drop indexes + if (databaseType === 'postgresql') { + await prisma.$transaction([ + prisma.$executeRaw`DROP INDEX IF EXISTS session_session_id_key;`, + prisma.$executeRaw`DROP INDEX IF EXISTS session_created_at_idx;`, + prisma.$executeRaw`DROP INDEX IF EXISTS session_website_id_idx;`, + prisma.$executeRaw`DROP INDEX IF EXISTS website_website_id_key;`, + prisma.$executeRaw`DROP INDEX IF EXISTS website_share_id_key;`, + prisma.$executeRaw`DROP INDEX IF EXISTS website_created_at_idx;`, + prisma.$executeRaw`DROP INDEX IF EXISTS website_share_id_idx;`, + prisma.$executeRaw`DROP INDEX IF EXISTS website_user_id_idx;`, + ]); + } else { + await prisma.$transaction([ + prisma.$executeRaw`DROP INDEX session_created_at_idx ON session;`, + prisma.$executeRaw`DROP INDEX session_website_id_idx ON session;`, + prisma.$executeRaw`DROP INDEX website_user_id_idx ON website;`, + prisma.$executeRaw`DROP INDEX website_share_id_key ON website;`, + ]); + } + + success('Dropped v1 database indexes.'); + } catch (e) { + console.log(e); + error('Failed to drop v1 database indexes.'); + process.exit(1); } } @@ -119,13 +161,13 @@ async function renameV1Tables(databaseType) { // rename tables if (databaseType === 'postgresql') { await prisma.$transaction([ - prisma.$executeRaw`ALTER TABLE IF EXISTS "_prisma_migrations" RENAME TO "v1_prisma_migrations";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "account" RENAME TO "v1_account";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "event" RENAME TO "v1_event";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "event_data" RENAME TO "v1_event_data";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "pageview" RENAME TO "v1_pageview";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "session" RENAME TO "v1_session";`, - prisma.$executeRaw`ALTER TABLE IF EXISTS "website" RENAME TO "v1_website";`, + prisma.$executeRaw`ALTER TABLE IF EXISTS _prisma_migrations RENAME TO v1_prisma_migrations;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS account RENAME TO v1_account;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS event RENAME TO v1_event;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS event_data RENAME TO v1_event_data;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS pageview RENAME TO v1_pageview;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS session RENAME TO v1_session;`, + prisma.$executeRaw`ALTER TABLE IF EXISTS website RENAME TO v1_website;`, ]); } else { await prisma.$transaction([ @@ -142,39 +184,8 @@ async function renameV1Tables(databaseType) { success('Renamed v1 database tables.'); } catch (e) { console.log(e); - throw new Error('Failed to rename v1 database tables.'); - } -} - -async function dropV1Indexes(databaseType) { - try { - // drop indexes - if (databaseType === 'postgresql') { - await prisma.$transaction([ - prisma.$executeRaw`DROP INDEX IF EXISTS "session_session_id_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "session_created_at_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "session_website_id_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_website_id_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_key";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_created_at_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_share_id_idx";`, - prisma.$executeRaw`DROP INDEX IF EXISTS "website_user_id_idx";`, - ]); - } else { - await prisma.$transaction([ - prisma.$executeRaw`ALTER TABLE session DROP FOREIGN KEY session_website_id_fkey;`, - prisma.$executeRaw`DROP INDEX session_created_at_idx ON session;`, - prisma.$executeRaw`DROP INDEX session_website_id_idx ON session;`, - prisma.$executeRaw`ALTER TABLE website DROP FOREIGN KEY website_user_id_fkey;`, - prisma.$executeRaw`DROP INDEX website_user_id_idx ON website;`, - prisma.$executeRaw`DROP INDEX website_share_id_key ON website;`, - ]); - } - - success('Dropped v1 database indexes.'); - } catch (e) { - console.log(e); - throw new Error('Failed to drop v1 database indexes.'); + error('Failed to rename v1 database tables.'); + process.exit(1); } } @@ -198,17 +209,18 @@ async function deleteV1Tables() { try { // drop tables await prisma.$transaction([ - prisma.$executeRaw`DROP TABLE IF EXISTS "v1_prisma_migrations";`, - prisma.$executeRaw`DROP TABLE IF EXISTS "v1_account";`, - prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event";`, - prisma.$executeRaw`DROP TABLE IF EXISTS "v1_event_data";`, - prisma.$executeRaw`DROP TABLE IF EXISTS "v1_pageview";`, - prisma.$executeRaw`DROP TABLE IF EXISTS "v1_session";`, - prisma.$executeRaw`DROP TABLE IF EXISTS "v1_website";`, + prisma.$executeRaw`DROP TABLE IF EXISTS v1_prisma_migrations;`, + prisma.$executeRaw`DROP TABLE IF EXISTS v1_event_data;`, + prisma.$executeRaw`DROP TABLE IF EXISTS v1_event;`, + prisma.$executeRaw`DROP TABLE IF EXISTS v1_pageview;`, + prisma.$executeRaw`DROP TABLE IF EXISTS v1_session;`, + prisma.$executeRaw`DROP TABLE IF EXISTS v1_website;`, + prisma.$executeRaw`DROP TABLE IF EXISTS v1_account;`, ]); success('Dropped v1 database tables.'); } catch (e) { + console.log(e); throw new Error('Failed to drop v1 database tables.'); } } @@ -247,13 +259,14 @@ async function runSqlFile(filePath) { checkConnection, checkV1Tables, checkV2Tables, + checkMigrationReady, migrateData, deleteV1TablesPrompt, ]) { try { - fn.name === 'checkV1Tables' ? await fn(databaseType) : await fn(); + ['checkV1Tables', 'migrateData'].includes(fn.name) ? await fn(databaseType) : await fn(); } catch (e) { - console.log(chalk.red(`✗ ${e.message}`)); + error(e.message); err = true; } finally { await prisma.$disconnect(); From 1bb33f7afff50eaaa96afe86a3445e9cb0891831 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Mon, 16 Jan 2023 12:14:50 -0800 Subject: [PATCH 21/25] clean-up migrate data param --- scripts/migrate-db.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js index 88e5336f..a41b4941 100644 --- a/scripts/migrate-db.js +++ b/scripts/migrate-db.js @@ -76,7 +76,6 @@ async function checkV2Tables() { // run v2 prisma migration steps await runSqlFile('../prisma/migrations/01_init/migration.sql'); console.log(execSync('prisma migrate resolve --applied 01_init').toString()); - // console.log(execSync('prisma migrate deploy').toString()); } } @@ -91,8 +90,8 @@ async function checkMigrationReady() { } } -async function migrateData(databaseType) { - const filePath = `../db/${databaseType}/migration_v2.sql`; +async function migrateData() { + const filePath = `../prisma/migration_v2.sql`; console.log('Starting v2 data migration. Please do no cancel this process, it may take a while.'); await runSqlFile(filePath); @@ -264,7 +263,7 @@ async function runSqlFile(filePath) { deleteV1TablesPrompt, ]) { try { - ['checkV1Tables', 'migrateData'].includes(fn.name) ? await fn(databaseType) : await fn(); + fn.name === 'checkV1Tables' ? await fn(databaseType) : await fn(); } catch (e) { error(e.message); err = true; From 529b7a35c3ace97176078dc7ecfe13c7b17ae02c Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Tue, 17 Jan 2023 10:36:16 -0800 Subject: [PATCH 22/25] add pgcrypto to postgres via extension preview --- db/mysql/migrations/01_init/migration.sql | 4 ++-- db/postgresql/schema.prisma | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/db/mysql/migrations/01_init/migration.sql b/db/mysql/migrations/01_init/migration.sql index 52a6c0e7..4b51de7f 100644 --- a/db/mysql/migrations/01_init/migration.sql +++ b/db/mysql/migrations/01_init/migration.sql @@ -107,5 +107,5 @@ CREATE TABLE `team_user` ( PRIMARY KEY (`team_user_id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; --- CreateAdminUser -INSERT INTO account (username, password, is_admin) values ('admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa', true); \ No newline at end of file +-- AddSystemUser +INSERT INTO `user` (user_id, username, role, password) VALUES ('41e2b680-648e-4b09-bcd7-3e2b10c06264' , 'admin', 'admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa'); \ No newline at end of file diff --git a/db/postgresql/schema.prisma b/db/postgresql/schema.prisma index 7e4e20d1..9c5e6ff5 100644 --- a/db/postgresql/schema.prisma +++ b/db/postgresql/schema.prisma @@ -1,11 +1,13 @@ generator client { provider = "prisma-client-js" + previewFeatures = ["postgresqlExtensions"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") relationMode = "prisma" + extensions = [pgcrypto] } model User { From 0b16d06d8c393bf365f034897e3861743d4ca505 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 2 Feb 2023 10:04:21 -0800 Subject: [PATCH 23/25] move migrate-db to own repo --- db/mysql/migration_v2.sql | 85 ---------- db/postgresql/migration_v2.sql | 85 ---------- db/postgresql/schema.prisma | 2 - package.json | 1 - scripts/migrate-db.js | 277 --------------------------------- 5 files changed, 450 deletions(-) delete mode 100644 db/mysql/migration_v2.sql delete mode 100644 db/postgresql/migration_v2.sql delete mode 100644 scripts/migrate-db.js diff --git a/db/mysql/migration_v2.sql b/db/mysql/migration_v2.sql deleted file mode 100644 index b59878fd..00000000 --- a/db/mysql/migration_v2.sql +++ /dev/null @@ -1,85 +0,0 @@ --- account -DELETE FROM `user` -WHERE username = 'admin'; - -INSERT INTO `user` -(user_id, username, password, role, created_at, updated_at, deleted_at) -SELECT account_uuid, - username, - password, - CASE WHEN is_admin = true THEN 'admin' ELSE 'user' END, - created_at, - updated_at, - NULL -FROM v1_account -WHERE NOT EXISTS (SELECT 1 FROM `user`); - --- website -INSERT INTO website -(website_id, name, domain, share_id, rev_id, user_id, team_id, created_at) -SELECT website_uuid, - name, - domain, - share_id, - 0 rev_id, - a.account_uuid, - NULL team_id, - a.created_at -FROM v1_website w -JOIN v1_account a -ON a.user_id = w.user_id -WHERE NOT EXISTS (SELECT 1 FROM website); - --- session -INSERT INTO session -(session_id, website_id, hostname, browser, os, device, screen, language, country) -SELECT session_uuid, - w.website_uuid, - hostname, - browser, - os, - device, - screen, - language, - country -FROM v1_session s -JOIN v1_website w -ON w.website_id = s.website_id -WHERE NOT EXISTS (SELECT 1 FROM session); - --- pageview -INSERT INTO website_event -(event_id, website_id, session_id, created_at, url, referrer, event_type) -SELECT uuid() event_id, - w.website_uuid, - s.session_uuid, - p.created_at, - p.url, - p.referrer, - 1 event_type -FROM v1_pageview p -JOIN v1_session s -ON s.session_id = p.session_id -JOIN v1_website w -ON w.website_id = s.website_id -WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 1); - --- event / event_data -INSERT INTO website_event -(event_id, website_id, session_id, created_at, url, event_type, event_name, event_data) -SELECT e.event_uuid, - w.website_uuid, - s.session_uuid, - e.created_at, - e.url, - 2 event_type, - e.event_name, - ed.event_data -FROM v1_event e -JOIN v1_session s -ON s.session_id = e.session_id -JOIN v1_website w -ON w.website_id = s.website_id -LEFT JOIN v1_event_data ed -ON ed.event_id = e.event_id -WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 2); \ No newline at end of file diff --git a/db/postgresql/migration_v2.sql b/db/postgresql/migration_v2.sql deleted file mode 100644 index 3b8c1356..00000000 --- a/db/postgresql/migration_v2.sql +++ /dev/null @@ -1,85 +0,0 @@ --- account -DELETE FROM "user" -WHERE username = 'admin'; - -INSERT INTO "user" -(user_id, username, password, role, created_at, updated_at, deleted_at) -SELECT account_uuid, - username, - password, - CASE WHEN is_admin = true THEN 'admin' ELSE 'user' END, - created_at, - updated_at, - NULL -FROM v1_account -WHERE NOT EXISTS (SELECT 1 FROM "user"); - --- website -INSERT INTO website -(website_id, name, domain, share_id, rev_id, user_id, team_id, created_at) -SELECT website_uuid, - name, - domain, - share_id, - 0 rev_id, - a.account_uuid, - NULL team_id, - a.created_at -FROM v1_website w -JOIN v1_account a -ON a.user_id = w.user_id -WHERE NOT EXISTS (SELECT 1 FROM website); - --- session -INSERT INTO session -(session_id, website_id, hostname, browser, os, device, screen, language, country) -SELECT session_uuid, - w.website_uuid, - hostname, - browser, - os, - device, - screen, - language, - country -FROM v1_session s -JOIN v1_website w -ON w.website_id = s.website_id -WHERE NOT EXISTS (SELECT 1 FROM session); - --- pageview -INSERT INTO website_event -(event_id, website_id, session_id, created_at, url, referrer, event_type) -SELECT gen_random_uuid() event_id, - w.website_uuid, - s.session_uuid, - p.created_at, - p.url, - p.referrer, - 1 event_type -FROM v1_pageview p -JOIN v1_session s -ON s.session_id = p.session_id -JOIN v1_website w -ON w.website_id = s.website_id -WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 1); - --- event / event_data -INSERT INTO website_event -(event_id, website_id, session_id, created_at, url, event_type, event_name, event_data) -SELECT e.event_uuid, - w.website_uuid, - s.session_uuid, - e.created_at, - e.url, - 2 event_type, - e.event_name, - ed.event_data -FROM v1_event e -JOIN v1_session s -ON s.session_id = e.session_id -JOIN v1_website w -ON w.website_id = s.website_id -LEFT JOIN v1_event_data ed -ON ed.event_id = e.event_id -WHERE NOT EXISTS (SELECT 1 FROM website_event WHERE event_type = 2); \ No newline at end of file diff --git a/db/postgresql/schema.prisma b/db/postgresql/schema.prisma index 5248ec79..ed1c4fe9 100644 --- a/db/postgresql/schema.prisma +++ b/db/postgresql/schema.prisma @@ -1,13 +1,11 @@ generator client { provider = "prisma-client-js" - previewFeatures = ["postgresqlExtensions"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") relationMode = "prisma" - extensions = [pgcrypto] } model User { diff --git a/package.json b/package.json index f7528d3b..334327f8 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "update-tracker": "node scripts/update-tracker.js", "update-db": "prisma migrate deploy", "check-db": "node scripts/check-db.js", - "migrate-db": "node scripts/migrate-db.js", "copy-db-files": "node scripts/copy-db-files.js", "generate-lang": "npm-run-all extract-lang merge-lang", "extract-lang": "formatjs extract \"{pages,components}/**/*.js\" --out-file build/messages.json", diff --git a/scripts/migrate-db.js b/scripts/migrate-db.js deleted file mode 100644 index a41b4941..00000000 --- a/scripts/migrate-db.js +++ /dev/null @@ -1,277 +0,0 @@ -/* eslint-disable no-console */ -require('dotenv').config(); -const fs = require('fs'); -const path = require('path'); -const { PrismaClient } = require('@prisma/client'); -const chalk = require('chalk'); -const { execSync } = require('child_process'); -const prompts = require('prompts'); - -const prisma = new PrismaClient(); - -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(); - -function success(msg) { - console.log(chalk.greenBright(`✓ ${msg}`)); -} - -function error(msg) { - console.log(chalk.redBright(`✗ ${msg}`)); -} - -async function checkEnv() { - if (!process.env.DATABASE_URL) { - throw new Error('DATABASE_URL is not defined.'); - } else { - success('DATABASE_URL is defined.'); - } -} - -async function checkConnection() { - try { - await prisma.$connect(); - - success('Database connection successful.'); - } catch (e) { - throw new Error('Unable to connect to the database.'); - } -} - -async function checkV1Tables(databaseType) { - try { - await prisma.$queryRaw`select * from _prisma_migrations where migration_name = '04_add_uuid' and finished_at IS NOT NULL`; - - console.log('Preparing v1 tables for migration'); - - // alter v1 tables - await dropV1Keys(databaseType); - await dropV1Indexes(databaseType); - await renameV1Tables(databaseType); - - success('Database v1 tables ready for migration.'); - } catch (e) { - error('Database v1 tables is not up to date.'); - } -} - -async function checkV2Tables() { - try { - await prisma.$queryRaw`select * from website_event limit 1`; - - success('Database v2 tables found.'); - } catch (e) { - console.log('Database v2 tables not found.'); - console.log('Adding v2 tables...'); - - // run v2 prisma migration steps - await runSqlFile('../prisma/migrations/01_init/migration.sql'); - console.log(execSync('prisma migrate resolve --applied 01_init').toString()); - } -} - -async function checkMigrationReady() { - try { - await prisma.$queryRaw`select * from website_event limit 1`; - await prisma.$queryRaw`select * from v1_account limit 1`; - - success('Database is ready for migration.'); - } catch (e) { - throw new Error('Database is not ready for migration.'); - } -} - -async function migrateData() { - const filePath = `../prisma/migration_v2.sql`; - console.log('Starting v2 data migration. Please do no cancel this process, it may take a while.'); - await runSqlFile(filePath); - - success('Data migration from V1 to V2 tables completed.'); -} - -async function dropV1Keys(databaseType) { - try { - // drop keys - if (databaseType === 'postgresql') { - await prisma.$transaction([ - prisma.$executeRaw`ALTER TABLE IF EXISTS _prisma_migrations DROP CONSTRAINT IF EXISTS _prisma_migrations_pkey CASCADE;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS account DROP CONSTRAINT IF EXISTS account_pkey CASCADE;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS event DROP CONSTRAINT IF EXISTS event_pkey CASCADE;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS session DROP CONSTRAINT IF EXISTS session_pkey CASCADE;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS website DROP CONSTRAINT IF EXISTS website_pkey CASCADE;`, - ]); - } else { - await prisma.$transaction([ - prisma.$executeRaw`ALTER TABLE session DROP FOREIGN KEY session_website_id_fkey;`, - prisma.$executeRaw`ALTER TABLE website DROP FOREIGN KEY website_user_id_fkey;`, - ]); - } - - success('Dropped v1 database keys.'); - } catch (e) { - console.log(e); - error('Failed to drop v1 database keys.'); - process.exit(1); - } -} - -async function dropV1Indexes(databaseType) { - try { - // drop indexes - if (databaseType === 'postgresql') { - await prisma.$transaction([ - prisma.$executeRaw`DROP INDEX IF EXISTS session_session_id_key;`, - prisma.$executeRaw`DROP INDEX IF EXISTS session_created_at_idx;`, - prisma.$executeRaw`DROP INDEX IF EXISTS session_website_id_idx;`, - prisma.$executeRaw`DROP INDEX IF EXISTS website_website_id_key;`, - prisma.$executeRaw`DROP INDEX IF EXISTS website_share_id_key;`, - prisma.$executeRaw`DROP INDEX IF EXISTS website_created_at_idx;`, - prisma.$executeRaw`DROP INDEX IF EXISTS website_share_id_idx;`, - prisma.$executeRaw`DROP INDEX IF EXISTS website_user_id_idx;`, - ]); - } else { - await prisma.$transaction([ - prisma.$executeRaw`DROP INDEX session_created_at_idx ON session;`, - prisma.$executeRaw`DROP INDEX session_website_id_idx ON session;`, - prisma.$executeRaw`DROP INDEX website_user_id_idx ON website;`, - prisma.$executeRaw`DROP INDEX website_share_id_key ON website;`, - ]); - } - - success('Dropped v1 database indexes.'); - } catch (e) { - console.log(e); - error('Failed to drop v1 database indexes.'); - process.exit(1); - } -} - -async function renameV1Tables(databaseType) { - try { - // rename tables - if (databaseType === 'postgresql') { - await prisma.$transaction([ - prisma.$executeRaw`ALTER TABLE IF EXISTS _prisma_migrations RENAME TO v1_prisma_migrations;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS account RENAME TO v1_account;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS event RENAME TO v1_event;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS event_data RENAME TO v1_event_data;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS pageview RENAME TO v1_pageview;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS session RENAME TO v1_session;`, - prisma.$executeRaw`ALTER TABLE IF EXISTS website RENAME TO v1_website;`, - ]); - } else { - await prisma.$transaction([ - prisma.$executeRaw`RENAME TABLE _prisma_migrations TO v1_prisma_migrations;`, - prisma.$executeRaw`RENAME TABLE account TO v1_account;`, - prisma.$executeRaw`RENAME TABLE event TO v1_event;`, - prisma.$executeRaw`RENAME TABLE event_data TO v1_event_data;`, - prisma.$executeRaw`RENAME TABLE pageview TO v1_pageview;`, - prisma.$executeRaw`RENAME TABLE session TO v1_session;`, - prisma.$executeRaw`RENAME TABLE website TO v1_website;`, - ]); - } - - success('Renamed v1 database tables.'); - } catch (e) { - console.log(e); - error('Failed to rename v1 database tables.'); - process.exit(1); - } -} - -async function deleteV1TablesPrompt() { - const response = await prompts({ - type: 'text', - name: 'value', - message: 'Do you want to delete V1 database tables? (Y/N)', - validate: value => - value.toUpperCase() !== 'Y' && value.toUpperCase() !== 'N' ? `Please enter Y or N.` : true, - }); - - if (response.value.toUpperCase() == 'Y') { - await deleteV1Tables(); - } - - success('Migration successfully completed.'); -} - -async function deleteV1Tables() { - try { - // drop tables - await prisma.$transaction([ - prisma.$executeRaw`DROP TABLE IF EXISTS v1_prisma_migrations;`, - prisma.$executeRaw`DROP TABLE IF EXISTS v1_event_data;`, - prisma.$executeRaw`DROP TABLE IF EXISTS v1_event;`, - prisma.$executeRaw`DROP TABLE IF EXISTS v1_pageview;`, - prisma.$executeRaw`DROP TABLE IF EXISTS v1_session;`, - prisma.$executeRaw`DROP TABLE IF EXISTS v1_website;`, - prisma.$executeRaw`DROP TABLE IF EXISTS v1_account;`, - ]); - - success('Dropped v1 database tables.'); - } catch (e) { - console.log(e); - throw new Error('Failed to drop v1 database tables.'); - } -} - -async function runSqlFile(filePath) { - try { - const rawSql = await fs.promises.readFile(path.join(__dirname, filePath)); - - const sqlStatements = rawSql - .toString() - .split('\n') - .filter(line => !line.startsWith('--')) // remove comments-only lines - .join('\n') - .replace(/\r\n|\n|\r/g, ' ') // remove newlines - .replace(/\s+/g, ' ') // excess white space - .split(';'); - - for (const sql of sqlStatements) { - if (sql.length > 0) { - await prisma.$executeRawUnsafe(sql); - } - } - filePath; - - success(`Ran sql file ${filePath}.`); - } catch (e) { - console.log(e); - throw new Error(`Failed to run sql file ${filePath}.`); - } -} - -(async () => { - let err = false; - for (let fn of [ - checkEnv, - checkConnection, - checkV1Tables, - checkV2Tables, - checkMigrationReady, - migrateData, - deleteV1TablesPrompt, - ]) { - try { - fn.name === 'checkV1Tables' ? await fn(databaseType) : await fn(); - } catch (e) { - error(e.message); - err = true; - } finally { - await prisma.$disconnect(); - if (err) { - process.exit(1); - } - } - } -})(); From 9078444ca5f464116a783512cc985b2dc89235c6 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 2 Feb 2023 10:12:25 -0800 Subject: [PATCH 24/25] update mysql to latest schema --- db/mysql/schema.prisma | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/db/mysql/schema.prisma b/db/mysql/schema.prisma index ba035ab5..f3b30236 100644 --- a/db/mysql/schema.prisma +++ b/db/mysql/schema.prisma @@ -19,6 +19,7 @@ model User { teamUser TeamUser[] Website Website[] + teamWebsite TeamWebsite[] @@map("user") } @@ -47,15 +48,13 @@ model Website { shareId String? @unique @map("share_id") @db.VarChar(50) revId Int @default(0) @map("rev_id") @db.UnsignedInt userId String? @map("user_id") @db.VarChar(36) - teamId String? @map("team_id") @db.VarChar(36) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) updatedAt DateTime? @map("updated_at") @db.Timestamp(0) deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) - team Team? @relation(fields: [teamId], references: [id]) user User? @relation(fields: [userId], references: [id]) + teamWebsite TeamWebsite[] - @@index([teamId]) @@index([userId]) @@index([createdAt]) @@index([shareId]) @@ -88,10 +87,9 @@ model Team { accessCode String? @unique @map("access_code") @db.VarChar(50) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) updatedAt DateTime? @map("updated_at") @db.Timestamp(0) - deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) teamUsers TeamUser[] - Website Website[] + teamWebsite TeamWebsite[] @@index([userId]) @@index([accessCode]) @@ -105,7 +103,6 @@ model TeamUser { role String @map("role") @db.VarChar(50) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) updatedAt DateTime? @map("updated_at") @db.Timestamp(0) - deletedAt DateTime? @map("deleted_at") @db.Timestamp(0) team Team @relation(fields: [teamId], references: [id]) user User @relation(fields: [userId], references: [id]) @@ -114,3 +111,20 @@ model TeamUser { @@index([userId]) @@map("team_user") } + +model TeamWebsite { + id String @id() @unique() @map("team_website_id") @db.VarChar(36) + teamId String @map("team_id") @db.VarChar(36) + userId String @map("user_id") @db.VarChar(36) + websiteId String @map("website_id") @db.VarChar(36) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) + + team Team @relation(fields: [teamId], references: [id]) + user User @relation(fields: [userId], references: [id]) + website Website @relation(fields: [websiteId], references: [id]) + + @@index([teamId]) + @@index([userId]) + @@index([websiteId]) + @@map("team_website") +} From 6457ddfec1d4afdab31779309a6ee20c800b6c91 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Thu, 2 Feb 2023 10:18:06 -0800 Subject: [PATCH 25/25] update 01_init to latest --- db/mysql/migrations/01_init/migration.sql | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/db/mysql/migrations/01_init/migration.sql b/db/mysql/migrations/01_init/migration.sql index 4b51de7f..d5f0e93a 100644 --- a/db/mysql/migrations/01_init/migration.sql +++ b/db/mysql/migrations/01_init/migration.sql @@ -40,14 +40,12 @@ CREATE TABLE `website` ( `share_id` VARCHAR(50) NULL, `rev_id` INTEGER UNSIGNED NOT NULL DEFAULT 0, `user_id` VARCHAR(36) NULL, - `team_id` VARCHAR(36) NULL, `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), `updated_at` TIMESTAMP(0) NULL, `deleted_at` TIMESTAMP(0) NULL, UNIQUE INDEX `website_website_id_key`(`website_id`), UNIQUE INDEX `website_share_id_key`(`share_id`), - INDEX `website_team_id_idx`(`team_id`), INDEX `website_user_id_idx`(`user_id`), INDEX `website_created_at_idx`(`created_at`), INDEX `website_share_id_idx`(`share_id`), @@ -82,7 +80,6 @@ CREATE TABLE `team` ( `access_code` VARCHAR(50) NULL, `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), `updated_at` TIMESTAMP(0) NULL, - `deleted_at` TIMESTAMP(0) NULL, UNIQUE INDEX `team_team_id_key`(`team_id`), UNIQUE INDEX `team_access_code_key`(`access_code`), @@ -99,7 +96,6 @@ CREATE TABLE `team_user` ( `role` VARCHAR(50) NOT NULL, `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), `updated_at` TIMESTAMP(0) NULL, - `deleted_at` TIMESTAMP(0) NULL, UNIQUE INDEX `team_user_team_user_id_key`(`team_user_id`), INDEX `team_user_team_id_idx`(`team_id`), @@ -107,5 +103,17 @@ CREATE TABLE `team_user` ( PRIMARY KEY (`team_user_id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; --- AddSystemUser -INSERT INTO `user` (user_id, username, role, password) VALUES ('41e2b680-648e-4b09-bcd7-3e2b10c06264' , 'admin', 'admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa'); \ No newline at end of file +-- CreateTable +CREATE TABLE `team_website` ( + `team_website_id` VARCHAR(36) NOT NULL, + `team_id` VARCHAR(36) NOT NULL, + `user_id` VARCHAR(36) NOT NULL, + `website_id` VARCHAR(36) NOT NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + + UNIQUE INDEX `team_website_team_website_id_key`(`team_website_id`), + INDEX `team_website_team_id_idx`(`team_id`), + INDEX `team_website_user_id_idx`(`user_id`), + INDEX `team_website_website_id_idx`(`website_id`), + PRIMARY KEY (`team_website_id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;