|
1 | 1 | import { spawnSync } from 'node:child_process' |
2 | | -import { mkdtemp, rm, writeFile } from 'node:fs/promises' |
| 2 | +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' |
3 | 3 | import { tmpdir } from 'node:os' |
4 | 4 | import { join } from 'node:path' |
| 5 | +import { prepareForcedPush } from '@sim/db/scripts/prepare-push' |
5 | 6 | import { generateId } from '@sim/utils/id' |
6 | 7 | import postgres, { type Sql } from 'postgres' |
7 | 8 | import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' |
@@ -54,7 +55,7 @@ describe.skipIf(!databaseUrl)('patched Drizzle push against PostgreSQL', () => { |
54 | 55 | async function schema(source: string) { |
55 | 56 | await writeFile( |
56 | 57 | join(directory, 'schema.ts'), |
57 | | - `import { pgTable, pgSchema, pgEnum, text, integer, boolean, check } from ${JSON.stringify(import.meta.resolve('drizzle-orm/pg-core'))} |
| 58 | + `import { pgTable, pgSchema, pgEnum, text, integer, bigint, boolean, check } from ${JSON.stringify(import.meta.resolve('drizzle-orm/pg-core'))} |
58 | 59 | import { sql } from ${JSON.stringify(import.meta.resolve('drizzle-orm'))} |
59 | 60 | ${source}` |
60 | 61 | ) |
@@ -90,6 +91,58 @@ ${source}` |
90 | 91 | })`) |
91 | 92 | } |
92 | 93 |
|
| 94 | + it('retires the legacy size bridge without losing bigint or unbackfilled values', async () => { |
| 95 | + await sql`CREATE TABLE workspace_files (id text PRIMARY KEY, size integer NOT NULL, size_bytes bigint)` |
| 96 | + await sql`INSERT INTO workspace_files VALUES ('legacy', 123, NULL), ('large', 2147483647, 5000000000)` |
| 97 | + await sql.unsafe( |
| 98 | + await readFile( |
| 99 | + new URL('../migrations/0308_workspace_file_size_cutover.sql', import.meta.url), |
| 100 | + 'utf8' |
| 101 | + ) |
| 102 | + ) |
| 103 | + await prepareForcedPush(sql) |
| 104 | + await prepareForcedPush(sql) |
| 105 | + await schema(`export const files = pgTable('workspace_files', { |
| 106 | + id: text('id').primaryKey(), sizeBytes: bigint('size_bytes', { mode: 'number' }), |
| 107 | + })`) |
| 108 | + const result = push() |
| 109 | + expect(result.status, result.stdout + result.stderr).toBe(0) |
| 110 | + expect(await sql`SELECT id, size_bytes::text FROM workspace_files ORDER BY id`).toEqual([ |
| 111 | + { id: 'large', size_bytes: '5000000000' }, |
| 112 | + { id: 'legacy', size_bytes: '123' }, |
| 113 | + ]) |
| 114 | + expect( |
| 115 | + await sql`SELECT to_regprocedure('sync_workspace_file_size_columns()') AS bridge` |
| 116 | + ).toEqual([{ bridge: null }]) |
| 117 | + }, 30_000) |
| 118 | + |
| 119 | + it('rolls back preparation instead of cascading unknown dependencies', async () => { |
| 120 | + await sql`CREATE TABLE workspace_files (id text PRIMARY KEY, size integer NOT NULL, size_bytes bigint)` |
| 121 | + await sql`INSERT INTO workspace_files VALUES ('legacy', 123, NULL)` |
| 122 | + await sql.unsafe( |
| 123 | + await readFile( |
| 124 | + new URL('../migrations/0308_workspace_file_size_cutover.sql', import.meta.url), |
| 125 | + 'utf8' |
| 126 | + ) |
| 127 | + ) |
| 128 | + await sql`CREATE VIEW retained_sizes AS SELECT size FROM workspace_files` |
| 129 | + await expect(prepareForcedPush(sql)).rejects.toThrow('depend') |
| 130 | + expect(await sql`SELECT size, size_bytes FROM workspace_files`).toEqual([ |
| 131 | + { size: 123, size_bytes: null }, |
| 132 | + ]) |
| 133 | + expect( |
| 134 | + await sql`SELECT tgname FROM pg_trigger WHERE tgrelid = 'workspace_files'::regclass AND NOT tgisinternal` |
| 135 | + ).toEqual([{ tgname: 'workspace_files_sync_size_columns' }]) |
| 136 | + }) |
| 137 | + |
| 138 | + it('prepares both fresh databases and legacy schemas without the new column', async () => { |
| 139 | + await prepareForcedPush(sql) |
| 140 | + await sql`CREATE TABLE workspace_files (id text PRIMARY KEY, size integer NOT NULL)` |
| 141 | + await sql`INSERT INTO workspace_files VALUES ('legacy', 456)` |
| 142 | + await prepareForcedPush(sql) |
| 143 | + expect(await sql`SELECT * FROM workspace_files`).toEqual([{ id: 'legacy', size_bytes: '456' }]) |
| 144 | + }) |
| 145 | + |
93 | 146 | it('initializes a fresh database', async () => { |
94 | 147 | await schema(`export const records = pgTable('records', { |
95 | 148 | id: text('id').primaryKey(), enabled: boolean('enabled').notNull().default(false), |
|
0 commit comments