lakesync 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter-types-DwsQGQS4.d.ts +94 -0
- package/dist/adapter.d.ts +23 -49
- package/dist/adapter.js +9 -4
- package/dist/analyst.js +1 -1
- package/dist/{base-poller-Bj9kX9dv.d.ts → base-poller-Y7ORYgUv.d.ts} +2 -0
- package/dist/catalogue.js +2 -2
- package/dist/{chunk-LDFFCG2K.js → chunk-4SG66H5K.js} +44 -31
- package/dist/chunk-4SG66H5K.js.map +1 -0
- package/dist/{chunk-LPWXOYNS.js → chunk-C4KD6YKP.js} +59 -43
- package/dist/chunk-C4KD6YKP.js.map +1 -0
- package/dist/{chunk-JI4C4R5H.js → chunk-FIIHPQMQ.js} +196 -118
- package/dist/chunk-FIIHPQMQ.js.map +1 -0
- package/dist/{chunk-TMLG32QV.js → chunk-U2NV4DUX.js} +2 -2
- package/dist/{chunk-QNITY4F6.js → chunk-XVP5DJJ7.js} +16 -13
- package/dist/{chunk-QNITY4F6.js.map → chunk-XVP5DJJ7.js.map} +1 -1
- package/dist/{chunk-KVSWLIJR.js → chunk-YHYBLU6W.js} +2 -2
- package/dist/{chunk-PYRS74YP.js → chunk-ZNY4DSFU.js} +16 -13
- package/dist/{chunk-PYRS74YP.js.map → chunk-ZNY4DSFU.js.map} +1 -1
- package/dist/{chunk-SSICS5KI.js → chunk-ZU7RC7CT.js} +2 -2
- package/dist/client.d.ts +28 -10
- package/dist/client.js +150 -29
- package/dist/client.js.map +1 -1
- package/dist/compactor.d.ts +1 -1
- package/dist/compactor.js +3 -3
- package/dist/connector-jira.d.ts +13 -3
- package/dist/connector-jira.js +6 -2
- package/dist/connector-salesforce.d.ts +13 -3
- package/dist/connector-salesforce.js +6 -2
- package/dist/{coordinator-NXy6tA0h.d.ts → coordinator-eGmZMnJ_.d.ts} +99 -16
- package/dist/create-poller-Cc2MGfhh.d.ts +55 -0
- package/dist/factory-DFfR-030.d.ts +33 -0
- package/dist/gateway-server.d.ts +398 -95
- package/dist/gateway-server.js +743 -56
- package/dist/gateway-server.js.map +1 -1
- package/dist/gateway.d.ts +14 -8
- package/dist/gateway.js +6 -5
- package/dist/index.d.ts +45 -73
- package/dist/index.js +5 -3
- package/dist/parquet.js +2 -2
- package/dist/proto.js +2 -2
- package/dist/react.d.ts +3 -3
- package/dist/{registry-BcspAtZI.d.ts → registry-Dd8JuW8T.d.ts} +1 -1
- package/dist/{request-handler-pUvL7ozF.d.ts → request-handler-B1I5xDOx.d.ts} +71 -27
- package/dist/{src-ROW4XLO7.js → src-WU7IBVC4.js} +6 -4
- package/dist/{types-BrcD1oJg.d.ts → types-D2C9jTbL.d.ts} +33 -23
- package/package.json +1 -1
- package/dist/auth-CAVutXzx.d.ts +0 -30
- package/dist/chunk-JI4C4R5H.js.map +0 -1
- package/dist/chunk-LDFFCG2K.js.map +0 -1
- package/dist/chunk-LPWXOYNS.js.map +0 -1
- package/dist/db-types-CfLMUBfW.d.ts +0 -29
- package/dist/src-B6NLV3FP.js +0 -27
- package/dist/src-ROW4XLO7.js.map +0 -1
- package/dist/src-ZRHKG42A.js +0 -25
- package/dist/src-ZRHKG42A.js.map +0 -1
- package/dist/types-DSC_EiwR.d.ts +0 -45
- /package/dist/{chunk-TMLG32QV.js.map → chunk-U2NV4DUX.js.map} +0 -0
- /package/dist/{chunk-KVSWLIJR.js.map → chunk-YHYBLU6W.js.map} +0 -0
- /package/dist/{chunk-SSICS5KI.js.map → chunk-ZU7RC7CT.js.map} +0 -0
- /package/dist/{src-B6NLV3FP.js.map → src-WU7IBVC4.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../adapter/src/db-types.ts","../../adapter/src/shared.ts","../../adapter/src/materialise.ts","../../adapter/src/bigquery.ts","../../adapter/src/composite.ts","../../adapter/src/mysql.ts","../../adapter/src/postgres.ts","../../adapter/src/factory.ts","../../adapter/src/fan-out.ts","../../adapter/src/lifecycle.ts","../../adapter/src/migrate.ts","../../adapter/src/minio.ts","../../adapter/src/query-fn.ts"],"sourcesContent":["export type { DatabaseAdapter, DatabaseAdapterConfig } from \"@lakesync/core\";\nexport { isDatabaseAdapter } from \"@lakesync/core\";\n\nimport type { TableSchema } from \"@lakesync/core\";\n\n/**\n * Map a LakeSync column type to a BigQuery column definition.\n */\nconst BIGQUERY_TYPE_MAP: Record<TableSchema[\"columns\"][number][\"type\"], string> = {\n\tstring: \"STRING\",\n\tnumber: \"FLOAT64\",\n\tboolean: \"BOOL\",\n\tjson: \"JSON\",\n\tnull: \"STRING\",\n};\n\nexport function lakeSyncTypeToBigQuery(type: TableSchema[\"columns\"][number][\"type\"]): string {\n\treturn BIGQUERY_TYPE_MAP[type];\n}\n","import { AdapterError, type ColumnDelta, Err, Ok, type Result } from \"@lakesync/core\";\n\n/**\n * Group raw delta rows by row_id, merge to latest state, and partition into upserts and deletes.\n */\nexport function groupAndMerge(\n\trows: Array<{ row_id: string; columns: string | ColumnDelta[]; op: string }>,\n): { upserts: Array<{ rowId: string; state: Record<string, unknown> }>; deleteIds: string[] } {\n\tconst byRowId = new Map<string, Array<{ columns: string | ColumnDelta[]; op: string }>>();\n\tfor (const row of rows) {\n\t\tlet arr = byRowId.get(row.row_id);\n\t\tif (!arr) {\n\t\t\tarr = [];\n\t\t\tbyRowId.set(row.row_id, arr);\n\t\t}\n\t\tarr.push(row);\n\t}\n\n\tconst upserts: Array<{ rowId: string; state: Record<string, unknown> }> = [];\n\tconst deleteIds: string[] = [];\n\n\tfor (const [rowId, group] of byRowId) {\n\t\tconst state = mergeLatestState(group);\n\t\tif (state !== null) {\n\t\t\tupserts.push({ rowId, state });\n\t\t} else {\n\t\t\tdeleteIds.push(rowId);\n\t\t}\n\t}\n\n\treturn { upserts, deleteIds };\n}\n\n/** Normalise a caught value into an Error or undefined. */\nexport function toCause(error: unknown): Error | undefined {\n\treturn error instanceof Error ? error : undefined;\n}\n\n/** Execute an async operation and wrap errors into an AdapterError Result. */\nexport async function wrapAsync<T>(\n\toperation: () => Promise<T>,\n\terrorMessage: string,\n): Promise<Result<T, AdapterError>> {\n\ttry {\n\t\tconst value = await operation();\n\t\treturn Ok(value);\n\t} catch (error) {\n\t\tif (error instanceof AdapterError) {\n\t\t\treturn Err(error);\n\t\t}\n\t\treturn Err(new AdapterError(errorMessage, toCause(error)));\n\t}\n}\n\n/**\n * Merge delta rows into final state using column-level LWW.\n * Shared by Postgres, MySQL, and BigQuery getLatestState implementations.\n * Rows must be sorted by HLC ascending.\n */\nexport function mergeLatestState(\n\trows: Array<{ columns: string | ColumnDelta[]; op: string }>,\n): Record<string, unknown> | null {\n\tif (rows.length === 0) return null;\n\n\tconst lastRow = rows[rows.length - 1]!;\n\tif (lastRow.op === \"DELETE\") return null;\n\n\tconst state: Record<string, unknown> = {};\n\n\tfor (const row of rows) {\n\t\tif (row.op === \"DELETE\") {\n\t\t\tfor (const key of Object.keys(state)) {\n\t\t\t\tdelete state[key];\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst columns: ColumnDelta[] =\n\t\t\ttypeof row.columns === \"string\" ? JSON.parse(row.columns) : row.columns;\n\n\t\tfor (const col of columns) {\n\t\t\tstate[col.column] = col.value;\n\t\t}\n\t}\n\n\treturn state;\n}\n","export type { Materialisable } from \"@lakesync/core\";\nexport { isMaterialisable } from \"@lakesync/core\";\n\nimport type { ColumnDelta } from \"@lakesync/core\";\nimport {\n\ttype AdapterError,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport { groupAndMerge, wrapAsync } from \"./shared\";\n\n/**\n * Resolve the primary key columns for a table schema.\n * Defaults to `[\"row_id\"]` when not explicitly set.\n */\nexport function resolvePrimaryKey(schema: TableSchema): string[] {\n\treturn schema.primaryKey ?? [\"row_id\"];\n}\n\n/**\n * Resolve the conflict columns used for upsert ON CONFLICT targeting.\n * When `externalIdColumn` is set, upserts resolve on that column instead of the PK.\n */\nexport function resolveConflictColumns(schema: TableSchema): string[] {\n\treturn schema.externalIdColumn ? [schema.externalIdColumn] : resolvePrimaryKey(schema);\n}\n\n/**\n * Whether tombstoned rows should be soft-deleted (default) or hard-deleted.\n */\nexport function isSoftDelete(schema: TableSchema): boolean {\n\treturn schema.softDelete !== false;\n}\n\n/**\n * Group deltas by their table name, collecting the set of affected row IDs per table.\n *\n * @param deltas - The deltas to group.\n * @returns A map from table name to the set of affected row IDs.\n */\nexport function groupDeltasByTable(deltas: ReadonlyArray<RowDelta>): Map<string, Set<string>> {\n\tconst result = new Map<string, Set<string>>();\n\tfor (const delta of deltas) {\n\t\tlet rowIds = result.get(delta.table);\n\t\tif (!rowIds) {\n\t\t\trowIds = new Set<string>();\n\t\t\tresult.set(delta.table, rowIds);\n\t\t}\n\t\trowIds.add(delta.rowId);\n\t}\n\treturn result;\n}\n\n/**\n * Build an index from source table name to schema.\n *\n * Keys are `schema.sourceTable ?? schema.table`, so deltas can be matched\n * by their `table` field to find the correct destination schema.\n *\n * @param schemas - The table schemas to index.\n * @returns A map from source table name to schema.\n */\nexport function buildSchemaIndex(schemas: ReadonlyArray<TableSchema>): Map<string, TableSchema> {\n\tconst index = new Map<string, TableSchema>();\n\tfor (const schema of schemas) {\n\t\tconst key = schema.sourceTable ?? schema.table;\n\t\tindex.set(key, schema);\n\t}\n\treturn index;\n}\n\n// ---------------------------------------------------------------------------\n// Shared materialise algorithm: SqlDialect + QueryExecutor + executeMaterialise\n// ---------------------------------------------------------------------------\n\n/** Minimal query interface for executing SQL against a database. */\nexport interface QueryExecutor {\n\tquery(sql: string, params: unknown[]): Promise<void>;\n\tqueryRows(\n\t\tsql: string,\n\t\tparams: unknown[],\n\t): Promise<Array<{ row_id: string; columns: string | ColumnDelta[]; op: string }>>;\n}\n\n/**\n * SQL dialect interface — encapsulates the syntactic differences between\n * Postgres, MySQL, and BigQuery for the materialise algorithm.\n */\nexport interface SqlDialect {\n\t/** Generate CREATE TABLE IF NOT EXISTS for the destination table. */\n\tcreateDestinationTable(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\tpk: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] };\n\n\t/** Generate a query to fetch delta history for a set of affected row IDs. */\n\tqueryDeltaHistory(sourceTable: string, rowIds: string[]): { sql: string; params: unknown[] };\n\n\t/** Generate an upsert statement for the merged row states. */\n\tbuildUpsert(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\tconflictCols: string[],\n\t\tsoftDelete: boolean,\n\t\tupserts: Array<{ rowId: string; state: Record<string, unknown> }>,\n\t): { sql: string; params: unknown[] };\n\n\t/** Generate a delete (hard or soft) statement for tombstoned row IDs. */\n\tbuildDelete(\n\t\tdest: string,\n\t\tdeleteIds: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] };\n}\n\n/**\n * Execute the shared materialise algorithm using the provided dialect and executor.\n *\n * Algorithm: group by table -> build schema index -> for each table:\n * create dest table -> query history -> merge -> upsert -> delete.\n *\n * @param executor - Executes SQL statements against the database.\n * @param dialect - Generates dialect-specific SQL.\n * @param deltas - The deltas that were just flushed.\n * @param schemas - Table schemas defining destination tables and column mappings.\n */\nexport async function executeMaterialise(\n\texecutor: QueryExecutor,\n\tdialect: SqlDialect,\n\tdeltas: RowDelta[],\n\tschemas: ReadonlyArray<TableSchema>,\n): Promise<Result<void, AdapterError>> {\n\tif (deltas.length === 0) {\n\t\treturn Ok(undefined);\n\t}\n\n\treturn wrapAsync(async () => {\n\t\tconst grouped = groupDeltasByTable(deltas);\n\t\tconst schemaIndex = buildSchemaIndex(schemas);\n\n\t\tfor (const [tableName, rowIds] of grouped) {\n\t\t\tconst schema = schemaIndex.get(tableName);\n\t\t\tif (!schema) continue;\n\n\t\t\tconst dest = schema.table;\n\t\t\tconst pk = resolvePrimaryKey(schema);\n\t\t\tconst conflictCols = resolveConflictColumns(schema);\n\t\t\tconst soft = isSoftDelete(schema);\n\n\t\t\t// 1. Create destination table\n\t\t\tconst createStmt = dialect.createDestinationTable(dest, schema, pk, soft);\n\t\t\tawait executor.query(createStmt.sql, createStmt.params);\n\n\t\t\t// 2. Query delta history for affected rows\n\t\t\tconst sourceTable = schema.sourceTable ?? schema.table;\n\t\t\tconst rowIdArray = [...rowIds];\n\t\t\tconst historyStmt = dialect.queryDeltaHistory(sourceTable, rowIdArray);\n\t\t\tconst rows = await executor.queryRows(historyStmt.sql, historyStmt.params);\n\n\t\t\t// 3. Merge to latest state\n\t\t\tconst { upserts, deleteIds } = groupAndMerge(rows);\n\n\t\t\t// 4. Upsert live rows\n\t\t\tif (upserts.length > 0) {\n\t\t\t\tconst upsertStmt = dialect.buildUpsert(dest, schema, conflictCols, soft, upserts);\n\t\t\t\tawait executor.query(upsertStmt.sql, upsertStmt.params);\n\t\t\t}\n\n\t\t\t// 5. Delete / soft-delete tombstoned rows\n\t\t\tif (deleteIds.length > 0) {\n\t\t\t\tconst deleteStmt = dialect.buildDelete(dest, deleteIds, soft);\n\t\t\t\tawait executor.query(deleteStmt.sql, deleteStmt.params);\n\t\t\t}\n\t\t}\n\t}, \"Failed to materialise deltas\");\n}\n","import { BigQuery } from \"@google-cloud/bigquery\";\nimport {\n\ttype AdapterError,\n\ttype ColumnDelta,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport type { DatabaseAdapter } from \"./db-types\";\nimport { lakeSyncTypeToBigQuery } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport { executeMaterialise, type QueryExecutor, type SqlDialect } from \"./materialise\";\nimport { mergeLatestState, wrapAsync } from \"./shared\";\n\n/**\n * Configuration for the BigQuery adapter.\n * Unlike SQL adapters, BigQuery is HTTP-based — no connection string needed.\n */\nexport interface BigQueryAdapterConfig {\n\t/** GCP project ID. */\n\tprojectId: string;\n\t/** BigQuery dataset name. */\n\tdataset: string;\n\t/** Path to a service account JSON key file. Falls back to ADC if omitted. */\n\tkeyFilename?: string;\n\t/** Dataset location (default: \"US\"). */\n\tlocation?: string;\n}\n\n/** Shape of a row returned from the lakesync_deltas table. */\ninterface BigQueryDeltaRow {\n\tdelta_id: string;\n\ttable: string;\n\trow_id: string;\n\tcolumns: string;\n\thlc: { value: string } | string | number;\n\tclient_id: string;\n\top: string;\n}\n\n/**\n * Convert a raw BigQuery row into a RowDelta.\n * BigQuery returns INT64 as `{ value: string }` objects to avoid precision loss.\n */\nfunction rowToRowDelta(row: BigQueryDeltaRow): RowDelta {\n\tconst columns: ColumnDelta[] =\n\t\ttypeof row.columns === \"string\" ? JSON.parse(row.columns) : row.columns;\n\n\t// BigQuery INT64 comes back as { value: \"123\" } to preserve precision\n\tconst hlcRaw = row.hlc;\n\tconst hlcString =\n\t\ttypeof hlcRaw === \"object\" && hlcRaw !== null && \"value\" in hlcRaw\n\t\t\t? hlcRaw.value\n\t\t\t: String(hlcRaw);\n\n\treturn {\n\t\tdeltaId: row.delta_id,\n\t\ttable: row.table,\n\t\trowId: row.row_id,\n\t\tcolumns,\n\t\thlc: BigInt(hlcString) as HLCTimestamp,\n\t\tclientId: row.client_id,\n\t\top: row.op as RowDelta[\"op\"],\n\t};\n}\n\n/**\n * BigQuery SQL dialect for the shared materialise algorithm.\n *\n * Uses `@name` named parameters, `MERGE` for upserts, `JSON` type,\n * `TIMESTAMP` types, and `CLUSTER BY` for table creation.\n *\n * BigQuery's parameterised query API uses named params in a flat object,\n * so this dialect encodes params as named keys and returns them as an\n * array of `[key, value]` pairs that the executor unpacks into a\n * `Record<string, unknown>`.\n */\nexport class BigQuerySqlDialect implements SqlDialect {\n\tconstructor(private readonly dataset: string) {}\n\n\tcreateDestinationTable(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\tpk: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] } {\n\t\tconst colDefs = schema.columns\n\t\t\t.map((c) => `${c.name} ${lakeSyncTypeToBigQuery(c.type)}`)\n\t\t\t.join(\", \");\n\t\tconst deletedAtCol = softDelete ? `,\\n\\tdeleted_at TIMESTAMP` : \"\";\n\n\t\treturn {\n\t\t\tsql: `CREATE TABLE IF NOT EXISTS \\`${this.dataset}.${dest}\\` (\n\trow_id STRING NOT NULL,\n\t${colDefs},\n\tprops JSON DEFAULT '{}'${deletedAtCol},\n\tsynced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP()\n)\nCLUSTER BY ${pk.map((c) => (c === \"row_id\" ? \"row_id\" : c)).join(\", \")}`,\n\t\t\tparams: [],\n\t\t};\n\t}\n\n\tqueryDeltaHistory(sourceTable: string, rowIds: string[]): { sql: string; params: unknown[] } {\n\t\treturn {\n\t\t\tsql: `SELECT row_id, columns, op FROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE \\`table\\` = @sourceTable AND row_id IN UNNEST(@rowIds)\nORDER BY hlc ASC`,\n\t\t\tparams: [\n\t\t\t\t[\"sourceTable\", sourceTable],\n\t\t\t\t[\"rowIds\", rowIds],\n\t\t\t],\n\t\t};\n\t}\n\n\tbuildUpsert(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\tconflictCols: string[],\n\t\tsoftDelete: boolean,\n\t\tupserts: Array<{ rowId: string; state: Record<string, unknown> }>,\n\t): { sql: string; params: unknown[] } {\n\t\tconst namedParams: Array<[string, unknown]> = [];\n\t\tconst selects: string[] = [];\n\n\t\tfor (let i = 0; i < upserts.length; i++) {\n\t\t\tconst u = upserts[i]!;\n\t\t\tnamedParams.push([`rid_${i}`, u.rowId]);\n\t\t\tfor (const col of schema.columns) {\n\t\t\t\tnamedParams.push([`c${schema.columns.indexOf(col)}_${i}`, u.state[col.name] ?? null]);\n\t\t\t}\n\n\t\t\tconst colSelects = schema.columns.map((col, ci) => `@c${ci}_${i} AS ${col.name}`).join(\", \");\n\t\t\tconst deletedAtSelect = softDelete ? \", CAST(NULL AS TIMESTAMP) AS deleted_at\" : \"\";\n\t\t\tselects.push(\n\t\t\t\t`SELECT @rid_${i} AS row_id, ${colSelects}${deletedAtSelect}, CURRENT_TIMESTAMP() AS synced_at`,\n\t\t\t);\n\t\t}\n\n\t\tconst mergeOn = conflictCols\n\t\t\t.map((c) => `t.${c === \"row_id\" ? \"row_id\" : c} = s.${c === \"row_id\" ? \"row_id\" : c}`)\n\t\t\t.join(\" AND \");\n\n\t\tconst updateSet = schema.columns.map((col) => `${col.name} = s.${col.name}`).join(\", \");\n\t\tconst softUpdateExtra = softDelete ? \", deleted_at = s.deleted_at\" : \"\";\n\n\t\tconst insertColsList = [\n\t\t\t\"row_id\",\n\t\t\t...schema.columns.map((c) => c.name),\n\t\t\t\"props\",\n\t\t\t...(softDelete ? [\"deleted_at\"] : []),\n\t\t\t\"synced_at\",\n\t\t].join(\", \");\n\t\tconst insertValsList = [\n\t\t\t\"s.row_id\",\n\t\t\t...schema.columns.map((c) => `s.${c.name}`),\n\t\t\t\"'{}'\",\n\t\t\t...(softDelete ? [\"s.deleted_at\"] : []),\n\t\t\t\"s.synced_at\",\n\t\t].join(\", \");\n\n\t\treturn {\n\t\t\tsql: `MERGE \\`${this.dataset}.${dest}\\` AS t\nUSING (${selects.join(\" UNION ALL \")}) AS s\nON ${mergeOn}\nWHEN MATCHED THEN UPDATE SET ${updateSet}${softUpdateExtra}, synced_at = s.synced_at\nWHEN NOT MATCHED THEN INSERT (${insertColsList})\nVALUES (${insertValsList})`,\n\t\t\tparams: namedParams,\n\t\t};\n\t}\n\n\tbuildDelete(\n\t\tdest: string,\n\t\tdeleteIds: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] } {\n\t\tif (softDelete) {\n\t\t\treturn {\n\t\t\t\tsql: `UPDATE \\`${this.dataset}.${dest}\\` SET deleted_at = CURRENT_TIMESTAMP(), synced_at = CURRENT_TIMESTAMP() WHERE row_id IN UNNEST(@rowIds)`,\n\t\t\t\tparams: [[\"rowIds\", deleteIds]],\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsql: `DELETE FROM \\`${this.dataset}.${dest}\\` WHERE row_id IN UNNEST(@rowIds)`,\n\t\t\tparams: [[\"rowIds\", deleteIds]],\n\t\t};\n\t}\n}\n\n/**\n * Create a QueryExecutor for BigQuery.\n *\n * BigQuery uses named parameters passed as a `Record<string, unknown>`.\n * The executor converts the dialect's params (either empty array for\n * no-param queries, or `[key, value]` tuples for named params) into\n * the correct format for the BigQuery client.\n */\nfunction createBigQueryExecutor(client: BigQuery, location: string): QueryExecutor {\n\tfunction toNamedParams(params: unknown[]): Record<string, unknown> | undefined {\n\t\tif (params.length === 0) return undefined;\n\t\t// Params are [key, value] tuples from the dialect\n\t\tconst result: Record<string, unknown> = {};\n\t\tfor (const entry of params) {\n\t\t\tconst [key, value] = entry as [string, unknown];\n\t\t\tresult[key] = value;\n\t\t}\n\t\treturn result;\n\t}\n\n\treturn {\n\t\tasync query(sql: string, params: unknown[]): Promise<void> {\n\t\t\tconst namedParams = toNamedParams(params);\n\t\t\tawait client.query({\n\t\t\t\tquery: sql,\n\t\t\t\tparams: namedParams,\n\t\t\t\tlocation,\n\t\t\t});\n\t\t},\n\t\tasync queryRows(sql: string, params: unknown[]) {\n\t\t\tconst namedParams = toNamedParams(params);\n\t\t\tconst [rows] = await client.query({\n\t\t\t\tquery: sql,\n\t\t\t\tparams: namedParams,\n\t\t\t\tlocation,\n\t\t\t});\n\t\t\treturn rows as Array<{\n\t\t\t\trow_id: string;\n\t\t\t\tcolumns: string | ColumnDelta[];\n\t\t\t\top: string;\n\t\t\t}>;\n\t\t},\n\t};\n}\n\n/**\n * BigQuery database adapter for LakeSync.\n *\n * Stores deltas in a `lakesync_deltas` table using standard SQL DML.\n * Idempotent inserts via MERGE statement. All public methods return\n * `Result` and never throw.\n *\n * **Note:** BigQuery DML is limited to 1,500 statements per table per day\n * on standard (non-partitioned) tables. Query latency is seconds, not\n * milliseconds — this adapter is designed for the analytics tier.\n */\nexport class BigQueryAdapter implements DatabaseAdapter, Materialisable {\n\t/** @internal */\n\treadonly client: BigQuery;\n\t/** @internal */\n\treadonly dataset: string;\n\t/** @internal */\n\treadonly location: string;\n\tprivate readonly dialect: BigQuerySqlDialect;\n\tprivate readonly executor: QueryExecutor;\n\n\tconstructor(config: BigQueryAdapterConfig) {\n\t\tthis.client = new BigQuery({\n\t\t\tprojectId: config.projectId,\n\t\t\tkeyFilename: config.keyFilename,\n\t\t});\n\t\tthis.dataset = config.dataset;\n\t\tthis.location = config.location ?? \"US\";\n\t\tthis.dialect = new BigQuerySqlDialect(this.dataset);\n\t\tthis.executor = createBigQueryExecutor(this.client, this.location);\n\t}\n\n\t/**\n\t * Insert deltas into the database in a single batch.\n\t * Idempotent via MERGE — existing deltaIds are silently skipped.\n\t */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\t// Build MERGE source from UNION ALL of parameterised SELECTs\n\t\t\tconst params: Record<string, string> = {};\n\t\t\tconst selects: string[] = [];\n\n\t\t\tfor (let i = 0; i < deltas.length; i++) {\n\t\t\t\tconst d = deltas[i]!;\n\t\t\t\tparams[`did_${i}`] = d.deltaId;\n\t\t\t\tparams[`tbl_${i}`] = d.table;\n\t\t\t\tparams[`rid_${i}`] = d.rowId;\n\t\t\t\tparams[`col_${i}`] = JSON.stringify(d.columns);\n\t\t\t\tparams[`hlc_${i}`] = d.hlc.toString();\n\t\t\t\tparams[`cid_${i}`] = d.clientId;\n\t\t\t\tparams[`op_${i}`] = d.op;\n\n\t\t\t\tselects.push(\n\t\t\t\t\t`SELECT @did_${i} AS delta_id, @tbl_${i} AS \\`table\\`, @rid_${i} AS row_id, @col_${i} AS columns, CAST(@hlc_${i} AS INT64) AS hlc, @cid_${i} AS client_id, @op_${i} AS op`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst sql = `MERGE \\`${this.dataset}.lakesync_deltas\\` AS target\nUSING (${selects.join(\" UNION ALL \")}) AS source\nON target.delta_id = source.delta_id\nWHEN NOT MATCHED THEN INSERT (delta_id, \\`table\\`, row_id, columns, hlc, client_id, op)\nVALUES (source.delta_id, source.\\`table\\`, source.row_id, source.columns, source.hlc, source.client_id, source.op)`;\n\n\t\t\tawait this.client.query({ query: sql, params, location: this.location });\n\t\t}, \"Failed to insert deltas\");\n\t}\n\n\t/**\n\t * Query deltas with HLC greater than the given timestamp, optionally filtered by table.\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tlet sql: string;\n\t\t\tconst params: Record<string, string | string[]> = {\n\t\t\t\tsinceHlc: hlc.toString(),\n\t\t\t};\n\n\t\t\tif (tables && tables.length > 0) {\n\t\t\t\tsql = `SELECT delta_id, \\`table\\`, row_id, columns, hlc, client_id, op\nFROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE hlc > CAST(@sinceHlc AS INT64) AND \\`table\\` IN UNNEST(@tables)\nORDER BY hlc ASC`;\n\t\t\t\tparams.tables = tables;\n\t\t\t} else {\n\t\t\t\tsql = `SELECT delta_id, \\`table\\`, row_id, columns, hlc, client_id, op\nFROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE hlc > CAST(@sinceHlc AS INT64)\nORDER BY hlc ASC`;\n\t\t\t}\n\n\t\t\tconst [rows] = await this.client.query({\n\t\t\t\tquery: sql,\n\t\t\t\tparams,\n\t\t\t\tlocation: this.location,\n\t\t\t});\n\t\t\treturn (rows as BigQueryDeltaRow[]).map(rowToRowDelta);\n\t\t}, \"Failed to query deltas\");\n\t}\n\n\t/**\n\t * Get the latest merged state for a specific row using column-level LWW.\n\t * Returns null if no deltas exist for this row.\n\t */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql = `SELECT columns, hlc, client_id, op\nFROM \\`${this.dataset}.lakesync_deltas\\`\nWHERE \\`table\\` = @tbl AND row_id = @rid\nORDER BY hlc ASC`;\n\n\t\t\tconst [rows] = await this.client.query({\n\t\t\t\tquery: sql,\n\t\t\t\tparams: { tbl: table, rid: rowId },\n\t\t\t\tlocation: this.location,\n\t\t\t});\n\t\t\treturn mergeLatestState(rows as BigQueryDeltaRow[]);\n\t\t}, `Failed to get latest state for ${table}:${rowId}`);\n\t}\n\n\t/**\n\t * Ensure the BigQuery dataset and lakesync_deltas table exist.\n\t * The `schema` parameter is accepted for interface compliance but the\n\t * internal table structure is fixed (deltas store column data as JSON).\n\t */\n\tasync ensureSchema(_schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\t// Create dataset if it doesn't exist\n\t\t\tconst datasetRef = this.client.dataset(this.dataset);\n\t\t\tconst [datasetExists] = await datasetRef.exists();\n\t\t\tif (!datasetExists) {\n\t\t\t\tawait this.client.createDataset(this.dataset, {\n\t\t\t\t\tlocation: this.location,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Create the deltas table\n\t\t\tawait this.client.query({\n\t\t\t\tquery: `CREATE TABLE IF NOT EXISTS \\`${this.dataset}.lakesync_deltas\\` (\n\tdelta_id STRING NOT NULL,\n\t\\`table\\` STRING NOT NULL,\n\trow_id STRING NOT NULL,\n\tcolumns JSON NOT NULL,\n\thlc INT64 NOT NULL,\n\tclient_id STRING NOT NULL,\n\top STRING NOT NULL\n)\nCLUSTER BY \\`table\\`, hlc`,\n\t\t\t\tlocation: this.location,\n\t\t\t});\n\t\t}, \"Failed to ensure schema\");\n\t}\n\n\t/**\n\t * Materialise deltas into destination tables.\n\t *\n\t * Delegates to the shared `executeMaterialise` algorithm with the\n\t * BigQuery SQL dialect.\n\t */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\treturn executeMaterialise(this.executor, this.dialect, deltas, schemas);\n\t}\n\n\t/**\n\t * No-op — BigQuery client is HTTP-based with no persistent connections.\n\t */\n\tasync close(): Promise<void> {\n\t\t// No-op: BigQuery uses HTTP requests, no connection pool to close\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\n\n/** A routing rule that maps specific tables to a database adapter. */\nexport interface CompositeRoute {\n\t/** Tables handled by this adapter */\n\ttables: string[];\n\t/** The adapter for these tables */\n\tadapter: DatabaseAdapter;\n}\n\n/** Configuration for CompositeAdapter routing. */\nexport interface CompositeAdapterConfig {\n\t/** Table-to-adapter routing rules */\n\troutes: CompositeRoute[];\n\t/** Fallback adapter for tables not matching any route */\n\tdefaultAdapter: DatabaseAdapter;\n}\n\n/**\n * Routes database operations to different adapters based on table name.\n * Implements DatabaseAdapter so it can be used as a drop-in replacement.\n */\nexport class CompositeAdapter implements DatabaseAdapter {\n\tprivate readonly routeMap: Map<string, DatabaseAdapter>;\n\tprivate readonly adapters: Set<DatabaseAdapter>;\n\tprivate readonly defaultAdapter: DatabaseAdapter;\n\n\tconstructor(config: CompositeAdapterConfig) {\n\t\tthis.routeMap = new Map();\n\t\tthis.adapters = new Set();\n\t\tthis.defaultAdapter = config.defaultAdapter;\n\t\tthis.adapters.add(config.defaultAdapter);\n\n\t\tfor (const route of config.routes) {\n\t\t\tthis.adapters.add(route.adapter);\n\t\t\tfor (const table of route.tables) {\n\t\t\t\tif (this.routeMap.has(table)) {\n\t\t\t\t\tthrow new Error(`Duplicate table route: \"${table}\" appears in multiple routes`);\n\t\t\t\t}\n\t\t\t\tthis.routeMap.set(table, route.adapter);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Insert deltas, routing each group to the correct adapter by table. */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tconst groups = new Map<DatabaseAdapter, RowDelta[]>();\n\n\t\tfor (const delta of deltas) {\n\t\t\tconst adapter = this.routeMap.get(delta.table) ?? this.defaultAdapter;\n\t\t\tlet group = groups.get(adapter);\n\t\t\tif (!group) {\n\t\t\t\tgroup = [];\n\t\t\t\tgroups.set(adapter, group);\n\t\t\t}\n\t\t\tgroup.push(delta);\n\t\t}\n\n\t\tfor (const [adapter, group] of groups) {\n\t\t\tconst result = await adapter.insertDeltas(group);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Query deltas since a given HLC, fanning out to relevant adapters and merging results. */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\tconst adapterSet = new Set<DatabaseAdapter>();\n\t\tconst adapterTables = new Map<DatabaseAdapter, string[]>();\n\n\t\tif (tables && tables.length > 0) {\n\t\t\tfor (const table of tables) {\n\t\t\t\tconst adapter = this.routeMap.get(table) ?? this.defaultAdapter;\n\t\t\t\tadapterSet.add(adapter);\n\t\t\t\tlet existing = adapterTables.get(adapter);\n\t\t\t\tif (!existing) {\n\t\t\t\t\texisting = [];\n\t\t\t\t\tadapterTables.set(adapter, existing);\n\t\t\t\t}\n\t\t\t\texisting.push(table);\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const adapter of this.adapters) {\n\t\t\t\tadapterSet.add(adapter);\n\t\t\t}\n\t\t}\n\n\t\tconst merged: RowDelta[] = [];\n\n\t\tfor (const adapter of adapterSet) {\n\t\t\tconst filterTables = adapterTables.get(adapter);\n\t\t\tconst result = await adapter.queryDeltasSince(hlc, filterTables);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tmerged.push(...result.value);\n\t\t}\n\n\t\tmerged.sort((a, b) => (a.hlc < b.hlc ? -1 : a.hlc > b.hlc ? 1 : 0));\n\n\t\treturn Ok(merged);\n\t}\n\n\t/** Get the latest state for a row, routing to the correct adapter. */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\tconst adapter = this.routeMap.get(table) ?? this.defaultAdapter;\n\t\treturn adapter.getLatestState(table, rowId);\n\t}\n\n\t/** Ensure schema exists, routing to the correct adapter for the table. */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\tconst adapter = this.routeMap.get(schema.table) ?? this.defaultAdapter;\n\t\treturn adapter.ensureSchema(schema);\n\t}\n\n\t/** Close all unique adapters (routes + default, deduplicated). */\n\tasync close(): Promise<void> {\n\t\tfor (const adapter of this.adapters) {\n\t\t\tawait adapter.close();\n\t\t}\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype ColumnDelta,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport mysql from \"mysql2/promise\";\nimport type { DatabaseAdapter, DatabaseAdapterConfig } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport { executeMaterialise, type QueryExecutor, type SqlDialect } from \"./materialise\";\nimport { mergeLatestState, wrapAsync } from \"./shared\";\n\n/**\n * Map a LakeSync column type to a MySQL column definition.\n */\nconst MYSQL_TYPE_MAP: Record<TableSchema[\"columns\"][number][\"type\"], string> = {\n\tstring: \"TEXT\",\n\tnumber: \"DOUBLE\",\n\tboolean: \"TINYINT(1)\",\n\tjson: \"JSON\",\n\tnull: \"TEXT\",\n};\n\nfunction lakeSyncTypeToMySQL(type: TableSchema[\"columns\"][number][\"type\"]): string {\n\treturn MYSQL_TYPE_MAP[type];\n}\n\n/**\n * MySQL SQL dialect for the shared materialise algorithm.\n *\n * Uses `?` positional parameters, `ON DUPLICATE KEY UPDATE`,\n * `JSON` type, and `TIMESTAMP` types.\n */\nexport class MySqlDialect implements SqlDialect {\n\tcreateDestinationTable(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\tpk: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] } {\n\t\tconst typedCols = schema.columns\n\t\t\t.map((col) => `\\`${col.name}\\` ${lakeSyncTypeToMySQL(col.type)}`)\n\t\t\t.join(\", \");\n\n\t\tconst pkConstraint = `PRIMARY KEY (${pk.map((c) => `\\`${c}\\``).join(\", \")})`;\n\t\tconst deletedAtCol = softDelete ? `, deleted_at TIMESTAMP NULL` : \"\";\n\t\tconst uniqueConstraint = schema.externalIdColumn\n\t\t\t? `, UNIQUE KEY (\\`${schema.externalIdColumn}\\`)`\n\t\t\t: \"\";\n\n\t\treturn {\n\t\t\tsql: `CREATE TABLE IF NOT EXISTS \\`${dest}\\` (row_id VARCHAR(255) NOT NULL, ${typedCols}, props JSON NOT NULL DEFAULT ('{}')${deletedAtCol}, synced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, ${pkConstraint}${uniqueConstraint})`,\n\t\t\tparams: [],\n\t\t};\n\t}\n\n\tqueryDeltaHistory(sourceTable: string, rowIds: string[]): { sql: string; params: unknown[] } {\n\t\tconst placeholders = rowIds.map(() => \"?\").join(\", \");\n\t\treturn {\n\t\t\tsql: `SELECT row_id, columns, op FROM lakesync_deltas WHERE \\`table\\` = ? AND row_id IN (${placeholders}) ORDER BY hlc ASC`,\n\t\t\tparams: [sourceTable, ...rowIds],\n\t\t};\n\t}\n\n\tbuildUpsert(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\t_conflictCols: string[],\n\t\tsoftDelete: boolean,\n\t\tupserts: Array<{ rowId: string; state: Record<string, unknown> }>,\n\t): { sql: string; params: unknown[] } {\n\t\tconst cols = schema.columns.map((c) => c.name);\n\n\t\tconst valuePlaceholders = softDelete\n\t\t\t? upserts.map(() => `(?, ${cols.map(() => \"?\").join(\", \")}, NULL, NOW())`).join(\", \")\n\t\t\t: upserts.map(() => `(?, ${cols.map(() => \"?\").join(\", \")}, NOW())`).join(\", \");\n\n\t\tconst values: unknown[] = [];\n\t\tfor (const { rowId, state } of upserts) {\n\t\t\tvalues.push(rowId);\n\t\t\tfor (const col of cols) {\n\t\t\t\tvalues.push(state[col] ?? null);\n\t\t\t}\n\t\t}\n\n\t\tconst updateCols = cols.map((c) => `\\`${c}\\` = VALUES(\\`${c}\\`)`).join(\", \");\n\t\tconst softUpdateExtra = softDelete ? \", deleted_at = NULL\" : \"\";\n\t\tconst colList = softDelete\n\t\t\t? `row_id, ${cols.map((c) => `\\`${c}\\``).join(\", \")}, deleted_at, synced_at`\n\t\t\t: `row_id, ${cols.map((c) => `\\`${c}\\``).join(\", \")}, synced_at`;\n\n\t\treturn {\n\t\t\tsql: `INSERT INTO \\`${dest}\\` (${colList}) VALUES ${valuePlaceholders} ON DUPLICATE KEY UPDATE ${updateCols}${softUpdateExtra}, synced_at = VALUES(synced_at)`,\n\t\t\tparams: values,\n\t\t};\n\t}\n\n\tbuildDelete(\n\t\tdest: string,\n\t\tdeleteIds: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] } {\n\t\tconst placeholders = deleteIds.map(() => \"?\").join(\", \");\n\t\tif (softDelete) {\n\t\t\treturn {\n\t\t\t\tsql: `UPDATE \\`${dest}\\` SET deleted_at = NOW(), synced_at = NOW() WHERE row_id IN (${placeholders})`,\n\t\t\t\tparams: deleteIds,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsql: `DELETE FROM \\`${dest}\\` WHERE row_id IN (${placeholders})`,\n\t\t\tparams: deleteIds,\n\t\t};\n\t}\n}\n\n/**\n * MySQL database adapter for LakeSync.\n *\n * Stores deltas in a `lakesync_deltas` table using INSERT IGNORE for\n * idempotent writes. All public methods return `Result` and never throw.\n * Uses mysql2/promise connection pool for async operations.\n */\nexport class MySQLAdapter implements DatabaseAdapter, Materialisable {\n\t/** @internal */\n\treadonly pool: mysql.Pool;\n\tprivate readonly dialect = new MySqlDialect();\n\n\tconstructor(config: DatabaseAdapterConfig) {\n\t\tthis.pool = mysql.createPool({\n\t\t\turi: config.connectionString,\n\t\t\tconnectionLimit: config.poolMax ?? 10,\n\t\t\tconnectTimeout: config.connectionTimeoutMs ?? 30_000,\n\t\t\tidleTimeout: config.idleTimeoutMs ?? 10_000,\n\t\t});\n\t}\n\n\tprivate get executor(): QueryExecutor {\n\t\tconst pool = this.pool;\n\t\treturn {\n\t\t\tasync query(sql: string, params: unknown[]): Promise<void> {\n\t\t\t\tawait pool.execute(sql, params);\n\t\t\t},\n\t\t\tasync queryRows(sql: string, params: unknown[]) {\n\t\t\t\tconst [rows] = await pool.execute(sql, params);\n\t\t\t\treturn rows as Array<{\n\t\t\t\t\trow_id: string;\n\t\t\t\t\tcolumns: string | ColumnDelta[];\n\t\t\t\t\top: string;\n\t\t\t\t}>;\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Insert deltas into the database in a single batch.\n\t * Uses INSERT IGNORE for idempotent writes — duplicate deltaIds are silently skipped.\n\t */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql = `INSERT IGNORE INTO lakesync_deltas (delta_id, \\`table\\`, row_id, columns, hlc, client_id, op) VALUES ${deltas.map(() => \"(?, ?, ?, ?, ?, ?, ?)\").join(\", \")}`;\n\n\t\t\tconst values: unknown[] = [];\n\t\t\tfor (const delta of deltas) {\n\t\t\t\tvalues.push(\n\t\t\t\t\tdelta.deltaId,\n\t\t\t\t\tdelta.table,\n\t\t\t\t\tdelta.rowId,\n\t\t\t\t\tJSON.stringify(delta.columns),\n\t\t\t\t\tdelta.hlc.toString(),\n\t\t\t\t\tdelta.clientId,\n\t\t\t\t\tdelta.op,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.pool.execute(sql, values);\n\t\t}, \"Failed to insert deltas\");\n\t}\n\n\t/**\n\t * Query deltas with HLC greater than the given timestamp.\n\t * Optionally filtered by table name(s).\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tlet sql =\n\t\t\t\t\"SELECT delta_id, `table`, row_id, columns, hlc, client_id, op FROM lakesync_deltas WHERE hlc > ?\";\n\t\t\tconst params: unknown[] = [hlc.toString()];\n\n\t\t\tif (tables && tables.length > 0) {\n\t\t\t\tsql += ` AND \\`table\\` IN (${tables.map(() => \"?\").join(\", \")})`;\n\t\t\t\tparams.push(...tables);\n\t\t\t}\n\n\t\t\tsql += \" ORDER BY hlc ASC\";\n\n\t\t\tconst [rows] = await this.pool.execute(sql, params);\n\t\t\treturn (rows as MySQLDeltaRow[]).map(rowToDelta);\n\t\t}, \"Failed to query deltas\");\n\t}\n\n\t/**\n\t * Get the latest merged state for a specific row using column-level LWW.\n\t * Returns null if no deltas exist or if the row is tombstoned by DELETE.\n\t */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql =\n\t\t\t\t\"SELECT columns, hlc, client_id, op FROM lakesync_deltas WHERE `table` = ? AND row_id = ? ORDER BY hlc ASC\";\n\t\t\tconst [rows] = await this.pool.execute(sql, [table, rowId]);\n\t\t\treturn mergeLatestState(rows as MySQLDeltaRow[]);\n\t\t}, `Failed to get latest state for ${table}:${rowId}`);\n\t}\n\n\t/**\n\t * Ensure the database schema exists. Creates the lakesync_deltas table\n\t * and a user table matching the given TableSchema definition.\n\t */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\t// Create the deltas table\n\t\t\tawait this.pool.execute(`\n\t\t\t\tCREATE TABLE IF NOT EXISTS lakesync_deltas (\n\t\t\t\t\tdelta_id VARCHAR(255) PRIMARY KEY,\n\t\t\t\t\t\\`table\\` VARCHAR(255) NOT NULL,\n\t\t\t\t\trow_id VARCHAR(255) NOT NULL,\n\t\t\t\t\tcolumns JSON NOT NULL,\n\t\t\t\t\thlc BIGINT NOT NULL,\n\t\t\t\t\tclient_id VARCHAR(255) NOT NULL,\n\t\t\t\t\top VARCHAR(50) NOT NULL DEFAULT 'upsert',\n\t\t\t\t\tINDEX idx_hlc (hlc),\n\t\t\t\t\tINDEX idx_table_row (\\`table\\`, row_id)\n\t\t\t\t)\n\t\t\t`);\n\n\t\t\t// Create the user-defined table\n\t\t\tconst columnDefs = schema.columns\n\t\t\t\t.map((col) => `\\`${col.name}\\` ${lakeSyncTypeToMySQL(col.type)}`)\n\t\t\t\t.join(\", \");\n\n\t\t\tawait this.pool.execute(\n\t\t\t\t`CREATE TABLE IF NOT EXISTS \\`${schema.table}\\` (row_id VARCHAR(255) PRIMARY KEY, ${columnDefs}, props JSON NOT NULL DEFAULT ('{}'), synced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)`,\n\t\t\t);\n\t\t}, `Failed to ensure schema for table ${schema.table}`);\n\t}\n\n\t/**\n\t * Materialise deltas into destination tables.\n\t *\n\t * Delegates to the shared `executeMaterialise` algorithm with the\n\t * MySQL SQL dialect.\n\t */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\treturn executeMaterialise(this.executor, this.dialect, deltas, schemas);\n\t}\n\n\t/** Close the database connection pool and release resources. */\n\tasync close(): Promise<void> {\n\t\tawait this.pool.end();\n\t}\n}\n\n/** Shape of a row returned from the lakesync_deltas table. */\ninterface MySQLDeltaRow {\n\tdelta_id: string;\n\ttable: string;\n\trow_id: string;\n\tcolumns: string;\n\thlc: string | bigint;\n\tclient_id: string;\n\top: string;\n}\n\n/**\n * Convert a raw MySQL row into a RowDelta.\n * Handles both string and bigint HLC representations.\n */\nfunction rowToDelta(row: MySQLDeltaRow): RowDelta {\n\treturn {\n\t\tdeltaId: row.delta_id,\n\t\ttable: row.table,\n\t\trowId: row.row_id,\n\t\tcolumns: typeof row.columns === \"string\" ? JSON.parse(row.columns) : row.columns,\n\t\thlc: BigInt(row.hlc) as HLCTimestamp,\n\t\tclientId: row.client_id,\n\t\top: row.op as RowDelta[\"op\"],\n\t};\n}\n","import {\n\ttype AdapterError,\n\ttype ColumnDelta,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\nimport { Pool, type PoolConfig } from \"pg\";\nimport type { DatabaseAdapter, DatabaseAdapterConfig } from \"./db-types\";\nimport type { Materialisable } from \"./materialise\";\nimport { executeMaterialise, type QueryExecutor, type SqlDialect } from \"./materialise\";\nimport { mergeLatestState, wrapAsync } from \"./shared\";\n\nconst POSTGRES_TYPE_MAP: Record<TableSchema[\"columns\"][number][\"type\"], string> = {\n\tstring: \"TEXT\",\n\tnumber: \"DOUBLE PRECISION\",\n\tboolean: \"BOOLEAN\",\n\tjson: \"JSONB\",\n\tnull: \"TEXT\",\n};\n\n/**\n * Postgres SQL dialect for the shared materialise algorithm.\n *\n * Uses `$N` positional parameters, `ON CONFLICT DO UPDATE`, `JSONB`,\n * and `TIMESTAMPTZ` types.\n */\nexport class PostgresSqlDialect implements SqlDialect {\n\tcreateDestinationTable(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\tpk: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] } {\n\t\tconst columnDefs = schema.columns\n\t\t\t.map((c) => `\"${c.name}\" ${POSTGRES_TYPE_MAP[c.type]}`)\n\t\t\t.join(\", \");\n\n\t\tconst pkConstraint = `PRIMARY KEY (${pk.map((c) => `\"${c}\"`).join(\", \")})`;\n\t\tconst deletedAtCol = softDelete ? `,\\n\\tdeleted_at TIMESTAMPTZ` : \"\";\n\t\tconst uniqueConstraint = schema.externalIdColumn\n\t\t\t? `,\\n\\tUNIQUE (\"${schema.externalIdColumn}\")`\n\t\t\t: \"\";\n\n\t\treturn {\n\t\t\tsql: `CREATE TABLE IF NOT EXISTS \"${dest}\" (\n\trow_id TEXT NOT NULL,\n\t${columnDefs},\n\tprops JSONB NOT NULL DEFAULT '{}'${deletedAtCol},\n\tsynced_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n\t${pkConstraint}${uniqueConstraint}\n)`,\n\t\t\tparams: [],\n\t\t};\n\t}\n\n\tqueryDeltaHistory(sourceTable: string, rowIds: string[]): { sql: string; params: unknown[] } {\n\t\treturn {\n\t\t\tsql: `SELECT row_id, columns, op FROM lakesync_deltas WHERE \"table\" = $1 AND row_id = ANY($2) ORDER BY hlc ASC`,\n\t\t\tparams: [sourceTable, rowIds],\n\t\t};\n\t}\n\n\tbuildUpsert(\n\t\tdest: string,\n\t\tschema: TableSchema,\n\t\tconflictCols: string[],\n\t\tsoftDelete: boolean,\n\t\tupserts: Array<{ rowId: string; state: Record<string, unknown> }>,\n\t): { sql: string; params: unknown[] } {\n\t\tconst colNames = schema.columns.map((c) => c.name);\n\t\tconst baseCols = [\"row_id\", ...colNames];\n\t\tconst allCols = softDelete\n\t\t\t? [...baseCols, \"deleted_at\", \"synced_at\"]\n\t\t\t: [...baseCols, \"synced_at\"];\n\t\tconst colList = allCols.map((c) => `\"${c}\"`).join(\", \");\n\n\t\tconst values: unknown[] = [];\n\t\tconst valueRows: string[] = [];\n\t\tconst paramsPerRow = allCols.length;\n\n\t\tfor (let i = 0; i < upserts.length; i++) {\n\t\t\tconst u = upserts[i]!;\n\t\t\tconst offset = i * paramsPerRow;\n\t\t\tconst placeholders = allCols.map((_, j) => `$${offset + j + 1}`);\n\t\t\tvalueRows.push(`(${placeholders.join(\", \")})`);\n\n\t\t\tvalues.push(u.rowId);\n\t\t\tfor (const col of colNames) {\n\t\t\t\tvalues.push(u.state[col] ?? null);\n\t\t\t}\n\t\t\tif (softDelete) values.push(null); // deleted_at = NULL (un-delete)\n\t\t\tvalues.push(new Date());\n\t\t}\n\n\t\tconst conflictList = conflictCols.map((c) => `\"${c}\"`).join(\", \");\n\t\tconst updateCols = softDelete\n\t\t\t? [...colNames, \"deleted_at\", \"synced_at\"]\n\t\t\t: [...colNames, \"synced_at\"];\n\t\tconst updateSet = updateCols.map((c) => `\"${c}\" = EXCLUDED.\"${c}\"`).join(\", \");\n\n\t\treturn {\n\t\t\tsql: `INSERT INTO \"${dest}\" (${colList}) VALUES ${valueRows.join(\", \")} ON CONFLICT (${conflictList}) DO UPDATE SET ${updateSet}`,\n\t\t\tparams: values,\n\t\t};\n\t}\n\n\tbuildDelete(\n\t\tdest: string,\n\t\tdeleteIds: string[],\n\t\tsoftDelete: boolean,\n\t): { sql: string; params: unknown[] } {\n\t\tif (softDelete) {\n\t\t\treturn {\n\t\t\t\tsql: `UPDATE \"${dest}\" SET deleted_at = now(), synced_at = now() WHERE row_id = ANY($1)`,\n\t\t\t\tparams: [deleteIds],\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsql: `DELETE FROM \"${dest}\" WHERE row_id = ANY($1)`,\n\t\t\tparams: [deleteIds],\n\t\t};\n\t}\n}\n\n/**\n * PostgreSQL database adapter for LakeSync.\n *\n * Stores deltas in a `lakesync_deltas` table using pg Pool.\n * All public methods return `Result` and never throw.\n */\nexport class PostgresAdapter implements DatabaseAdapter, Materialisable {\n\t/** @internal */\n\treadonly pool: Pool;\n\tprivate readonly dialect = new PostgresSqlDialect();\n\n\tconstructor(config: DatabaseAdapterConfig) {\n\t\tconst poolConfig: PoolConfig = {\n\t\t\tconnectionString: config.connectionString,\n\t\t\tmax: config.poolMax ?? 10,\n\t\t\tidleTimeoutMillis: config.idleTimeoutMs ?? 10_000,\n\t\t\tconnectionTimeoutMillis: config.connectionTimeoutMs ?? 30_000,\n\t\t\tstatement_timeout: config.statementTimeoutMs ?? 30_000,\n\t\t};\n\t\tthis.pool = new Pool(poolConfig);\n\t}\n\n\tprivate get executor(): QueryExecutor {\n\t\tconst pool = this.pool;\n\t\treturn {\n\t\t\tasync query(sql: string, params: unknown[]): Promise<void> {\n\t\t\t\tawait pool.query(sql, params);\n\t\t\t},\n\t\t\tasync queryRows(sql: string, params: unknown[]) {\n\t\t\t\tconst result = await pool.query(sql, params);\n\t\t\t\treturn result.rows as Array<{\n\t\t\t\t\trow_id: string;\n\t\t\t\t\tcolumns: string | ColumnDelta[];\n\t\t\t\t\top: string;\n\t\t\t\t}>;\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Insert deltas into the database in a single batch.\n\t * Idempotent via `ON CONFLICT (delta_id) DO NOTHING`.\n\t */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tif (deltas.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\t// Build a multi-row INSERT with parameterised values\n\t\t\tconst values: unknown[] = [];\n\t\t\tconst rows: string[] = [];\n\n\t\t\tfor (let i = 0; i < deltas.length; i++) {\n\t\t\t\tconst d = deltas[i]!;\n\t\t\t\tconst offset = i * 7;\n\t\t\t\trows.push(\n\t\t\t\t\t`($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}, $${offset + 6}, $${offset + 7})`,\n\t\t\t\t);\n\t\t\t\tvalues.push(\n\t\t\t\t\td.deltaId,\n\t\t\t\t\td.table,\n\t\t\t\t\td.rowId,\n\t\t\t\t\tJSON.stringify(d.columns),\n\t\t\t\t\td.hlc.toString(),\n\t\t\t\t\td.clientId,\n\t\t\t\t\td.op,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst sql = `INSERT INTO lakesync_deltas (delta_id, \"table\", row_id, columns, hlc, client_id, op)\nVALUES ${rows.join(\", \")}\nON CONFLICT (delta_id) DO NOTHING`;\n\n\t\t\tawait this.pool.query(sql, values);\n\t\t}, \"Failed to insert deltas\");\n\t}\n\n\t/**\n\t * Query deltas with HLC greater than the given timestamp, optionally filtered by table.\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tlet sql: string;\n\t\t\tlet params: unknown[];\n\n\t\t\tif (tables && tables.length > 0) {\n\t\t\t\tsql = `SELECT delta_id, \"table\", row_id, columns, hlc, client_id, op\nFROM lakesync_deltas\nWHERE hlc > $1 AND \"table\" = ANY($2)\nORDER BY hlc ASC`;\n\t\t\t\tparams = [hlc.toString(), tables];\n\t\t\t} else {\n\t\t\t\tsql = `SELECT delta_id, \"table\", row_id, columns, hlc, client_id, op\nFROM lakesync_deltas\nWHERE hlc > $1\nORDER BY hlc ASC`;\n\t\t\t\tparams = [hlc.toString()];\n\t\t\t}\n\n\t\t\tconst result = await this.pool.query(sql, params);\n\t\t\treturn result.rows.map(rowToRowDelta);\n\t\t}, \"Failed to query deltas\");\n\t}\n\n\t/**\n\t * Get the latest merged state for a specific row using column-level LWW.\n\t * Returns null if no deltas exist for this row.\n\t */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst sql = `SELECT columns, hlc, client_id, op\nFROM lakesync_deltas\nWHERE \"table\" = $1 AND row_id = $2\nORDER BY hlc ASC`;\n\n\t\t\tconst result = await this.pool.query(sql, [table, rowId]);\n\t\t\treturn mergeLatestState(result.rows);\n\t\t}, `Failed to get latest state for ${table}:${rowId}`);\n\t}\n\n\t/**\n\t * Ensure the lakesync_deltas table and indices exist.\n\t * The `schema` parameter is accepted for interface compliance but the\n\t * internal table structure is fixed (deltas store column data as JSONB).\n\t */\n\tasync ensureSchema(_schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.pool.query(`\nCREATE TABLE IF NOT EXISTS lakesync_deltas (\n\tdelta_id TEXT PRIMARY KEY,\n\t\"table\" TEXT NOT NULL,\n\trow_id TEXT NOT NULL,\n\tcolumns JSONB NOT NULL,\n\thlc BIGINT NOT NULL,\n\tclient_id TEXT NOT NULL,\n\top TEXT NOT NULL DEFAULT 'INSERT'\n);\nCREATE INDEX IF NOT EXISTS idx_lakesync_deltas_hlc ON lakesync_deltas (hlc);\nCREATE INDEX IF NOT EXISTS idx_lakesync_deltas_table_row ON lakesync_deltas (\"table\", row_id);\n`);\n\t\t}, \"Failed to ensure schema\");\n\t}\n\n\t/**\n\t * Materialise deltas into destination tables.\n\t *\n\t * Delegates to the shared `executeMaterialise` algorithm with the\n\t * Postgres SQL dialect.\n\t */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\treturn executeMaterialise(this.executor, this.dialect, deltas, schemas);\n\t}\n\n\t/** Close the database connection pool and release resources. */\n\tasync close(): Promise<void> {\n\t\tawait this.pool.end();\n\t}\n}\n\n/**\n * Convert a raw Postgres row into a RowDelta.\n */\nfunction rowToRowDelta(row: Record<string, unknown>): RowDelta {\n\tconst columns: ColumnDelta[] =\n\t\ttypeof row.columns === \"string\"\n\t\t\t? JSON.parse(row.columns as string)\n\t\t\t: (row.columns as ColumnDelta[]);\n\n\treturn {\n\t\tdeltaId: row.delta_id as string,\n\t\ttable: row.table as string,\n\t\trowId: row.row_id as string,\n\t\tcolumns,\n\t\thlc: BigInt(row.hlc as string) as HLCTimestamp,\n\t\tclientId: row.client_id as string,\n\t\top: row.op as RowDelta[\"op\"],\n\t};\n}\n","import {\n\tAdapterError,\n\ttype BigQueryConnectorConfigFull,\n\ttype ConnectorConfig,\n\ttype DatabaseAdapter,\n\tErr,\n\ttype MySQLConnectorConfigFull,\n\tOk,\n\ttype PostgresConnectorConfigFull,\n\ttype Result,\n\ttoError,\n} from \"@lakesync/core\";\nimport { BigQueryAdapter } from \"./bigquery\";\nimport { MySQLAdapter } from \"./mysql\";\nimport { PostgresAdapter } from \"./postgres\";\n\n// ---------------------------------------------------------------------------\n// AdapterFactoryRegistry — open, immutable registry for adapter construction\n// ---------------------------------------------------------------------------\n\n/** Factory function that creates a DatabaseAdapter from a ConnectorConfig. */\nexport type AdapterFactory = (config: ConnectorConfig) => DatabaseAdapter;\n\n/** Immutable registry of adapter factories keyed by connector type. */\nexport interface AdapterFactoryRegistry {\n\t/** Look up a factory by type. */\n\tget(type: string): AdapterFactory | undefined;\n\t/** Create a new registry with an additional or replaced factory. */\n\twith(type: string, factory: AdapterFactory): AdapterFactoryRegistry;\n}\n\n/**\n * Create an immutable {@link AdapterFactoryRegistry} from a Map of factories.\n */\nexport function createAdapterFactoryRegistry(\n\tfactories: Map<string, AdapterFactory> = new Map(),\n): AdapterFactoryRegistry {\n\treturn buildAdapterFactoryRegistry(new Map(factories));\n}\n\nfunction buildAdapterFactoryRegistry(map: Map<string, AdapterFactory>): AdapterFactoryRegistry {\n\treturn {\n\t\tget(type: string): AdapterFactory | undefined {\n\t\t\treturn map.get(type);\n\t\t},\n\t\twith(type: string, factory: AdapterFactory): AdapterFactoryRegistry {\n\t\t\tconst next = new Map(map);\n\t\t\tnext.set(type, factory);\n\t\t\treturn buildAdapterFactoryRegistry(next);\n\t\t},\n\t};\n}\n\n/** Default registry with built-in database adapters (Postgres, MySQL, BigQuery). */\nexport function defaultAdapterFactoryRegistry(): AdapterFactoryRegistry {\n\treturn createAdapterFactoryRegistry()\n\t\t.with(\"postgres\", (c) => {\n\t\t\tconst pg = (c as PostgresConnectorConfigFull).postgres;\n\t\t\treturn new PostgresAdapter({ connectionString: pg.connectionString });\n\t\t})\n\t\t.with(\"mysql\", (c) => {\n\t\t\tconst my = (c as MySQLConnectorConfigFull).mysql;\n\t\t\treturn new MySQLAdapter({ connectionString: my.connectionString });\n\t\t})\n\t\t.with(\"bigquery\", (c) => {\n\t\t\tconst bq = (c as BigQueryConnectorConfigFull).bigquery;\n\t\t\treturn new BigQueryAdapter({\n\t\t\t\tprojectId: bq.projectId,\n\t\t\t\tdataset: bq.dataset,\n\t\t\t\tkeyFilename: bq.keyFilename,\n\t\t\t\tlocation: bq.location,\n\t\t\t});\n\t\t});\n}\n\n/**\n * Instantiate a {@link DatabaseAdapter} from a {@link ConnectorConfig}.\n *\n * Uses the provided registry (or the default built-in registry) to look up\n * a factory for the config's type. Returns an {@link AdapterError} if the\n * type is unsupported or the adapter constructor throws.\n *\n * @param config - Validated connector configuration.\n * @param registry - Optional adapter factory registry. Defaults to built-in adapters.\n * @returns The instantiated adapter or an error.\n */\nexport function createDatabaseAdapter(\n\tconfig: ConnectorConfig,\n\tregistry?: AdapterFactoryRegistry,\n): Result<DatabaseAdapter, AdapterError> {\n\tconst reg = registry ?? defaultAdapterFactoryRegistry();\n\tconst factory = reg.get(config.type);\n\tif (!factory) {\n\t\treturn Err(new AdapterError(`No adapter factory for connector type \"${config.type}\"`));\n\t}\n\ttry {\n\t\treturn Ok(factory(config));\n\t} catch (err: unknown) {\n\t\treturn Err(new AdapterError(`Failed to create adapter: ${toError(err).message}`));\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\nimport { isMaterialisable } from \"./materialise\";\n\n/** Configuration for the FanOutAdapter. */\nexport interface FanOutAdapterConfig {\n\t/** The primary adapter that handles all reads and authoritative writes. */\n\tprimary: DatabaseAdapter;\n\t/** Secondary adapters that receive replicated writes on a best-effort basis. */\n\tsecondaries: DatabaseAdapter[];\n}\n\n/**\n * Writes to a primary adapter synchronously and replicates to secondary\n * adapters asynchronously. Reads always go to the primary.\n *\n * Secondary failures are silently caught and never affect the return value.\n * Use case: write to Postgres (fast, operational), replicate to BigQuery (analytics).\n *\n * **Materialisation:** This adapter exposes a `materialise()` method for\n * duck-type compatibility with `isMaterialisable()`. When the primary adapter\n * is itself materialisable, materialisation is delegated to it; otherwise\n * the method is a graceful no-op returning `Ok`. Materialisable secondaries\n * receive fire-and-forget replication.\n */\nexport class FanOutAdapter implements DatabaseAdapter {\n\tprivate readonly primary: DatabaseAdapter;\n\tprivate readonly secondaries: ReadonlyArray<DatabaseAdapter>;\n\n\tconstructor(config: FanOutAdapterConfig) {\n\t\tthis.primary = config.primary;\n\t\tthis.secondaries = config.secondaries;\n\t}\n\n\t/** Insert deltas into the primary, then replicate to secondaries (fire-and-forget). */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\tconst result = await this.primary.insertDeltas(deltas);\n\t\tif (!result.ok) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tsecondary.insertDeltas(deltas).catch(() => {});\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Query deltas from the primary adapter only. */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\treturn this.primary.queryDeltasSince(hlc, tables);\n\t}\n\n\t/** Get the latest state from the primary adapter only. */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\treturn this.primary.getLatestState(table, rowId);\n\t}\n\n\t/** Ensure schema on the primary first, then best-effort on secondaries. */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\tconst result = await this.primary.ensureSchema(schema);\n\t\tif (!result.ok) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tsecondary.ensureSchema(schema).catch(() => {});\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Materialise via primary, then replicate to materialisable secondaries (fire-and-forget). */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\tif (isMaterialisable(this.primary)) {\n\t\t\tconst result = await this.primary.materialise(deltas, schemas);\n\t\t\tif (!result.ok) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tif (isMaterialisable(secondary)) {\n\t\t\t\tsecondary.materialise(deltas, schemas).catch(() => {});\n\t\t\t}\n\t\t}\n\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Close primary and all secondary adapters. */\n\tasync close(): Promise<void> {\n\t\tawait this.primary.close();\n\t\tfor (const secondary of this.secondaries) {\n\t\t\tawait secondary.close();\n\t\t}\n\t}\n}\n","import {\n\ttype AdapterError,\n\ttype HLCTimestamp,\n\tOk,\n\ttype Result,\n\ttype RowDelta,\n\ttype TableSchema,\n} from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\nimport { isMaterialisable } from \"./materialise\";\n\n/** Configuration for age-based tiered storage. */\nexport interface LifecycleAdapterConfig {\n\t/** Hot tier — recent data, fast queries. */\n\thot: {\n\t\t/** The adapter storing recent deltas. */\n\t\tadapter: DatabaseAdapter;\n\t\t/** Maximum age in milliseconds before data is considered cold. */\n\t\tmaxAgeMs: number;\n\t};\n\t/** Cold tier — older data, cheap storage. */\n\tcold: {\n\t\t/** The adapter storing archived deltas. */\n\t\tadapter: DatabaseAdapter;\n\t};\n}\n\n/**\n * Routes database operations across hot and cold tiers based on delta age.\n *\n * Writes always go to the hot adapter. Reads fan out to both tiers when\n * the requested HLC is older than the configured `maxAgeMs` threshold.\n *\n * Use {@link migrateToTier} as a background job to copy aged-out deltas\n * from hot to cold.\n *\n * **Materialisation:** This adapter exposes a `materialise()` method for\n * duck-type compatibility with `isMaterialisable()`. Materialisation is\n * delegated to the hot tier only — cold tier stores archived deltas, not\n * destination tables. When the hot adapter is not materialisable, the\n * method is a graceful no-op returning `Ok`.\n */\nexport class LifecycleAdapter implements DatabaseAdapter {\n\tprivate readonly hot: DatabaseAdapter;\n\tprivate readonly cold: DatabaseAdapter;\n\tprivate readonly maxAgeMs: number;\n\n\tconstructor(config: LifecycleAdapterConfig) {\n\t\tthis.hot = config.hot.adapter;\n\t\tthis.cold = config.cold.adapter;\n\t\tthis.maxAgeMs = config.hot.maxAgeMs;\n\t}\n\n\t/** Insert deltas into the hot adapter — new data is always hot. */\n\tasync insertDeltas(deltas: RowDelta[]): Promise<Result<void, AdapterError>> {\n\t\treturn this.hot.insertDeltas(deltas);\n\t}\n\n\t/**\n\t * Query deltas since the given HLC.\n\t *\n\t * If `sinceHlc` is older than `now - maxAgeMs`, queries both hot and cold\n\t * adapters and merges the results sorted by HLC. Otherwise queries hot only.\n\t */\n\tasync queryDeltasSince(\n\t\thlc: HLCTimestamp,\n\t\ttables?: string[],\n\t): Promise<Result<RowDelta[], AdapterError>> {\n\t\tconst sinceWallMs = Number(hlc >> 16n);\n\t\tconst thresholdMs = Date.now() - this.maxAgeMs;\n\n\t\tif (sinceWallMs < thresholdMs) {\n\t\t\t// Query spans into cold territory — fan out to both tiers\n\t\t\tconst [hotResult, coldResult] = await Promise.all([\n\t\t\t\tthis.hot.queryDeltasSince(hlc, tables),\n\t\t\t\tthis.cold.queryDeltasSince(hlc, tables),\n\t\t\t]);\n\n\t\t\tif (!hotResult.ok) return hotResult;\n\t\t\tif (!coldResult.ok) return coldResult;\n\n\t\t\tconst merged = [...hotResult.value, ...coldResult.value];\n\t\t\tmerged.sort((a, b) => (a.hlc < b.hlc ? -1 : a.hlc > b.hlc ? 1 : 0));\n\n\t\t\treturn Ok(merged);\n\t\t}\n\n\t\t// Recent query — hot tier only\n\t\treturn this.hot.queryDeltasSince(hlc, tables);\n\t}\n\n\t/** Get latest state — try hot first, fall back to cold if hot returns null. */\n\tasync getLatestState(\n\t\ttable: string,\n\t\trowId: string,\n\t): Promise<Result<Record<string, unknown> | null, AdapterError>> {\n\t\tconst hotResult = await this.hot.getLatestState(table, rowId);\n\t\tif (!hotResult.ok) return hotResult;\n\n\t\tif (hotResult.value !== null) {\n\t\t\treturn hotResult;\n\t\t}\n\n\t\treturn this.cold.getLatestState(table, rowId);\n\t}\n\n\t/** Ensure schema exists on both hot and cold adapters. */\n\tasync ensureSchema(schema: TableSchema): Promise<Result<void, AdapterError>> {\n\t\tconst hotResult = await this.hot.ensureSchema(schema);\n\t\tif (!hotResult.ok) return hotResult;\n\n\t\treturn this.cold.ensureSchema(schema);\n\t}\n\n\t/** Materialise via hot tier only — cold tier stores archived deltas, not destination tables. */\n\tasync materialise(\n\t\tdeltas: RowDelta[],\n\t\tschemas: ReadonlyArray<TableSchema>,\n\t): Promise<Result<void, AdapterError>> {\n\t\tif (isMaterialisable(this.hot)) {\n\t\t\treturn this.hot.materialise(deltas, schemas);\n\t\t}\n\t\treturn Ok(undefined);\n\t}\n\n\t/** Close both hot and cold adapters. */\n\tasync close(): Promise<void> {\n\t\tawait this.hot.close();\n\t\tawait this.cold.close();\n\t}\n}\n\n/**\n * Migrate aged-out deltas from the hot adapter to the cold adapter.\n *\n * Queries the hot adapter for all deltas since HLC 0, filters those with\n * wall time older than `Date.now() - maxAgeMs`, and inserts them into the\n * cold adapter. Insertion is idempotent via deltaId uniqueness.\n *\n * Does NOT delete from hot — that is a separate cleanup concern.\n *\n * @param hot - The hot-tier adapter to read old deltas from.\n * @param cold - The cold-tier adapter to write old deltas to.\n * @param maxAgeMs - Age threshold in milliseconds.\n * @returns The count of migrated deltas, or an AdapterError.\n */\nexport async function migrateToTier(\n\thot: DatabaseAdapter,\n\tcold: DatabaseAdapter,\n\tmaxAgeMs: number,\n): Promise<Result<{ migrated: number }, AdapterError>> {\n\tconst thresholdMs = Date.now() - maxAgeMs;\n\tconst thresholdHlc = (BigInt(0) << 16n) as HLCTimestamp;\n\n\tconst result = await hot.queryDeltasSince(thresholdHlc);\n\tif (!result.ok) return result;\n\n\tconst oldDeltas = result.value.filter((delta) => {\n\t\tconst wallMs = Number(delta.hlc >> 16n);\n\t\treturn wallMs < thresholdMs;\n\t});\n\n\tif (oldDeltas.length === 0) {\n\t\treturn Ok({ migrated: 0 });\n\t}\n\n\tconst insertResult = await cold.insertDeltas(oldDeltas);\n\tif (!insertResult.ok) return insertResult;\n\n\treturn Ok({ migrated: oldDeltas.length });\n}\n","import { type AdapterError, type HLCTimestamp, Ok, type Result } from \"@lakesync/core\";\n\nimport type { DatabaseAdapter } from \"./db-types\";\n\n/** Options for migrating deltas between database adapters. */\nexport interface MigrateOptions {\n\t/** Source adapter to read from */\n\tfrom: DatabaseAdapter;\n\t/** Target adapter to write to */\n\tto: DatabaseAdapter;\n\t/** Optional: only migrate specific tables */\n\ttables?: string[];\n\t/** Batch size for writing (default: 1000) */\n\tbatchSize?: number;\n\t/** Progress callback invoked after each batch write */\n\tonProgress?: (info: MigrateProgress) => void;\n}\n\n/** Progress information reported during migration. */\nexport interface MigrateProgress {\n\t/** Current batch number (1-based) */\n\tbatch: number;\n\t/** Total deltas migrated so far */\n\ttotalSoFar: number;\n}\n\n/** Result of a successful migration. */\nexport interface MigrateResult {\n\t/** Total number of deltas migrated */\n\ttotalDeltas: number;\n\t/** Number of batches processed */\n\tbatches: number;\n}\n\n/**\n * Migrate deltas from one database adapter to another.\n * Reads all matching deltas from the source, then writes them in batches to the target.\n * Idempotent via deltaId uniqueness in the target adapter.\n */\nexport async function migrateAdapter(\n\topts: MigrateOptions,\n): Promise<Result<MigrateResult, AdapterError>> {\n\tconst batchSize = opts.batchSize ?? 1000;\n\n\tconst readResult = await opts.from.queryDeltasSince(BigInt(0) as HLCTimestamp, opts.tables);\n\tif (!readResult.ok) {\n\t\treturn readResult;\n\t}\n\n\tconst deltas = readResult.value;\n\n\tif (deltas.length === 0) {\n\t\treturn Ok({ totalDeltas: 0, batches: 0 });\n\t}\n\n\tlet batchCount = 0;\n\tlet totalSoFar = 0;\n\n\tfor (let i = 0; i < deltas.length; i += batchSize) {\n\t\tconst batch = deltas.slice(i, i + batchSize);\n\t\tconst writeResult = await opts.to.insertDeltas(batch);\n\t\tif (!writeResult.ok) {\n\t\t\treturn writeResult;\n\t\t}\n\n\t\tbatchCount++;\n\t\ttotalSoFar += batch.length;\n\n\t\topts.onProgress?.({ batch: batchCount, totalSoFar });\n\t}\n\n\treturn Ok({ totalDeltas: totalSoFar, batches: batchCount });\n}\n","import {\n\tDeleteObjectCommand,\n\tDeleteObjectsCommand,\n\tGetObjectCommand,\n\tHeadObjectCommand,\n\tListObjectsV2Command,\n\tPutObjectCommand,\n\tS3Client,\n} from \"@aws-sdk/client-s3\";\nimport { AdapterError, Ok, type Result } from \"@lakesync/core\";\nimport { wrapAsync } from \"./shared\";\nimport type { AdapterConfig, LakeAdapter, ObjectInfo } from \"./types\";\n\n/**\n * MinIO/S3-compatible lake adapter.\n *\n * Wraps the AWS S3 SDK to provide a Result-based interface for\n * interacting with MinIO or any S3-compatible object store.\n * All public methods return `Result` and never throw.\n */\nexport class MinIOAdapter implements LakeAdapter {\n\tprivate readonly client: S3Client;\n\tprivate readonly bucket: string;\n\n\tconstructor(config: AdapterConfig) {\n\t\tthis.bucket = config.bucket;\n\t\tthis.client = new S3Client({\n\t\t\tendpoint: config.endpoint,\n\t\t\tregion: config.region ?? \"us-east-1\",\n\t\t\tcredentials: config.credentials,\n\t\t\tforcePathStyle: true, // Required for MinIO\n\t\t});\n\t}\n\n\t/** Store an object in the lake */\n\tasync putObject(\n\t\tpath: string,\n\t\tdata: Uint8Array,\n\t\tcontentType?: string,\n\t): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.client.send(\n\t\t\t\tnew PutObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t\tBody: data,\n\t\t\t\t\tContentType: contentType,\n\t\t\t\t}),\n\t\t\t);\n\t\t}, `Failed to put object: ${path}`);\n\t}\n\n\t/** Retrieve an object from the lake */\n\tasync getObject(path: string): Promise<Result<Uint8Array, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew GetObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tconst bytes = await response.Body?.transformToByteArray();\n\t\t\tif (!bytes) {\n\t\t\t\tthrow new AdapterError(`Empty response for object: ${path}`);\n\t\t\t}\n\t\t\treturn bytes;\n\t\t}, `Failed to get object: ${path}`);\n\t}\n\n\t/** Get object metadata without retrieving the body */\n\tasync headObject(\n\t\tpath: string,\n\t): Promise<Result<{ size: number; lastModified: Date }, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew HeadObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tsize: response.ContentLength ?? 0,\n\t\t\t\tlastModified: response.LastModified ?? new Date(0),\n\t\t\t};\n\t\t}, `Failed to head object: ${path}`);\n\t}\n\n\t/** List objects matching a given prefix */\n\tasync listObjects(prefix: string): Promise<Result<ObjectInfo[], AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tconst response = await this.client.send(\n\t\t\t\tnew ListObjectsV2Command({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tPrefix: prefix,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn (response.Contents ?? []).map((item) => ({\n\t\t\t\tkey: item.Key ?? \"\",\n\t\t\t\tsize: item.Size ?? 0,\n\t\t\t\tlastModified: item.LastModified ?? new Date(0),\n\t\t\t}));\n\t\t}, `Failed to list objects with prefix: ${prefix}`);\n\t}\n\n\t/** Delete a single object from the lake */\n\tasync deleteObject(path: string): Promise<Result<void, AdapterError>> {\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteObjectCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tKey: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t}, `Failed to delete object: ${path}`);\n\t}\n\n\t/** Delete multiple objects from the lake in a single batch operation */\n\tasync deleteObjects(paths: string[]): Promise<Result<void, AdapterError>> {\n\t\tif (paths.length === 0) {\n\t\t\treturn Ok(undefined);\n\t\t}\n\n\t\treturn wrapAsync(async () => {\n\t\t\tawait this.client.send(\n\t\t\t\tnew DeleteObjectsCommand({\n\t\t\t\t\tBucket: this.bucket,\n\t\t\t\t\tDelete: {\n\t\t\t\t\t\tObjects: paths.map((key) => ({ Key: key })),\n\t\t\t\t\t\tQuiet: true,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t);\n\t\t}, `Failed to batch delete ${paths.length} objects`);\n\t}\n}\n","import type {\n\tConnectorConfig,\n\tMySQLConnectorConfigFull,\n\tPostgresConnectorConfigFull,\n} from \"@lakesync/core\";\n\n/** Generic query function — abstracts any SQL database connection. */\nexport type QueryFn = (sql: string, params?: unknown[]) => Promise<Record<string, unknown>[]>;\n\n/**\n * Create a raw SQL query function from a {@link ConnectorConfig}.\n *\n * Uses dynamic imports so the database drivers (pg, mysql2) are only\n * loaded when actually needed. Returns `null` for connector types that\n * do not support the standard SQL polling model (e.g. BigQuery, Jira, Salesforce).\n *\n * @param config - Validated connector configuration.\n * @returns A query function or `null` if the connector type is unsupported.\n */\nexport async function createQueryFn(config: ConnectorConfig): Promise<QueryFn | null> {\n\tswitch (config.type) {\n\t\tcase \"postgres\": {\n\t\t\tconst pg = config as PostgresConnectorConfigFull;\n\t\t\tconst { Pool } = await import(\"pg\");\n\t\t\tconst pool = new Pool({ connectionString: pg.postgres.connectionString });\n\t\t\treturn async (sql: string, params?: unknown[]) => {\n\t\t\t\tconst result = await pool.query(sql, params);\n\t\t\t\treturn result.rows as Record<string, unknown>[];\n\t\t\t};\n\t\t}\n\t\tcase \"mysql\": {\n\t\t\tconst my = config as MySQLConnectorConfigFull;\n\t\t\tconst mysql = await import(\"mysql2/promise\");\n\t\t\tconst pool = mysql.createPool(my.mysql.connectionString);\n\t\t\treturn async (sql: string, params?: unknown[]) => {\n\t\t\t\tconst [rows] = await pool.query(sql, params);\n\t\t\t\treturn rows as Record<string, unknown>[];\n\t\t\t};\n\t\t}\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n"],"mappings":"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","names":["rowToRowDelta","Pool","mysql"]}
|