From da7f4cb2d0dec2a810e789ed53fceb77cb659a58 Mon Sep 17 00:00:00 2001 From: Francis Cao Date: Fri, 18 Jul 2025 10:26:24 -0700 Subject: [PATCH] create and apply mysql migrations --- .../migrations/11_add_segment/migration.sql | 14 ++++ .../12_update_report_parameter/migration.sql | 2 + .../migrations/13_add_revenue/migration.sql | 18 +++++ db/mysql/schema.prisma | 46 +++++++++++-- pnpm-lock.yaml | 68 +++++++++---------- .../populate-revenue-table.sql | 41 +++++++++++ 6 files changed, 151 insertions(+), 38 deletions(-) create mode 100644 db/mysql/migrations/11_add_segment/migration.sql create mode 100644 db/mysql/migrations/12_update_report_parameter/migration.sql create mode 100644 db/mysql/migrations/13_add_revenue/migration.sql create mode 100644 scripts/data-migrations/populate-revenue-table.sql diff --git a/db/mysql/migrations/11_add_segment/migration.sql b/db/mysql/migrations/11_add_segment/migration.sql new file mode 100644 index 00000000..c79e916d --- /dev/null +++ b/db/mysql/migrations/11_add_segment/migration.sql @@ -0,0 +1,14 @@ +-- CreateTable +CREATE TABLE `segment` ( + `segment_id` VARCHAR(36) NOT NULL, + `website_id` VARCHAR(36) NOT NULL, + `type` VARCHAR(200) NOT NULL, + `name` VARCHAR(200) NOT NULL, + `parameters` JSON NOT NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `updated_at` TIMESTAMP(0) NULL, + + UNIQUE INDEX `segment_segment_id_key`(`segment_id`), + INDEX `segment_website_id_idx`(`website_id`), + PRIMARY KEY (`segment_id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/db/mysql/migrations/12_update_report_parameter/migration.sql b/db/mysql/migrations/12_update_report_parameter/migration.sql new file mode 100644 index 00000000..f6a99c3f --- /dev/null +++ b/db/mysql/migrations/12_update_report_parameter/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `report` MODIFY `parameters` JSON NOT NULL; diff --git a/db/mysql/migrations/13_add_revenue/migration.sql b/db/mysql/migrations/13_add_revenue/migration.sql new file mode 100644 index 00000000..96115a33 --- /dev/null +++ b/db/mysql/migrations/13_add_revenue/migration.sql @@ -0,0 +1,18 @@ +-- CreateTable +CREATE TABLE `revenue` ( + `revenue_id` VARCHAR(36) NOT NULL, + `website_id` VARCHAR(36) NOT NULL, + `session_id` VARCHAR(36) NOT NULL, + `event_id` VARCHAR(36) NOT NULL, + `event_name` VARCHAR(50) NOT NULL, + `currency` VARCHAR(100) NOT NULL, + `revenue` DECIMAL(19, 4) NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + + UNIQUE INDEX `revenue_revenue_id_key`(`revenue_id`), + INDEX `revenue_website_id_idx`(`website_id`), + INDEX `revenue_session_id_idx`(`session_id`), + INDEX `revenue_website_id_created_at_idx`(`website_id`, `created_at`), + INDEX `revenue_website_id_session_id_created_at_idx`(`website_id`, `session_id`, `created_at`), + PRIMARY KEY (`revenue_id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/db/mysql/schema.prisma b/db/mysql/schema.prisma index 2a5513ab..67bd24d2 100644 --- a/db/mysql/schema.prisma +++ b/db/mysql/schema.prisma @@ -43,6 +43,7 @@ model Session { websiteEvent WebsiteEvent[] sessionData SessionData[] + revenue Revenue[] @@index([createdAt]) @@index([websiteId]) @@ -76,7 +77,9 @@ model Website { team Team? @relation(fields: [teamId], references: [id]) eventData EventData[] report Report[] + revenue Revenue[] sessionData SessionData[] + segment Segment[] @@index([userId]) @@index([teamId]) @@ -215,10 +218,10 @@ model Report { id String @id() @unique() @map("report_id") @db.VarChar(36) userId String @map("user_id") @db.VarChar(36) websiteId String @map("website_id") @db.VarChar(36) - type String @map("type") @db.VarChar(200) - name String @map("name") @db.VarChar(200) - description String @map("description") @db.VarChar(500) - parameters String @map("parameters") @db.VarChar(6000) + type String @db.VarChar(200) + name String @db.VarChar(200) + description String @db.VarChar(500) + parameters Json createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamp(0) @@ -231,3 +234,38 @@ model Report { @@index([name]) @@map("report") } + +model Segment { + id String @id() @unique() @map("segment_id") @db.VarChar(36) + websiteId String @map("website_id") @db.VarChar(36) + type String @db.VarChar(200) + name String @db.VarChar(200) + parameters Json + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) + updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamp(0) + + website Website @relation(fields: [websiteId], references: [id]) + + @@index([websiteId]) + @@map("segment") +} + +model Revenue { + id String @id() @unique() @map("revenue_id") @db.VarChar(36) + websiteId String @map("website_id") @db.VarChar(36) + sessionId String @map("session_id") @db.VarChar(36) + eventId String @map("event_id") @db.VarChar(36) + eventName String @map("event_name") @db.VarChar(50) + currency String @db.VarChar(100) + revenue Decimal? @db.Decimal(19, 4) + createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) + + website Website @relation(fields: [websiteId], references: [id]) + session Session @relation(fields: [sessionId], references: [id]) + + @@index([websiteId]) + @@index([sessionId]) + @@index([websiteId, createdAt]) + @@index([websiteId, sessionId, createdAt]) + @@map("revenue") +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a25a6594..bd8c46f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -248,7 +248,7 @@ importers: version: 14.2.30(eslint@8.57.1)(typescript@5.8.3) eslint-config-prettier: specifier: ^8.5.0 - version: 8.10.0(eslint@8.57.1) + version: 8.10.1(eslint@8.57.1) eslint-import-resolver-alias: specifier: ^1.1.2 version: 1.1.2(eslint-plugin-import@2.32.0) @@ -266,7 +266,7 @@ importers: version: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.16.4)(ts-node@10.9.2(@types/node@22.16.4)(typescript@5.8.3)))(typescript@5.8.3) eslint-plugin-prettier: specifier: ^4.0.0 - version: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8) + version: 4.2.3(eslint-config-prettier@8.10.1(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8) extract-react-intl-messages: specifier: ^4.1.1 version: 4.1.1(ts-jest@29.4.0(@babel/core@7.28.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.0))(esbuild@0.25.6)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.16.4)(ts-node@10.9.2(@types/node@22.16.4)(typescript@5.8.3)))(typescript@5.8.3)) @@ -1308,14 +1308,14 @@ packages: peerDependencies: '@dicebear/core': ^9.0.0 - '@emnapi/core@1.4.4': - resolution: {integrity: sha512-A9CnAbC6ARNMKcIcrQwq6HeHCjpcBZ5wSx4U01WXCqEKlrzB9F9315WDNHkrs2xbx7YjjSxbUYxuN6EQzpcY2g==} + '@emnapi/core@1.4.5': + resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} - '@emnapi/runtime@1.4.4': - resolution: {integrity: sha512-hHyapA4A3gPaDCNfiqyZUStTMqIkKRshqPIuDOXv1hcBnD4U3l8cP0T1HMCfGRxQ6V64TGCcoswChANyOAwbQg==} + '@emnapi/runtime@1.4.5': + resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} - '@emnapi/wasi-threads@1.0.3': - resolution: {integrity: sha512-8K5IFFsQqF9wQNJptGbS6FNKgUTsSRYnTqNCG1vPP8jFdjSv18n2mQfJpkt2Oibo9iBEzcDnDxNwKTzC7svlJw==} + '@emnapi/wasi-threads@1.0.4': + resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} '@esbuild/aix-ppc64@0.25.6': resolution: {integrity: sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==} @@ -3377,8 +3377,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.186: - resolution: {integrity: sha512-lur7L4BFklgepaJxj4DqPk7vKbTEl0pajNlg2QjE5shefmlmBLm2HvQ7PMf1R/GvlevT/581cop33/quQcfX3A==} + electron-to-chromium@1.5.187: + resolution: {integrity: sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -3477,8 +3477,8 @@ packages: typescript: optional: true - eslint-config-prettier@8.10.0: - resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + eslint-config-prettier@8.10.1: + resolution: {integrity: sha512-mXi3I2ghYZv02pKsUS5C2IRcYlOs3WFNYzYtLKX5s9mFju7BIAjxJqA4UG2qN2DAC0yUECdnfs5iGnyUdgOWzA==} hasBin: true peerDependencies: eslint: '>=7.0.0' @@ -3566,8 +3566,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - eslint-plugin-prettier@4.2.1: - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} + eslint-plugin-prettier@4.2.3: + resolution: {integrity: sha512-HOT5QrFj0ioo/USxnMvj9+E1kwJHg7HDpY9sf6mxNqisHbSegMnmdan/wfUtIPVZ8hwcfGGEJpyG1/TpeR5R1g==} engines: {node: '>=12.0.0'} peerDependencies: eslint: '>=7.28.0' @@ -4796,8 +4796,8 @@ packages: mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - mdn-data@2.22.1: - resolution: {integrity: sha512-u9Xnc9zLuF/CL2IHPow7HcXPpb8okQyzYpwL5wFsY//JRedSWYglYRg3PYWoQCu1zO+tBTmWOJN/iM0mPC5CRQ==} + mdn-data@2.23.0: + resolution: {integrity: sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==} memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} @@ -4914,8 +4914,8 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - napi-postinstall@0.3.0: - resolution: {integrity: sha512-M7NqKyhODKV1gRLdkwE7pDsZP2/SC2a2vHkOYh9MCpKMbWVfyVfUw5MaH83Fv6XMjxr5jryUp3IDDL9rlxsTeA==} + napi-postinstall@0.3.1: + resolution: {integrity: sha512-is9eGpjKpRg+Z7ECny6NSOekea7+1eTs9+jTt5jJx43ez0o1BYRUKEBIf+ZZn15oQf5wvPnRf0Uat6MAtvVz+A==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true @@ -7840,18 +7840,18 @@ snapshots: dependencies: '@dicebear/core': 9.2.3 - '@emnapi/core@1.4.4': + '@emnapi/core@1.4.5': dependencies: - '@emnapi/wasi-threads': 1.0.3 + '@emnapi/wasi-threads': 1.0.4 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.4': + '@emnapi/runtime@1.4.5': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.0.3': + '@emnapi/wasi-threads@1.0.4': dependencies: tslib: 2.8.1 optional: true @@ -8180,7 +8180,7 @@ snapshots: '@img/sharp-wasm32@0.34.3': dependencies: - '@emnapi/runtime': 1.4.4 + '@emnapi/runtime': 1.4.5 optional: true '@img/sharp-win32-arm64@0.34.3': @@ -8407,8 +8407,8 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.4.4 - '@emnapi/runtime': 1.4.4 + '@emnapi/core': 1.4.5 + '@emnapi/runtime': 1.4.5 '@tybys/wasm-util': 0.10.0 optional: true @@ -9458,7 +9458,7 @@ snapshots: browserslist@4.25.1: dependencies: caniuse-lite: 1.0.30001727 - electron-to-chromium: 1.5.186 + electron-to-chromium: 1.5.187 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) @@ -10119,7 +10119,7 @@ snapshots: dependencies: jake: 10.9.2 - electron-to-chromium@1.5.186: {} + electron-to-chromium@1.5.187: {} emittery@0.13.1: {} @@ -10311,7 +10311,7 @@ snapshots: - eslint-plugin-import-x - supports-color - eslint-config-prettier@8.10.0(eslint@8.57.1): + eslint-config-prettier@8.10.1(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -10423,13 +10423,13 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8): + eslint-plugin-prettier@4.2.3(eslint-config-prettier@8.10.1(eslint@8.57.1))(eslint@8.57.1)(prettier@2.8.8): dependencies: eslint: 8.57.1 prettier: 2.8.8 prettier-linter-helpers: 1.0.0 optionalDependencies: - eslint-config-prettier: 8.10.0(eslint@8.57.1) + eslint-config-prettier: 8.10.1(eslint@8.57.1) eslint-plugin-promise@6.6.0(eslint@8.57.1): dependencies: @@ -11914,7 +11914,7 @@ snapshots: mdn-data@2.12.2: optional: true - mdn-data@2.22.1: + mdn-data@2.23.0: optional: true memoize-one@5.2.1: {} @@ -12029,7 +12029,7 @@ snapshots: nanoid@3.3.11: {} - napi-postinstall@0.3.0: {} + napi-postinstall@0.3.1: {} natural-compare@1.4.0: {} @@ -13465,7 +13465,7 @@ snapshots: css-tree: 3.1.0 is-plain-object: 5.0.0 known-css-properties: 0.36.0 - mdn-data: 2.22.1 + mdn-data: 2.23.0 postcss-media-query-parser: 0.2.3 postcss-resolve-nested-selector: 0.1.6 postcss-selector-parser: 7.1.0 @@ -13789,7 +13789,7 @@ snapshots: unrs-resolver@1.11.1: dependencies: - napi-postinstall: 0.3.0 + napi-postinstall: 0.3.1 optionalDependencies: '@unrs/resolver-binding-android-arm-eabi': 1.11.1 '@unrs/resolver-binding-android-arm64': 1.11.1 diff --git a/scripts/data-migrations/populate-revenue-table.sql b/scripts/data-migrations/populate-revenue-table.sql new file mode 100644 index 00000000..9df75189 --- /dev/null +++ b/scripts/data-migrations/populate-revenue-table.sql @@ -0,0 +1,41 @@ +----------------------------------------------------- +-- PostgreSQL +----------------------------------------------------- +INSERT INTO "revenue" +SELECT gen_random_uuid() revenue_id, + ed.website_id, + we.session_id, + we.event_id, + we.event_name, + currency.string_value currency, + coalesce(ed.number_value, cast(ed.string_value as numeric(19,4))) revenue, + ed.created_at +FROM event_data ed +JOIN website_event we +ON we.event_id = ed.website_event_id +JOIN (SELECT website_event_id, string_value + FROM event_data + WHERE data_key ilike '%currency%') currency +ON currency.website_event_id = ed.website_event_id +WHERE ed.data_key ilike '%revenue%'; + +----------------------------------------------------- +-- MySQL +----------------------------------------------------- +INSERT INTO `revenue` +SELECT UUID() revenue_id, + ed.website_id, + we.session_id, + we.event_id, + we.event_name, + currency.string_value currency, + coalesce(ed.number_value, cast(ed.string_value as decimal(19,4))) revenue, + ed.created_at +FROM event_data ed +JOIN website_event we +ON we.event_id = ed.website_event_id +JOIN (SELECT website_event_id, string_value + FROM event_data + WHERE data_key like '%currency%') currency +ON currency.website_event_id = ed.website_event_id +WHERE ed.data_key like '%revenue%'; \ No newline at end of file