feat(04-07): migrate list_items.rank to COLLATE utf8mb4_bin (LIST-03)
- Add varcharBin customType helper emitting varchar(255) COLLATE utf8mb4_bin - Replace listItems.rank varchar with varcharBin to carry explicit binary collation - Generate migration 0002_yielding_mattie_franklin.sql: ALTER TABLE list_items MODIFY COLUMN rank varchar(255) COLLATE utf8mb4_bin NOT NULL (additive, no DROP) - Apply migration via db:migrate (never db:push, per project memory constraint) - utf8mb4_bin ensures uppercase-prefixed ranks (e.g. Zz) sort before lowercase ranks (e.g. a0) in DB ORDER BY, matching JS string order — closes LIST-03 gap
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `list_items` MODIFY COLUMN `rank` varchar(255) COLLATE utf8mb4_bin NOT NULL;
|
||||||
@@ -10,8 +10,20 @@ import {
|
|||||||
boolean,
|
boolean,
|
||||||
index,
|
index,
|
||||||
unique,
|
unique,
|
||||||
|
customType,
|
||||||
} from 'drizzle-orm/mysql-core'
|
} from 'drizzle-orm/mysql-core'
|
||||||
|
|
||||||
|
// Custom varchar type with explicit binary collation.
|
||||||
|
// Drizzle 0.45.x does not expose a first-class collation option on varchar,
|
||||||
|
// so we use customType to emit `varchar(255) COLLATE utf8mb4_bin`.
|
||||||
|
// utf8mb4_bin is required for fractional-indexing rank keys: uppercase-prefixed
|
||||||
|
// ranks (e.g. 'Zz') must sort BEFORE lowercase ranks (e.g. 'a0') — matching JS
|
||||||
|
// string order — so that drag-to-top persists across a DB ORDER BY rank.
|
||||||
|
const varcharBin = (name: string) =>
|
||||||
|
customType<{ data: string; driverData: string }>({
|
||||||
|
dataType: () => 'varchar(255) COLLATE utf8mb4_bin',
|
||||||
|
})(name)
|
||||||
|
|
||||||
// ── Phase 4: List tables ───────────────────────────────────────────────────
|
// ── Phase 4: List tables ───────────────────────────────────────────────────
|
||||||
// Imported by test/setup.ts for afterEach cleanup — keep exports consistent.
|
// Imported by test/setup.ts for afterEach cleanup — keep exports consistent.
|
||||||
|
|
||||||
@@ -228,7 +240,7 @@ export const listItems = mysqlTable(
|
|||||||
.references(() => lists.id, { onDelete: 'cascade' }),
|
.references(() => lists.id, { onDelete: 'cascade' }),
|
||||||
text: varchar('text', { length: 500 }).notNull(),
|
text: varchar('text', { length: 500 }).notNull(),
|
||||||
checked: boolean('checked').default(false).notNull(),
|
checked: boolean('checked').default(false).notNull(),
|
||||||
rank: varchar('rank', { length: 255 }).notNull(), // fractional-indexing string (D-13)
|
rank: varcharBin('rank').notNull(), // fractional-indexing string (D-13) — COLLATE utf8mb4_bin
|
||||||
createdAt: timestamp('created_at').defaultNow().notNull(),
|
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||||
updatedAt: timestamp('updated_at').defaultNow().onUpdateNow(),
|
updatedAt: timestamp('updated_at').defaultNow().onUpdateNow(),
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user