schema-apply.test.ts49 lines · main
1import { describe, expect, test } from 'bun:test';
2
3import { table, text, varchar } from '@briven/schema';
4
5import { renderChange, singlePkColumn } from './schema-apply.js';
6
7describe('schema-apply', () => {
8 const usersTable = table({
9 columns: {
10 id: varchar(26).primaryKey(),
11 email: varchar(255).notNull(),
12 },
13 });
14
15 const compositePkTable = table({
16 columns: {
17 tenant_id: varchar(26).primaryKey(),
18 user_id: varchar(26).primaryKey(),
19 role: text().notNull(),
20 },
21 });
22
23 test('singlePkColumn returns the PK name when exactly one column is PK', () => {
24 expect(singlePkColumn(usersTable)).toBe('id');
25 });
26
27 test('singlePkColumn returns null for composite PK', () => {
28 expect(singlePkColumn(compositePkTable)).toBeNull();
29 });
30
31 test('create_table emits ONLY the CREATE TABLE (no NOTIFY trigger — sprint S1.7)', () => {
32 const stmts = renderChange({ kind: 'create_table', table: 'users', def: usersTable });
33 expect(stmts.length).toBe(1);
34 expect(stmts[0]).toMatch(/^CREATE TABLE/);
35 // Realtime uses DOLT_HASHOF polling, not LISTEN/NOTIFY — no trigger emitted.
36 expect(stmts.join('\n')).not.toContain('CREATE TRIGGER');
37 expect(stmts.join('\n')).not.toContain('pg_notify');
38 });
39
40 test('drop_table still cleans up any pre-existing trigger + function + table', () => {
41 const stmts = renderChange({ kind: 'drop_table', table: 'users' });
42 expect(stmts.length).toBe(3);
43 // Idempotent cleanup of triggers left by projects deployed before S1.7.
44 // Order matters: trigger → function → table.
45 expect(stmts[0]).toMatch(/^DROP TRIGGER IF EXISTS _briven_notify_users/);
46 expect(stmts[1]).toMatch(/^DROP FUNCTION IF EXISTS _briven_notify_users_fn\(\) CASCADE/);
47 expect(stmts[2]).toMatch(/^DROP TABLE IF EXISTS "users" CASCADE/);
48 });
49});