mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
drop old platform ID column
This commit is contained in:
+4
-1
@@ -98,7 +98,10 @@ cached login.
|
|||||||
|
|
||||||
The account blob keeps `platform`/`platformId` as the account's **primary** identity
|
The account blob keeps `platform`/`platformId` as the account's **primary** identity
|
||||||
(the first one linked). It feeds the account DTO and a refreshed token's claims, and
|
(the first one linked). It feeds the account DTO and a refreshed token's claims, and
|
||||||
nothing authorizes off it.
|
nothing authorizes off it. It is no longer indexed: migration 0008 drops the
|
||||||
|
`account.platform_id` generated column that 0004 added, since leaving a queryable copy
|
||||||
|
of one identity per account invites exactly the picker/grant disagreement above. Look
|
||||||
|
identities up in `platform_account`.
|
||||||
|
|
||||||
## Signup caps
|
## Signup caps
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
-- Drop the `platform_id` generated column added by 0004. Nothing reads it any more:
|
||||||
|
-- 0007 moved every account ↔ identity link into `platform_account`, which is now the
|
||||||
|
-- one source of truth for the login picker and the `cached_login` grant. The column's
|
||||||
|
-- last reader was 0007's own backfill, which has already run.
|
||||||
|
--
|
||||||
|
-- Leaving it would leave a SECOND, stale answer to "which account does this identity
|
||||||
|
-- open?" — it only ever holds the account's primary identity, so an account reachable
|
||||||
|
-- from a PC and a headset appears here under one of them. That is exactly the split
|
||||||
|
-- that used to have the picker offer an account the grant then refused.
|
||||||
|
--
|
||||||
|
-- The underlying `platformId` in the JSON blob STAYS: it is the account's primary
|
||||||
|
-- identity, and feeds the account DTO and a refreshed token's claims. This drops the
|
||||||
|
-- generated column and its index only — a virtual column stores nothing, so no account
|
||||||
|
-- data is rewritten or lost. The index has to go first; SQLite refuses to drop an
|
||||||
|
-- indexed column. Kept in sync with SCHEMA_DDL in @repo/domain's accounts-db.ts.
|
||||||
|
--
|
||||||
|
-- Safe to run before or after the deploy that ships it: no worker queries this column,
|
||||||
|
-- so the currently-deployed code doesn't notice it go. (`PLATFORM_BACKFILL_SQL` in
|
||||||
|
-- src/platform-db.ts still names it in 0007's text — that statement has run and won't
|
||||||
|
-- run again; the exported copy selects the blob instead so tests keep working.)
|
||||||
|
|
||||||
|
DROP INDEX IF EXISTS idx_accounts_platform_id;
|
||||||
|
ALTER TABLE account DROP COLUMN platform_id;
|
||||||
@@ -39,22 +39,30 @@ export const PLATFORM_SCHEMA_DDL: string[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The one-time backfill 0007 runs after creating the table: every identity already
|
* The one-time backfill 0007 ran after creating the table: every identity already bound
|
||||||
* bound to an account becomes a link, so nobody loses their cached login at deploy.
|
* to an account became a link, so nobody lost their cached login at deploy. It has run;
|
||||||
* Exported so a test can run exactly the statement the migration does.
|
* this exists so a test can still exercise it, which is the only coverage that legacy
|
||||||
|
* blob-bound accounts get a link at all.
|
||||||
*
|
*
|
||||||
* `platform` is COALESCEd to 0 because nothing ever defaulted that field — an account
|
* `platform` is COALESCEd to 0 because nothing ever defaulted that field — an account
|
||||||
* can carry a platformId with no platform recorded, and back when Steam was the only
|
* can carry a platformId with no platform recorded, and back when Steam was the only
|
||||||
* verifiable platform an unset one *was* Steam.
|
* verifiable platform an unset one *was* Steam.
|
||||||
|
*
|
||||||
|
* NOT byte-identical to the migration any more, deliberately. 0007 selected the
|
||||||
|
* `account.platform_id` generated column; 0008 drops it, so that text is unrunnable
|
||||||
|
* against the head schema the tests build. This selects the blob directly instead —
|
||||||
|
* the same values, since the dropped column was DEFINED as
|
||||||
|
* `json_extract(data, '$.platformId')`. 0007 is left exactly as it ran on prod.
|
||||||
*/
|
*/
|
||||||
export const PLATFORM_BACKFILL_SQL = `INSERT OR IGNORE INTO platform_account (account_id, platform, platform_id, linked_at)
|
export const PLATFORM_BACKFILL_SQL = `INSERT OR IGNORE INTO platform_account (account_id, platform, platform_id, linked_at)
|
||||||
SELECT
|
SELECT
|
||||||
account_id,
|
account_id,
|
||||||
COALESCE(json_extract(data, '$.platform'), 0),
|
COALESCE(json_extract(data, '$.platform'), 0),
|
||||||
platform_id,
|
json_extract(data, '$.platformId'),
|
||||||
COALESCE(json_extract(data, '$.createdAt'), '1970-01-01T00:00:00Z')
|
COALESCE(json_extract(data, '$.createdAt'), '1970-01-01T00:00:00Z')
|
||||||
FROM account
|
FROM account
|
||||||
WHERE platform_id IS NOT NULL AND platform_id <> ''`
|
WHERE json_extract(data, '$.platformId') IS NOT NULL
|
||||||
|
AND json_extract(data, '$.platformId') <> ''`
|
||||||
|
|
||||||
/** One account ↔ platform identity link. */
|
/** One account ↔ platform identity link. */
|
||||||
export interface PlatformLink {
|
export interface PlatformLink {
|
||||||
|
|||||||
@@ -11,18 +11,20 @@
|
|||||||
* it from `@repo/domain` (each uses the subset it needs).
|
* it from `@repo/domain` (each uses the subset it needs).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Schema DDL (mirror of migrations 0001_accounts + 0002_avatar, sans seed INSERTs). */
|
/**
|
||||||
|
* Schema DDL — the head schema, i.e. what the table looks like after every migration
|
||||||
|
* (0001_accounts + 0002_avatar, sans seed INSERTs; 0004 added a `platform_id` generated
|
||||||
|
* column and 0008 dropped it again, so it appears here in neither form).
|
||||||
|
*/
|
||||||
export const SCHEMA_DDL: string[] = [
|
export const SCHEMA_DDL: string[] = [
|
||||||
`CREATE TABLE IF NOT EXISTS account (
|
`CREATE TABLE IF NOT EXISTS account (
|
||||||
data TEXT NOT NULL,
|
data TEXT NOT NULL,
|
||||||
avatar TEXT,
|
avatar TEXT,
|
||||||
account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.accountId')) VIRTUAL,
|
account_id INTEGER GENERATED ALWAYS AS (json_extract(data, '$.accountId')) VIRTUAL,
|
||||||
username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.username'))) VIRTUAL,
|
username_lower TEXT GENERATED ALWAYS AS (lower(json_extract(data, '$.username'))) VIRTUAL
|
||||||
platform_id TEXT GENERATED ALWAYS AS (json_extract(data, '$.platformId')) VIRTUAL
|
|
||||||
)`,
|
)`,
|
||||||
`CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_account_id ON account (account_id)`,
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_account_id ON account (account_id)`,
|
||||||
`CREATE INDEX IF NOT EXISTS idx_accounts_username_lower ON account (username_lower)`,
|
`CREATE INDEX IF NOT EXISTS idx_accounts_username_lower ON account (username_lower)`,
|
||||||
`CREATE INDEX IF NOT EXISTS idx_accounts_platform_id ON account (platform_id)`,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
/** Client-facing account shape (camelCase, exactly as the client's AccountDTO). */
|
/** Client-facing account shape (camelCase, exactly as the client's AccountDTO). */
|
||||||
@@ -225,8 +227,9 @@ export async function searchAccounts(
|
|||||||
*
|
*
|
||||||
* Reads `deviceId` straight out of the JSON blob, so this is a table scan — no
|
* Reads `deviceId` straight out of the JSON blob, so this is a table scan — no
|
||||||
* generated column, no migration. Fine at our account count and for the occasional
|
* generated column, no migration. Fine at our account count and for the occasional
|
||||||
* linkup lookup this exists for; if it ever gets hot, promote `deviceId` to an
|
* linkup lookup this exists for; if it ever gets hot, promote `deviceId` to an indexed
|
||||||
* indexed generated column the way `platformId` is (see the 0004 migration).
|
* generated column (migration 0004 did that for `platformId`, and 0008 undid it once
|
||||||
|
* nothing queried it — that pair is the recipe both ways).
|
||||||
*
|
*
|
||||||
* The device id is unverified client input, so treat a match as a *hint* (these
|
* The device id is unverified client input, so treat a match as a *hint* (these
|
||||||
* accounts share a device) and never as proof of identity.
|
* accounts share a device) and never as proof of identity.
|
||||||
|
|||||||
Reference in New Issue
Block a user