@@ -6,6 +6,7 @@ import { assertEquals } from "@std/assert/equals";
66import { ConnectionManager } from "../sync/connection-manager.ts" ;
77import { assertArrayIncludes } from "@std/assert" ;
88import { PgIdentifier } from "@query-doctor/core" ;
9+ import { type Op } from "jsondiffpatch/formatters/jsonpatch" ;
910
1011const TEST_TARGET_CONTAINER_NAME = "postgres:17" ;
1112const TEST_TARGET_CONTAINER_TIMESCALEDB_NAME =
@@ -423,3 +424,95 @@ Deno.test({
423424 }
424425 } ,
425426} ) ;
427+
428+ Deno . test ( {
429+ name : "schema loader detects changes after database modification" ,
430+ sanitizeOps : false ,
431+ sanitizeResources : false ,
432+ fn : async ( ) => {
433+ const [ sourceDb , targetDb ] = await Promise . all ( [
434+ new PostgreSqlContainer ( "postgres:17" )
435+ . withCopyContentToContainer ( [
436+ {
437+ content : `
438+ create extension pg_stat_statements;
439+ create table testing(a int, b text);
440+ insert into testing values (1, 'test');
441+ create index "testing_b_idx" on testing(b);
442+ select * from testing where a = 1;
443+ ` ,
444+ target : "/docker-entrypoint-initdb.d/init.sql" ,
445+ } ,
446+ ] )
447+ . withCommand ( [ "-c" , "shared_preload_libraries=pg_stat_statements" ] )
448+ . start ( ) ,
449+ testSpawnTarget ( ) ,
450+ ] ) ;
451+
452+ try {
453+ const target = Connectable . fromString ( targetDb . getConnectionUri ( ) ) ;
454+ const source = Connectable . fromString ( sourceDb . getConnectionUri ( ) ) ;
455+
456+ const manager = ConnectionManager . forLocalDatabase ( ) ;
457+ await using remote = new Remote ( target , manager ) ;
458+
459+ const sourcePg = postgres ( source . toString ( ) ) ;
460+
461+ await remote . syncFrom ( source ) ;
462+ await remote . optimizer . finish ;
463+
464+ const initialStatus = await remote . getStatus ( ) ;
465+ const initialDiffsResult = initialStatus . diffs ;
466+ assertEquals (
467+ initialDiffsResult . status ,
468+ "fulfilled" ,
469+ "Schema poll should succeed" ,
470+ ) ;
471+ const initialDiffs = initialDiffsResult . status === "fulfilled"
472+ ? initialDiffsResult . value
473+ : [ ] ;
474+ assertEquals (
475+ initialDiffs . length ,
476+ 0 ,
477+ "Should have no diffs initially after sync" ,
478+ ) ;
479+
480+ await sourcePg . unsafe ( `
481+ alter table testing add column c int;
482+ create index "testing_c_idx" on testing(c);
483+ ` ) ;
484+
485+ const statusAfterChange = await remote . getStatus ( ) ;
486+ const diffsResult = statusAfterChange . diffs ;
487+
488+ assertEquals (
489+ diffsResult . status ,
490+ "fulfilled" ,
491+ "Schema poll should succeed" ,
492+ ) ;
493+ const diffs = diffsResult . status === "fulfilled"
494+ ? diffsResult . value
495+ : [ ] ;
496+
497+ assertEquals (
498+ diffs . length ,
499+ 2 ,
500+ "Should detect 2 schema changes (added column and index)" ,
501+ ) ;
502+
503+ const addedColumnDiff = diffs . find ( ( diff : Op ) =>
504+ typeof diff . path === "string" && diff . path . includes ( "columns" )
505+ ) ;
506+ assertEquals ( addedColumnDiff ?. op , "add" , "Should detect column addition" ) ;
507+
508+ const addedIndexDiff = diffs . find ( ( diff : Op ) =>
509+ typeof diff . path === "string" && diff . path . includes ( "indexes" )
510+ ) ;
511+ assertEquals ( addedIndexDiff ?. op , "add" , "Should detect index addition" ) ;
512+
513+ await sourcePg . end ( ) ;
514+ } finally {
515+ await Promise . all ( [ sourceDb . stop ( ) , targetDb . stop ( ) ] ) ;
516+ }
517+ } ,
518+ } ) ;
0 commit comments