Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/remote/remote.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Deno.test({
);

const result = await remote.syncFrom(source);
await remote.optimizer.finish;
const optimizedQueries = remote.optimizer.getQueries();

const queries = optimizedQueries.map((f) => f.query);
Expand Down Expand Up @@ -129,6 +130,66 @@ Deno.test({
},
});

// Users who upgraded from Postgres 13/14 may have a leftover bit_xor aggregate.
// It became built-in in Postgres 15, but custom versions from older installs remain.
// This test ensures sync handles this gracefully.
Deno.test({
name: "syncs database with custom bit_xor aggregate",
sanitizeOps: false,
sanitizeResources: false,
fn: async () => {
const [sourceDb, targetDb] = await Promise.all([
new PostgreSqlContainer("postgres:17")
.withCopyContentToContainer([
{
content: `
create extension pg_stat_statements;
CREATE AGGREGATE public.bit_xor(v bigint) (
SFUNC = int8xor,
STYPE = bigint
);
create table testing(a bigint);
insert into testing values (1);
create index "testing_idx" on testing(a);
`,
target: "/docker-entrypoint-initdb.d/init.sql",
},
])
.withCommand(["-c", "shared_preload_libraries=pg_stat_statements"])
.start(),
testSpawnTarget(),
]);

try {
const target = Connectable.fromString(targetDb.getConnectionUri());
const source = Connectable.fromString(sourceDb.getConnectionUri());

const remote = new Remote(
target,
ConnectionManager.forLocalDatabase(),
);

const result = await remote.syncFrom(source);
await remote.optimizer.finish;

// Assert sync completed successfully (aggregate excluded gracefully)
assertOk(result.schema);

const tableNames = result.schema.value.tables.map((table) =>
table.tableName
);
assertArrayIncludes(tableNames, ["testing"]);

const indexNames = result.schema.value.indexes.map((index) =>
index.indexName
);
assertArrayIncludes(indexNames, ["testing_idx"]);
} finally {
await Promise.all([sourceDb.stop(), targetDb.stop()]);
}
},
});

Deno.test({
name: "raw timescaledb syncs correctly",
sanitizeOps: false,
Expand Down Expand Up @@ -243,6 +304,7 @@ Deno.test({
targetConn.withDatabaseName(PgIdentifier.fromString("optimizing_db")),
);
await remote.syncFrom(sourceConn);
await remote.optimizer.finish;
const queries = remote.optimizer.getQueries();
const queryStrings = queries.map((q) => q.query);

Expand Down
2 changes: 2 additions & 0 deletions src/sync/schema_dump.sql
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ all_functions as (
n.nspname not like 'pg_%'
AND n.nspname <> 'information_schema'
AND d.objid IS NULL
-- Exclude bit_xor aggregate as pg_get_functiondef doesn't work on it
AND NOT (pro.proname = 'bit_xor' AND pro.prokind = 'a')
ORDER BY
n.nspname, pro.proname, pg_get_function_identity_arguments(pro.oid)
),
Expand Down
Loading