From 6f0e934573b3913c3cd5d015f096fc82da8fa22b Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Sun, 21 Jun 2026 04:38:47 -0500 Subject: [PATCH] fix(stats): make unique users migration idempotent --- .github/workflows/deploy.yml | 2 +- packages/stats/core/package.json | 1 + packages/stats/core/src/athena.ts | 2 +- packages/stats/core/src/database.ts | 4 +-- .../stats/core/src/ensure-unique-users.ts | 26 +++++++++++++++++++ 5 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 packages/stats/core/src/ensure-unique-users.ts diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2c326bb6f..22342a0ee 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -47,7 +47,7 @@ jobs: VITE_SENTRY_DSN: ${{ vars.WEB_SENTRY_DSN }} VITE_SENTRY_RELEASE: web@${{ github.sha }} - - run: bun sst shell --stage=${{ github.ref_name }} -- bun run --cwd packages/stats/core db:migrate + - run: bun sst shell --stage=${{ github.ref_name }} -- bun run --cwd packages/stats/core db:ensure-unique-users env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} PLANETSCALE_SERVICE_TOKEN_NAME: ${{ secrets.PLANETSCALE_SERVICE_TOKEN_NAME }} diff --git a/packages/stats/core/package.json b/packages/stats/core/package.json index c54cb7434..38379bc2e 100644 --- a/packages/stats/core/package.json +++ b/packages/stats/core/package.json @@ -17,6 +17,7 @@ }, "scripts": { "db:generate": "drizzle-kit generate --config=drizzle.config.ts", + "db:ensure-unique-users": "bun src/ensure-unique-users.ts", "db:migrate": "bun src/migrate.ts", "db:push": "drizzle-kit push --config=drizzle.config.ts", "db:studio": "drizzle-kit studio --config=drizzle.config.ts", diff --git a/packages/stats/core/src/athena.ts b/packages/stats/core/src/athena.ts index 54037002f..a2be44ebb 100644 --- a/packages/stats/core/src/athena.ts +++ b/packages/stats/core/src/athena.ts @@ -17,7 +17,7 @@ export type AthenaData = Record export class AthenaQueryError extends Schema.TaggedErrorClass()("AthenaQueryError", { message: Schema.String, queryExecutionId: Schema.optional(Schema.String), - cause: Schema.optional(Schema.Defect()), + cause: Schema.optional(Schema.Defect), }) {} export class AthenaQueryTimeoutError extends Schema.TaggedErrorClass()( diff --git a/packages/stats/core/src/database.ts b/packages/stats/core/src/database.ts index 9edb717bc..d265f82bf 100644 --- a/packages/stats/core/src/database.ts +++ b/packages/stats/core/src/database.ts @@ -45,14 +45,14 @@ export class DrizzleClient extends Context.Service()("@o } export class DatabaseError extends Schema.TaggedErrorClass()("DatabaseError", { - cause: Schema.Defect(), + cause: Schema.Defect, }) {} export const catchDbError = Effect.mapError((cause) => DatabaseError.make({ cause })) export class MigrationError extends Schema.TaggedErrorClass()("MigrationError", { message: Schema.String, - cause: Schema.optional(Schema.Defect()), + cause: Schema.optional(Schema.Defect), }) {} export const migrate = Effect.fn("Database.migrate")(function* () { diff --git a/packages/stats/core/src/ensure-unique-users.ts b/packages/stats/core/src/ensure-unique-users.ts new file mode 100644 index 000000000..af610cfb7 --- /dev/null +++ b/packages/stats/core/src/ensure-unique-users.ts @@ -0,0 +1,26 @@ +import { Client } from "@planetscale/database" +import { Resource } from "sst/resource" + +const tables = ["geo_stat", "model_stat", "provider_stat"] as const + +const client = new Client({ url: Resource.StatsDatabase.url }) + +await tables.reduce( + (promise, table) => promise.then(() => ensureUniqueUsersColumn(table)), + Promise.resolve(), +) + +async function ensureUniqueUsersColumn(table: (typeof tables)[number]) { + const result = await client.execute<{ column_name: string }>( + "SELECT column_name FROM information_schema.columns WHERE table_schema = database() AND table_name = ? AND column_name = 'unique_users'", + [table], + ) + + if (result.rows.length > 0) { + console.log(`unique_users column already exists on ${table}`) + return + } + + await client.execute(`ALTER TABLE \`${table}\` ADD \`unique_users\` bigint NOT NULL DEFAULT 0`) + console.log(`added unique_users column to ${table}`) +}