@rocicorp/zero 0.26.2-canary.4 → 0.26.2-canary.6
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/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +17 -3
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +8 -3
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +44 -17
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +134 -0
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +75 -6
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +7 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +3 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/types/pg.d.ts +6 -0
- package/out/zero-cache/src/types/pg.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg.js +14 -7
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/workers/connection.js +2 -2
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +5 -1
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../z2s/src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAQ7C,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAExD,OAAO,KAAK,EACV,GAAG,EAEH,kBAAkB,EAElB,WAAW,EAEX,QAAQ,EACR,eAAe,EAEhB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AACxE,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AAUtD,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,YAAY,CAAC;IAErB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAQF,wBAAgB,OAAO,CACrB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,GAAG,EACR,MAAM,CAAC,EAAE,MAAM,GACd,QAAQ,CAgBV;AA4CD,wBAAgB,KAAK,CACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAC5B,QAAQ,CAWV;AAUD,wBAAgB,OAAO,CACrB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,QAAQ,GAAG,SAAS,EAC7B,KAAK,EAAE,KAAK,GACX,QAAQ,CAoBV;AA4LD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,CAAC,UAAU,EAAE,KAAK,KAAK,QAAQ,CAiBjC;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAgCV;AAED,wBAAgB,GAAG,CACjB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAMV;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAIV;AAmGD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD,IAAI,EAAE,QAAQ,CAAC;IACf,mBAAmB,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;CAC/D,CA2BA;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD;QACE,KAAK,EAAE,KAAK,CAAC;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KAC3B;IACD;QAAC,KAAK,EAAE,KAAK,CAAC;QAAC,WAAW,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAC;CACpE,CAsBA;
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../../../z2s/src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAQ7C,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAExD,OAAO,KAAK,EACV,GAAG,EAEH,kBAAkB,EAElB,WAAW,EAEX,QAAQ,EACR,eAAe,EAEhB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AACxE,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AAUtD,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,YAAY,CAAC;IAErB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAQF,wBAAgB,OAAO,CACrB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,GAAG,EACR,MAAM,CAAC,EAAE,MAAM,GACd,QAAQ,CAgBV;AA4CD,wBAAgB,KAAK,CACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAC5B,QAAQ,CAWV;AAUD,wBAAgB,OAAO,CACrB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,QAAQ,GAAG,SAAS,EAC7B,KAAK,EAAE,KAAK,GACX,QAAQ,CAoBV;AA4LD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,CAAC,UAAU,EAAE,KAAK,KAAK,QAAQ,CAiBjC;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAgCV;AAED,wBAAgB,GAAG,CACjB,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAMV;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,eAAe,EAC1B,KAAK,EAAE,KAAK,GACX,QAAQ,CAIV;AAmGD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD,IAAI,EAAE,QAAQ,CAAC;IACf,mBAAmB,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;CAC/D,CA2BA;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,kBAAkB,GAC/B;IACD;QACE,KAAK,EAAE,KAAK,CAAC;QACb,WAAW,EAAE,WAAW,CAAC;QACzB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;KAC3B;IACD;QAAC,KAAK,EAAE,KAAK,CAAC;QAAC,WAAW,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAC;CACpE,CAsBA;AAwED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAMhE"}
|
package/out/z2s/src/compiler.js
CHANGED
|
@@ -252,9 +252,23 @@ function toJSON(table, singular = false) {
|
|
|
252
252
|
function selectIdent(server, column) {
|
|
253
253
|
const serverColumnSchema = server.schema[server.mapper.tableName(column.table.zql)][server.mapper.columnName(column.table.zql, column.zql)];
|
|
254
254
|
const serverType = serverColumnSchema.type;
|
|
255
|
-
if (!serverColumnSchema.isEnum
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
if (!serverColumnSchema.isEnum) {
|
|
256
|
+
let needsNormalization = false;
|
|
257
|
+
switch (serverType) {
|
|
258
|
+
case "timestamptz":
|
|
259
|
+
case "timetz": needsNormalization = true;
|
|
260
|
+
case "date":
|
|
261
|
+
case "time":
|
|
262
|
+
case "time without time zone":
|
|
263
|
+
case "time with time zone":
|
|
264
|
+
case "timestamp":
|
|
265
|
+
case "timestamp without time zone":
|
|
266
|
+
case "timestamp with time zone": {
|
|
267
|
+
const toMs = (epochExpr) => needsNormalization ? sql`((${epochExpr})::bigint + 86400000) % 86400000` : epochExpr;
|
|
268
|
+
if (serverColumnSchema.isArray) return sql`ARRAY(SELECT ${toMs(sql`EXTRACT(EPOCH FROM unnest(${colIdent(server, column)})) * 1000`)}) as ${sql.ident(column.zql)}`;
|
|
269
|
+
return sql`${toMs(sql`EXTRACT(EPOCH FROM ${colIdent(server, column)}) * 1000`)} as ${sql.ident(column.zql)}`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
258
272
|
}
|
|
259
273
|
return sql`${colIdent(server, column)} as ${sql.ident(column.zql)}`;
|
|
260
274
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.js","names":[],"sources":["../../../../z2s/src/compiler.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport {last, zip} from '../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n parse as parseBigIntJson,\n type JSONValue as BigIntJSONValue,\n} from '../../shared/src/bigint-json.ts';\nimport {hasOwn} from '../../shared/src/has-own.ts';\nimport {type JSONValue} from '../../shared/src/json.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {\n AST,\n Condition,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Correlation,\n LiteralReference,\n Ordering,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {\n clientToServer,\n type NameMapper,\n} from '../../zero-schema/src/name-mapper.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {ServerSchema} from '../../zero-types/src/server-schema.ts';\nimport type {Format} from '../../zql/src/ivm/view.ts';\nimport {completeOrdering} from '../../zql/src/query/complete-ordering.ts';\nimport {\n sql,\n sqlConvertColumnArg,\n sqlConvertPluralLiteralArg,\n sqlConvertSingularLiteralArg,\n type PluralLiteralType,\n} from './sql.ts';\n\ntype Table = {\n zql: string;\n alias: string;\n};\n\ntype QualifiedColumn = {\n table: Table;\n zql: string;\n};\n\ntype ServerSpec = {\n schema: ServerSchema;\n // maps zql names to server names\n mapper: NameMapper;\n};\n\nexport type Spec = {\n server: ServerSpec;\n zql: Schema['tables'];\n aliasCount: number;\n};\n\nconst ZQL_RESULT_KEY = 'zql_result';\nconst ZQL_RESULT_KEY_IDENT = sql.ident(ZQL_RESULT_KEY);\n\nconst ZQL_RESULT_TABLE_KEY = 'zql_root';\nconst ZQL_RESULT_TABLE_IDENT = sql.ident(ZQL_RESULT_TABLE_KEY);\n\nexport function compile(\n serverSchema: ServerSchema,\n zqlSchema: Schema,\n ast: AST,\n format?: Format,\n): SQLQuery {\n ast = completeOrdering(\n ast,\n tableName => zqlSchema.tables[tableName].primaryKey,\n );\n const spec: Spec = {\n aliasCount: 0,\n server: {\n schema: serverSchema,\n mapper: clientToServer(zqlSchema.tables),\n },\n zql: zqlSchema.tables,\n };\n return sql`SELECT \n ${toJSON(ZQL_RESULT_TABLE_KEY, format?.singular)}::text AS ${ZQL_RESULT_KEY_IDENT}\n FROM (${select(spec, ast, format)}) ${ZQL_RESULT_TABLE_IDENT}`;\n}\n\nfunction select(\n spec: Spec,\n ast: AST,\n format: Format | undefined,\n correlate?: (childTable: Table) => SQLQuery,\n): SQLQuery {\n const table = makeTable(spec, ast.table);\n const selectionSet = related(spec, ast.related ?? [], format, table);\n const tableSchema = spec.zql[ast.table];\n const usedAliases = new Set<string>(\n ast.related?.map(r => r.subquery.alias ?? ''),\n );\n for (const column of Object.keys(tableSchema.columns)) {\n if (!usedAliases.has(column)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table,\n zql: column,\n }),\n );\n }\n }\n\n let appliedWhere = false;\n function maybeWhere(test: unknown | undefined) {\n if (!test) {\n return sql``;\n }\n\n const ret = appliedWhere ? sql`AND` : sql`WHERE`;\n appliedWhere = true;\n return ret;\n }\n\n return sql`SELECT ${sql.join(selectionSet, ',')}\n FROM ${fromIdent(spec.server, table)}\n ${maybeWhere(ast.where)} ${where(spec, ast.where, table)}\n ${maybeWhere(correlate)} ${correlate ? correlate(table) : sql``}\n ${orderBy(spec, ast.orderBy, table)}\n ${limit(ast.limit, format?.singular)}`;\n}\n\nexport function limit(\n limit: number | undefined,\n singular: boolean | undefined,\n): SQLQuery {\n if (limit === 0) {\n return sql`LIMIT 0`;\n }\n if (singular) {\n return sql`LIMIT 1`;\n }\n if (limit === undefined) {\n return sql``;\n }\n return sql`LIMIT ${sqlConvertSingularLiteralArg(limit)}`;\n}\n\nfunction makeTable(spec: Spec, zql: string, alias?: string): Table {\n alias = alias ?? zql + '_' + spec.aliasCount++;\n return {\n zql,\n alias,\n };\n}\n\nexport function orderBy(\n spec: Spec,\n orderBy: Ordering | undefined,\n table: Table,\n): SQLQuery {\n if (!orderBy) {\n return sql``;\n }\n return sql`ORDER BY ${sql.join(\n orderBy.map(([col, dir]) =>\n dir === 'asc'\n ? // Oh postgres. The table must be referred to by client name but the column by server name.\n // E.g., `SELECT server_col as client_col FROM server_table as client_table ORDER BY client_Table.server_col`\n sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} ASC NULLS FIRST`\n : sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} DESC NULLS LAST`,\n ),\n ', ',\n )}`;\n}\n\nfunction related(\n spec: Spec,\n relationships: readonly CorrelatedSubquery[],\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery[] {\n return relationships.map(relationship =>\n relationshipSubquery(\n spec,\n relationship,\n format?.relationships[must(relationship.subquery.alias)],\n parentTable,\n ),\n );\n}\n\nfunction relationshipSubquery(\n spec: Spec,\n relationship: CorrelatedSubquery,\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery {\n const innerAlias = `inner_${relationship.subquery.alias}`;\n if (relationship.hidden) {\n const {join, participatingTables} = makeJunctionJoin(spec, relationship);\n const lastTable = must(last(participatingTables)).table;\n\n assert(\n relationship.subquery.related,\n 'hidden relationship must be a junction',\n );\n const nestedAst = relationship.subquery.related[0].subquery;\n const selectionSet = related(\n spec,\n nestedAst.related ?? [],\n format,\n lastTable,\n );\n const tableSchema = spec.zql[nestedAst.table];\n for (const column of Object.keys(tableSchema.columns)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table: lastTable,\n zql: column,\n }),\n );\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (SELECT ${sql.join(\n selectionSet,\n ',',\n )} FROM ${join} WHERE (${makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n )(participatingTables[0].table)}) ${\n nestedAst.where\n ? sql`AND ${where(spec, nestedAst.where, lastTable)}`\n : sql``\n } ${orderBy(spec, nestedAst.orderBy, lastTable)} ${limit(\n last(participatingTables)?.limit,\n format?.singular,\n )} ) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (${select(\n spec,\n relationship.subquery,\n format,\n makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n ),\n )}) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n}\n\nfunction where(\n spec: Spec,\n condition: Condition | undefined,\n table: Table,\n): SQLQuery {\n if (!condition) {\n return sql``;\n }\n\n switch (condition.type) {\n case 'and':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' AND ',\n )})`;\n case 'or':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' OR ',\n )})`;\n case 'correlatedSubquery':\n if (condition.scalar) {\n return scalarSubquery(spec, condition, table);\n }\n return exists(spec, condition, table);\n case 'simple':\n return simple(spec, condition, table);\n }\n}\n\nfunction exists(\n spec: Spec,\n condition: CorrelatedSubqueryCondition,\n parentTable: Table,\n): SQLQuery {\n switch (condition.op) {\n case 'EXISTS':\n return sql`EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n case 'NOT EXISTS':\n return sql`NOT EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n }\n}\n\nfunction scalarSubquery(\n spec: Spec,\n condition: CorrelatedSubqueryCondition,\n parentTable: Table,\n): SQLQuery {\n const parentField = condition.related.correlation.parentField[0];\n const childField = condition.related.correlation.childField[0];\n const subqueryAST = condition.related.subquery;\n\n const parentCol = colIdent(spec.server, {\n table: parentTable,\n zql: parentField,\n });\n\n const subqueryTable = makeTable(spec, subqueryAST.table);\n const childCol = colIdent(spec.server, {\n table: subqueryTable,\n zql: childField,\n });\n\n const op = sql.__dangerous__rawValue(\n condition.op === 'EXISTS' ? '=' : 'IS NOT',\n );\n\n const subqueryWhere = subqueryAST.where\n ? sql`WHERE ${where(spec, subqueryAST.where, subqueryTable)}`\n : sql``;\n const subqueryOrderBy = orderBy(spec, subqueryAST.orderBy, subqueryTable);\n\n return sql`${parentCol} ${op} (SELECT ${childCol} FROM ${fromIdent(spec.server, subqueryTable)} ${subqueryWhere} ${subqueryOrderBy} LIMIT 1)`;\n}\n\nexport function makeCorrelator(\n spec: Spec,\n parentFields: readonly QualifiedColumn[],\n childZqlFields: readonly string[],\n): (childTable: Table) => SQLQuery {\n return (childTable: Table) => {\n const childFields = childZqlFields.map(zqlField => ({\n table: childTable,\n zql: zqlField,\n }));\n return sql.join(\n zip(parentFields, childFields).map(\n ([parentColumn, childColumn]) =>\n sql`${colIdent(spec.server, parentColumn)} = ${colIdent(\n spec.server,\n childColumn,\n )}`,\n ),\n ' AND ',\n );\n };\n}\n\nexport function simple(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n switch (condition.op) {\n case '!=':\n case '<':\n case '<=':\n case '=':\n case '>':\n case '>=':\n case 'ILIKE':\n case 'LIKE':\n case 'NOT ILIKE':\n case 'NOT LIKE':\n return sql`${valueComparison(\n spec,\n condition.left,\n table,\n condition.right,\n false,\n )} ${sql.__dangerous__rawValue(condition.op)} ${valueComparison(\n spec,\n condition.right,\n table,\n condition.left,\n false,\n )}`;\n case 'NOT IN':\n case 'IN':\n return any(spec, condition, table);\n case 'IS':\n case 'IS NOT':\n return distinctFrom(spec, condition, table);\n }\n}\n\nexport function any(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${condition.op === 'NOT IN' ? sql`NOT` : sql``}\n (\n ${valueComparison(spec, condition.left, table, condition.right, false)} = ANY \n (${valueComparison(spec, condition.right, table, condition.left, true)})\n )`;\n}\n\nexport function distinctFrom(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${valueComparison(spec, condition.left, table, condition.right, false)} ${\n condition.op === 'IS' ? sql`IS NOT DISTINCT FROM` : sql`IS DISTINCT FROM`\n } ${valueComparison(spec, condition.right, table, condition.left, false)}`;\n}\n\nfunction valueComparison(\n spec: Spec,\n valuePos: ValuePosition,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const valuePosType = valuePos.type;\n switch (valuePosType) {\n case 'column': {\n const qualified: QualifiedColumn = {\n table,\n zql: valuePos.name,\n };\n return colIdent(spec.server, qualified);\n }\n case 'literal':\n return literalValueComparison(\n spec,\n valuePos,\n table,\n otherValuePos,\n plural,\n );\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(valuePosType);\n break;\n }\n}\n\nfunction literalValueComparison(\n spec: Spec,\n valuePos: LiteralReference,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const otherType = otherValuePos.type;\n switch (otherType) {\n case 'column':\n return sqlConvertColumnArg(\n getServerColumn(spec.server, table, otherValuePos.name),\n valuePos.value,\n plural,\n true,\n );\n case 'literal': {\n assert(\n plural === Array.isArray(valuePos.value),\n 'Expected plural flag to match whether value is an array',\n );\n if (Array.isArray(valuePos.value)) {\n if (valuePos.value.length > 0) {\n // If the array is non-empty base its type on its first\n // element\n return sqlConvertPluralLiteralArg(\n typeof valuePos.value[0] as PluralLiteralType,\n valuePos.value as PluralLiteralType[],\n );\n }\n // If the array is empty, base its type on the other value\n // position's type (as long as the other value position is non-null,\n // cannot have a null[]).\n if (otherValuePos.value !== null) {\n return sqlConvertPluralLiteralArg(\n typeof otherValuePos.value as PluralLiteralType,\n [],\n );\n }\n // If the other value position is null, it can be compared to any\n // type of empty array, chose 'string' arbitrarily.\n return sqlConvertPluralLiteralArg('string', []);\n }\n if (\n typeof valuePos.value === 'string' ||\n typeof valuePos.value === 'number' ||\n typeof valuePos.value === 'boolean'\n ) {\n return sqlConvertSingularLiteralArg(valuePos.value);\n }\n throw new Error(\n `Literal of unexpected type. ${valuePos.value} of type ${typeof valuePos.value}`,\n );\n }\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(otherType);\n }\n}\n\nexport function makeJunctionJoin(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): {\n join: SQLQuery;\n participatingTables: ReturnType<typeof pullTablesForJunction>;\n} {\n const participatingTables = pullTablesForJunction(spec, relationship);\n const joins: SQLQuery[] = [];\n\n for (const {table} of participatingTables) {\n if (joins.length === 0) {\n joins.push(fromIdent(spec.server, table));\n continue;\n }\n joins.push(\n sql` JOIN ${fromIdent(spec.server, table)} ON ${makeCorrelator(\n spec,\n participatingTables[joins.length].correlation.parentField.map(f => ({\n table: participatingTables[joins.length - 1].table,\n zql: f,\n })),\n participatingTables[joins.length].correlation.childField,\n )(participatingTables[joins.length].table)}`,\n );\n }\n\n return {\n join: sql`${sql.join(joins, '')}`,\n participatingTables,\n // lastTable: participatingTables[participatingTables.length - 1].table,\n // lastLimit: participatingTables[participatingTables.length - 1].limit,\n };\n}\n\nexport function pullTablesForJunction(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): [\n {\n table: Table;\n correlation: Correlation;\n limit: number | undefined;\n },\n {table: Table; correlation: Correlation; limit: number | undefined},\n] {\n assert(\n relationship.subquery.related?.length === 1,\n 'Too many related tables for a junction edge',\n );\n const otherRelationship = relationship.subquery.related[0];\n assert(\n !otherRelationship.hidden,\n 'Expected junction edge relationship to not be hidden',\n );\n return [\n {\n table: makeTable(spec, relationship.subquery.table),\n correlation: relationship.correlation,\n limit: relationship.subquery.limit,\n },\n {\n table: makeTable(spec, otherRelationship.subquery.table),\n correlation: otherRelationship.correlation,\n limit: otherRelationship.subquery.limit,\n },\n ];\n}\n\nfunction toJSON(table: string, singular = false): SQLQuery {\n return sql`${\n singular ? sql`` : sql`COALESCE(json_agg`\n }(row_to_json(${sql.ident(table)}))${singular ? sql`` : sql`, '[]'::json)`}`;\n}\n\nfunction selectIdent(server: ServerSpec, column: QualifiedColumn): SQLQuery {\n const serverColumnSchema =\n server.schema[server.mapper.tableName(column.table.zql)][\n server.mapper.columnName(column.table.zql, column.zql)\n ];\n const serverType = serverColumnSchema.type;\n if (\n !serverColumnSchema.isEnum &&\n (serverType === 'date' ||\n serverType === 'timestamp' ||\n serverType === 'timestamp without time zone' ||\n serverType === 'timestamptz' ||\n serverType === 'timestamp with time zone')\n ) {\n if (serverColumnSchema.isArray) {\n // Map EXTRACT(EPOCH FROM ...) * 1000 over array elements\n return sql`ARRAY(SELECT EXTRACT(EPOCH FROM unnest(${colIdent(server, column)})) * 1000) as ${sql.ident(column.zql)}`;\n }\n return sql`EXTRACT(EPOCH FROM ${colIdent(server, column)}) * 1000 as ${sql.ident(column.zql)}`;\n }\n return sql`${colIdent(server, column)} as ${sql.ident(column.zql)}`;\n}\n\nfunction colIdent(server: ServerSpec, column: QualifiedColumn) {\n return sql.ident(\n column.table.alias,\n server.mapper.columnName(column.table.zql, column.zql),\n );\n}\n\nfunction fromIdent(server: ServerSpec, table: Table) {\n return sql`${sql.ident(server.mapper.tableName(table.zql))} AS ${sql.ident(table.alias)}`;\n}\n\nfunction getServerColumn(spec: ServerSpec, table: Table, zqlColumn: string) {\n return spec.schema[spec.mapper.tableName(table.zql)][\n spec.mapper.columnName(table.zql, zqlColumn)\n ];\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nexport function extractZqlResult(pgResult: Array<any>): JSONValue {\n const bigIntJson: BigIntJSONValue = parseBigIntJson(\n pgResult[0][ZQL_RESULT_KEY],\n );\n assertJSONValue(bigIntJson);\n return bigIntJson;\n}\n\nfunction assertJSONValue(v: BigIntJSONValue): asserts v is JSONValue {\n const path = findPathToBigInt(v);\n if (path) {\n throw new Error(`Value exceeds safe Number range. ${path}`);\n }\n}\n\nfunction findPathToBigInt(v: BigIntJSONValue): string | undefined {\n const typeOfV = typeof v;\n switch (typeOfV) {\n case 'bigint':\n return ` = ${v}`;\n case 'object': {\n if (v === null) {\n return;\n }\n if (Array.isArray(v)) {\n for (let i = 0; i < v.length; i++) {\n const path = findPathToBigInt(v[i]);\n if (path) {\n return `[${i}]${path}`;\n }\n }\n return undefined;\n }\n\n const o = v as Record<string, BigIntJSONValue>;\n for (const k in o) {\n if (hasOwn(o, k)) {\n const path = findPathToBigInt(o[k]);\n if (path) {\n return `['${k}']${path}`;\n }\n }\n }\n return undefined;\n }\n case 'number':\n return undefined;\n case 'boolean':\n return undefined;\n default:\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compiler.js","names":[],"sources":["../../../../z2s/src/compiler.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport {last, zip} from '../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n parse as parseBigIntJson,\n type JSONValue as BigIntJSONValue,\n} from '../../shared/src/bigint-json.ts';\nimport {hasOwn} from '../../shared/src/has-own.ts';\nimport {type JSONValue} from '../../shared/src/json.ts';\nimport {must} from '../../shared/src/must.ts';\nimport type {\n AST,\n Condition,\n CorrelatedSubquery,\n CorrelatedSubqueryCondition,\n Correlation,\n LiteralReference,\n Ordering,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport {\n clientToServer,\n type NameMapper,\n} from '../../zero-schema/src/name-mapper.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {ServerSchema} from '../../zero-types/src/server-schema.ts';\nimport type {Format} from '../../zql/src/ivm/view.ts';\nimport {completeOrdering} from '../../zql/src/query/complete-ordering.ts';\nimport {\n sql,\n sqlConvertColumnArg,\n sqlConvertPluralLiteralArg,\n sqlConvertSingularLiteralArg,\n type PluralLiteralType,\n} from './sql.ts';\n\ntype Table = {\n zql: string;\n alias: string;\n};\n\ntype QualifiedColumn = {\n table: Table;\n zql: string;\n};\n\ntype ServerSpec = {\n schema: ServerSchema;\n // maps zql names to server names\n mapper: NameMapper;\n};\n\nexport type Spec = {\n server: ServerSpec;\n zql: Schema['tables'];\n aliasCount: number;\n};\n\nconst ZQL_RESULT_KEY = 'zql_result';\nconst ZQL_RESULT_KEY_IDENT = sql.ident(ZQL_RESULT_KEY);\n\nconst ZQL_RESULT_TABLE_KEY = 'zql_root';\nconst ZQL_RESULT_TABLE_IDENT = sql.ident(ZQL_RESULT_TABLE_KEY);\n\nexport function compile(\n serverSchema: ServerSchema,\n zqlSchema: Schema,\n ast: AST,\n format?: Format,\n): SQLQuery {\n ast = completeOrdering(\n ast,\n tableName => zqlSchema.tables[tableName].primaryKey,\n );\n const spec: Spec = {\n aliasCount: 0,\n server: {\n schema: serverSchema,\n mapper: clientToServer(zqlSchema.tables),\n },\n zql: zqlSchema.tables,\n };\n return sql`SELECT \n ${toJSON(ZQL_RESULT_TABLE_KEY, format?.singular)}::text AS ${ZQL_RESULT_KEY_IDENT}\n FROM (${select(spec, ast, format)}) ${ZQL_RESULT_TABLE_IDENT}`;\n}\n\nfunction select(\n spec: Spec,\n ast: AST,\n format: Format | undefined,\n correlate?: (childTable: Table) => SQLQuery,\n): SQLQuery {\n const table = makeTable(spec, ast.table);\n const selectionSet = related(spec, ast.related ?? [], format, table);\n const tableSchema = spec.zql[ast.table];\n const usedAliases = new Set<string>(\n ast.related?.map(r => r.subquery.alias ?? ''),\n );\n for (const column of Object.keys(tableSchema.columns)) {\n if (!usedAliases.has(column)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table,\n zql: column,\n }),\n );\n }\n }\n\n let appliedWhere = false;\n function maybeWhere(test: unknown | undefined) {\n if (!test) {\n return sql``;\n }\n\n const ret = appliedWhere ? sql`AND` : sql`WHERE`;\n appliedWhere = true;\n return ret;\n }\n\n return sql`SELECT ${sql.join(selectionSet, ',')}\n FROM ${fromIdent(spec.server, table)}\n ${maybeWhere(ast.where)} ${where(spec, ast.where, table)}\n ${maybeWhere(correlate)} ${correlate ? correlate(table) : sql``}\n ${orderBy(spec, ast.orderBy, table)}\n ${limit(ast.limit, format?.singular)}`;\n}\n\nexport function limit(\n limit: number | undefined,\n singular: boolean | undefined,\n): SQLQuery {\n if (limit === 0) {\n return sql`LIMIT 0`;\n }\n if (singular) {\n return sql`LIMIT 1`;\n }\n if (limit === undefined) {\n return sql``;\n }\n return sql`LIMIT ${sqlConvertSingularLiteralArg(limit)}`;\n}\n\nfunction makeTable(spec: Spec, zql: string, alias?: string): Table {\n alias = alias ?? zql + '_' + spec.aliasCount++;\n return {\n zql,\n alias,\n };\n}\n\nexport function orderBy(\n spec: Spec,\n orderBy: Ordering | undefined,\n table: Table,\n): SQLQuery {\n if (!orderBy) {\n return sql``;\n }\n return sql`ORDER BY ${sql.join(\n orderBy.map(([col, dir]) =>\n dir === 'asc'\n ? // Oh postgres. The table must be referred to by client name but the column by server name.\n // E.g., `SELECT server_col as client_col FROM server_table as client_table ORDER BY client_Table.server_col`\n sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} ASC NULLS FIRST`\n : sql`${colIdent(spec.server, {\n table,\n zql: col,\n })} DESC NULLS LAST`,\n ),\n ', ',\n )}`;\n}\n\nfunction related(\n spec: Spec,\n relationships: readonly CorrelatedSubquery[],\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery[] {\n return relationships.map(relationship =>\n relationshipSubquery(\n spec,\n relationship,\n format?.relationships[must(relationship.subquery.alias)],\n parentTable,\n ),\n );\n}\n\nfunction relationshipSubquery(\n spec: Spec,\n relationship: CorrelatedSubquery,\n format: Format | undefined,\n parentTable: Table,\n): SQLQuery {\n const innerAlias = `inner_${relationship.subquery.alias}`;\n if (relationship.hidden) {\n const {join, participatingTables} = makeJunctionJoin(spec, relationship);\n const lastTable = must(last(participatingTables)).table;\n\n assert(\n relationship.subquery.related,\n 'hidden relationship must be a junction',\n );\n const nestedAst = relationship.subquery.related[0].subquery;\n const selectionSet = related(\n spec,\n nestedAst.related ?? [],\n format,\n lastTable,\n );\n const tableSchema = spec.zql[nestedAst.table];\n for (const column of Object.keys(tableSchema.columns)) {\n selectionSet.push(\n selectIdent(spec.server, {\n table: lastTable,\n zql: column,\n }),\n );\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (SELECT ${sql.join(\n selectionSet,\n ',',\n )} FROM ${join} WHERE (${makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n )(participatingTables[0].table)}) ${\n nestedAst.where\n ? sql`AND ${where(spec, nestedAst.where, lastTable)}`\n : sql``\n } ${orderBy(spec, nestedAst.orderBy, lastTable)} ${limit(\n last(participatingTables)?.limit,\n format?.singular,\n )} ) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n }\n\n return sql`(\n SELECT ${toJSON(innerAlias, format?.singular)} FROM (${select(\n spec,\n relationship.subquery,\n format,\n makeCorrelator(\n spec,\n relationship.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n relationship.correlation.childField,\n ),\n )}) ${sql.ident(innerAlias)}\n ) as ${sql.ident(relationship.subquery.alias)}`;\n}\n\nfunction where(\n spec: Spec,\n condition: Condition | undefined,\n table: Table,\n): SQLQuery {\n if (!condition) {\n return sql``;\n }\n\n switch (condition.type) {\n case 'and':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' AND ',\n )})`;\n case 'or':\n return sql`(${sql.join(\n condition.conditions.map(c => where(spec, c, table)),\n ' OR ',\n )})`;\n case 'correlatedSubquery':\n if (condition.scalar) {\n return scalarSubquery(spec, condition, table);\n }\n return exists(spec, condition, table);\n case 'simple':\n return simple(spec, condition, table);\n }\n}\n\nfunction exists(\n spec: Spec,\n condition: CorrelatedSubqueryCondition,\n parentTable: Table,\n): SQLQuery {\n switch (condition.op) {\n case 'EXISTS':\n return sql`EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n case 'NOT EXISTS':\n return sql`NOT EXISTS (${select(\n spec,\n condition.related.subquery,\n undefined,\n makeCorrelator(\n spec,\n condition.related.correlation.parentField.map(f => ({\n table: parentTable,\n zql: f,\n })),\n condition.related.correlation.childField,\n ),\n )})`;\n }\n}\n\nfunction scalarSubquery(\n spec: Spec,\n condition: CorrelatedSubqueryCondition,\n parentTable: Table,\n): SQLQuery {\n const parentField = condition.related.correlation.parentField[0];\n const childField = condition.related.correlation.childField[0];\n const subqueryAST = condition.related.subquery;\n\n const parentCol = colIdent(spec.server, {\n table: parentTable,\n zql: parentField,\n });\n\n const subqueryTable = makeTable(spec, subqueryAST.table);\n const childCol = colIdent(spec.server, {\n table: subqueryTable,\n zql: childField,\n });\n\n const op = sql.__dangerous__rawValue(\n condition.op === 'EXISTS' ? '=' : 'IS NOT',\n );\n\n const subqueryWhere = subqueryAST.where\n ? sql`WHERE ${where(spec, subqueryAST.where, subqueryTable)}`\n : sql``;\n const subqueryOrderBy = orderBy(spec, subqueryAST.orderBy, subqueryTable);\n\n return sql`${parentCol} ${op} (SELECT ${childCol} FROM ${fromIdent(spec.server, subqueryTable)} ${subqueryWhere} ${subqueryOrderBy} LIMIT 1)`;\n}\n\nexport function makeCorrelator(\n spec: Spec,\n parentFields: readonly QualifiedColumn[],\n childZqlFields: readonly string[],\n): (childTable: Table) => SQLQuery {\n return (childTable: Table) => {\n const childFields = childZqlFields.map(zqlField => ({\n table: childTable,\n zql: zqlField,\n }));\n return sql.join(\n zip(parentFields, childFields).map(\n ([parentColumn, childColumn]) =>\n sql`${colIdent(spec.server, parentColumn)} = ${colIdent(\n spec.server,\n childColumn,\n )}`,\n ),\n ' AND ',\n );\n };\n}\n\nexport function simple(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n switch (condition.op) {\n case '!=':\n case '<':\n case '<=':\n case '=':\n case '>':\n case '>=':\n case 'ILIKE':\n case 'LIKE':\n case 'NOT ILIKE':\n case 'NOT LIKE':\n return sql`${valueComparison(\n spec,\n condition.left,\n table,\n condition.right,\n false,\n )} ${sql.__dangerous__rawValue(condition.op)} ${valueComparison(\n spec,\n condition.right,\n table,\n condition.left,\n false,\n )}`;\n case 'NOT IN':\n case 'IN':\n return any(spec, condition, table);\n case 'IS':\n case 'IS NOT':\n return distinctFrom(spec, condition, table);\n }\n}\n\nexport function any(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${condition.op === 'NOT IN' ? sql`NOT` : sql``}\n (\n ${valueComparison(spec, condition.left, table, condition.right, false)} = ANY \n (${valueComparison(spec, condition.right, table, condition.left, true)})\n )`;\n}\n\nexport function distinctFrom(\n spec: Spec,\n condition: SimpleCondition,\n table: Table,\n): SQLQuery {\n return sql`${valueComparison(spec, condition.left, table, condition.right, false)} ${\n condition.op === 'IS' ? sql`IS NOT DISTINCT FROM` : sql`IS DISTINCT FROM`\n } ${valueComparison(spec, condition.right, table, condition.left, false)}`;\n}\n\nfunction valueComparison(\n spec: Spec,\n valuePos: ValuePosition,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const valuePosType = valuePos.type;\n switch (valuePosType) {\n case 'column': {\n const qualified: QualifiedColumn = {\n table,\n zql: valuePos.name,\n };\n return colIdent(spec.server, qualified);\n }\n case 'literal':\n return literalValueComparison(\n spec,\n valuePos,\n table,\n otherValuePos,\n plural,\n );\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(valuePosType);\n break;\n }\n}\n\nfunction literalValueComparison(\n spec: Spec,\n valuePos: LiteralReference,\n table: Table,\n otherValuePos: ValuePosition,\n plural: boolean,\n): SQLQuery {\n const otherType = otherValuePos.type;\n switch (otherType) {\n case 'column':\n return sqlConvertColumnArg(\n getServerColumn(spec.server, table, otherValuePos.name),\n valuePos.value,\n plural,\n true,\n );\n case 'literal': {\n assert(\n plural === Array.isArray(valuePos.value),\n 'Expected plural flag to match whether value is an array',\n );\n if (Array.isArray(valuePos.value)) {\n if (valuePos.value.length > 0) {\n // If the array is non-empty base its type on its first\n // element\n return sqlConvertPluralLiteralArg(\n typeof valuePos.value[0] as PluralLiteralType,\n valuePos.value as PluralLiteralType[],\n );\n }\n // If the array is empty, base its type on the other value\n // position's type (as long as the other value position is non-null,\n // cannot have a null[]).\n if (otherValuePos.value !== null) {\n return sqlConvertPluralLiteralArg(\n typeof otherValuePos.value as PluralLiteralType,\n [],\n );\n }\n // If the other value position is null, it can be compared to any\n // type of empty array, chose 'string' arbitrarily.\n return sqlConvertPluralLiteralArg('string', []);\n }\n if (\n typeof valuePos.value === 'string' ||\n typeof valuePos.value === 'number' ||\n typeof valuePos.value === 'boolean'\n ) {\n return sqlConvertSingularLiteralArg(valuePos.value);\n }\n throw new Error(\n `Literal of unexpected type. ${valuePos.value} of type ${typeof valuePos.value}`,\n );\n }\n case 'static':\n throw new Error(\n 'Static parameters must be bound to a value before compiling to SQL',\n );\n default:\n unreachable(otherType);\n }\n}\n\nexport function makeJunctionJoin(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): {\n join: SQLQuery;\n participatingTables: ReturnType<typeof pullTablesForJunction>;\n} {\n const participatingTables = pullTablesForJunction(spec, relationship);\n const joins: SQLQuery[] = [];\n\n for (const {table} of participatingTables) {\n if (joins.length === 0) {\n joins.push(fromIdent(spec.server, table));\n continue;\n }\n joins.push(\n sql` JOIN ${fromIdent(spec.server, table)} ON ${makeCorrelator(\n spec,\n participatingTables[joins.length].correlation.parentField.map(f => ({\n table: participatingTables[joins.length - 1].table,\n zql: f,\n })),\n participatingTables[joins.length].correlation.childField,\n )(participatingTables[joins.length].table)}`,\n );\n }\n\n return {\n join: sql`${sql.join(joins, '')}`,\n participatingTables,\n // lastTable: participatingTables[participatingTables.length - 1].table,\n // lastLimit: participatingTables[participatingTables.length - 1].limit,\n };\n}\n\nexport function pullTablesForJunction(\n spec: Spec,\n relationship: CorrelatedSubquery,\n): [\n {\n table: Table;\n correlation: Correlation;\n limit: number | undefined;\n },\n {table: Table; correlation: Correlation; limit: number | undefined},\n] {\n assert(\n relationship.subquery.related?.length === 1,\n 'Too many related tables for a junction edge',\n );\n const otherRelationship = relationship.subquery.related[0];\n assert(\n !otherRelationship.hidden,\n 'Expected junction edge relationship to not be hidden',\n );\n return [\n {\n table: makeTable(spec, relationship.subquery.table),\n correlation: relationship.correlation,\n limit: relationship.subquery.limit,\n },\n {\n table: makeTable(spec, otherRelationship.subquery.table),\n correlation: otherRelationship.correlation,\n limit: otherRelationship.subquery.limit,\n },\n ];\n}\n\nfunction toJSON(table: string, singular = false): SQLQuery {\n return sql`${\n singular ? sql`` : sql`COALESCE(json_agg`\n }(row_to_json(${sql.ident(table)}))${singular ? sql`` : sql`, '[]'::json)`}`;\n}\n\nfunction selectIdent(server: ServerSpec, column: QualifiedColumn): SQLQuery {\n const serverColumnSchema =\n server.schema[server.mapper.tableName(column.table.zql)][\n server.mapper.columnName(column.table.zql, column.zql)\n ];\n const serverType = serverColumnSchema.type;\n if (!serverColumnSchema.isEnum) {\n let needsNormalization = false;\n switch (serverType) {\n case 'timestamptz':\n // @ts-expect-error Fallthrough intended\n case 'timetz':\n needsNormalization = true;\n // fallthrough\n\n case 'date':\n case 'time':\n case 'time without time zone':\n case 'time with time zone':\n case 'timestamp':\n case 'timestamp without time zone':\n case 'timestamp with time zone': {\n // EXTRACT(EPOCH FROM timetz) can be negative when the UTC offset is\n // positive (e.g. 01:00+02 = 23:00 UTC prev day = -3600s). Wrap with\n // modular arithmetic to normalize to 0..86400000.\n const toMs = (epochExpr: SQLQuery): SQLQuery =>\n needsNormalization\n ? sql`((${epochExpr})::bigint + 86400000) % 86400000`\n : epochExpr;\n\n if (serverColumnSchema.isArray) {\n return sql`ARRAY(SELECT ${toMs(\n sql`EXTRACT(EPOCH FROM unnest(${colIdent(server, column)})) * 1000`,\n )}) as ${sql.ident(column.zql)}`;\n }\n\n return sql`${toMs(\n sql`EXTRACT(EPOCH FROM ${colIdent(server, column)}) * 1000`,\n )} as ${sql.ident(column.zql)}`;\n }\n }\n }\n\n return sql`${colIdent(server, column)} as ${sql.ident(column.zql)}`;\n}\n\nfunction colIdent(server: ServerSpec, column: QualifiedColumn) {\n return sql.ident(\n column.table.alias,\n server.mapper.columnName(column.table.zql, column.zql),\n );\n}\n\nfunction fromIdent(server: ServerSpec, table: Table) {\n return sql`${sql.ident(server.mapper.tableName(table.zql))} AS ${sql.ident(table.alias)}`;\n}\n\nfunction getServerColumn(spec: ServerSpec, table: Table, zqlColumn: string) {\n return spec.schema[spec.mapper.tableName(table.zql)][\n spec.mapper.columnName(table.zql, zqlColumn)\n ];\n}\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\nexport function extractZqlResult(pgResult: Array<any>): JSONValue {\n const bigIntJson: BigIntJSONValue = parseBigIntJson(\n pgResult[0][ZQL_RESULT_KEY],\n );\n assertJSONValue(bigIntJson);\n return bigIntJson;\n}\n\nfunction assertJSONValue(v: BigIntJSONValue): asserts v is JSONValue {\n const path = findPathToBigInt(v);\n if (path) {\n throw new Error(`Value exceeds safe Number range. ${path}`);\n }\n}\n\nfunction findPathToBigInt(v: BigIntJSONValue): string | undefined {\n const typeOfV = typeof v;\n switch (typeOfV) {\n case 'bigint':\n return ` = ${v}`;\n case 'object': {\n if (v === null) {\n return;\n }\n if (Array.isArray(v)) {\n for (let i = 0; i < v.length; i++) {\n const path = findPathToBigInt(v[i]);\n if (path) {\n return `[${i}]${path}`;\n }\n }\n return undefined;\n }\n\n const o = v as Record<string, BigIntJSONValue>;\n for (const k in o) {\n if (hasOwn(o, k)) {\n const path = findPathToBigInt(o[k]);\n if (path) {\n return `['${k}']${path}`;\n }\n }\n }\n return undefined;\n }\n case 'number':\n return undefined;\n case 'boolean':\n return undefined;\n default:\n return undefined;\n }\n}\n"],"mappings":"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"}
|
package/out/z2s/src/sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../../z2s/src/sql.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAwB,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACpE,OAAO,OAAsB,MAAM,gBAAgB,CAAC;AAOpD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,uCAAuC,CAAC;AAE9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ;
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../../z2s/src/sql.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAwB,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACpE,OAAO,OAAsB,MAAM,gBAAgB,CAAC;AAOpD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,uCAAuC,CAAC;AAE9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ;UA0Q9B,MAAM;YACJ,OAAO,EAAE;EAxQlB;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,QAAQ;UAqQ7C,MAAM;YACJ,OAAO,EAAE;EAnQlB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ;UAgQlC,MAAM;YACJ,OAAO,EAAE;EA9PlB;AAID,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AACnE,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AAwB7D,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,GACtC,QAAQ,CAQV;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,iBAAiB,EAAE,GACzB,QAAQ,CAQV;AAED,wBAAgB,mBAAmB,CACjC,kBAAkB,EAAE,kBAAkB,EACtC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,OAAO,GACpB,QAAQ,CASV;AAiLD,eAAO,MAAM,GAAG,aAAkB,CAAC"}
|
package/out/z2s/src/sql.js
CHANGED
|
@@ -107,12 +107,17 @@ function createPlaceholder(index, arg) {
|
|
|
107
107
|
}
|
|
108
108
|
function formatCommonToSingularAndPlural(index, arg) {
|
|
109
109
|
const valuePlaceholder = arg.plural ? "value" : `$${index}`;
|
|
110
|
+
let atTimeZone = ` AT TIME ZONE 'UTC'`;
|
|
110
111
|
switch (arg.type) {
|
|
112
|
+
case "timestamptz":
|
|
113
|
+
case "timestamp with time zone": atTimeZone = "";
|
|
111
114
|
case "date":
|
|
112
115
|
case "timestamp":
|
|
113
|
-
case "timestamp without time zone": return `to_timestamp(${valuePlaceholder}::text::bigint / 1000.0)
|
|
114
|
-
case "
|
|
115
|
-
case "
|
|
116
|
+
case "timestamp without time zone": return `to_timestamp(${valuePlaceholder}::text::bigint / 1000.0)${atTimeZone}`;
|
|
117
|
+
case "timetz":
|
|
118
|
+
case "time with time zone": atTimeZone = "";
|
|
119
|
+
case "time":
|
|
120
|
+
case "time without time zone": return `(${valuePlaceholder}::text::int * interval'1ms')::time${atTimeZone}`;
|
|
116
121
|
case "uuid": return `${valuePlaceholder}::text::uuid`;
|
|
117
122
|
}
|
|
118
123
|
if (arg.isEnum) return `${valuePlaceholder}::text::"${arg.type}"`;
|
package/out/z2s/src/sql.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.js","names":["#seen","#size"],"sources":["../../../../z2s/src/sql.ts"],"sourcesContent":["import {\n escapePostgresIdentifier,\n escapeSQLiteIdentifier,\n} from '@databases/escape-identifier';\nimport type {FormatConfig, SQLItem, SQLQuery} from '@databases/sql';\nimport baseSql, {SQLItemType} from '@databases/sql';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n isPgNumberType,\n isPgStringType,\n} from '../../zero-cache/src/types/pg-data-type.ts';\nimport type {LiteralValue} from '../../zero-protocol/src/ast.ts';\nimport type {ServerColumnSchema} from '../../zero-types/src/server-schema.ts';\n\nexport function formatPg(sql: SQLQuery) {\n const format = new ReusingFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatPgInternalConvert(sql: SQLQuery) {\n const format = new SQLConvertFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatSqlite(sql: SQLQuery) {\n const format = new ReusingFormat(escapeSQLiteIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nconst sqlConvert = Symbol('fromJson');\n\nexport type LiteralType = 'boolean' | 'number' | 'string' | 'null';\nexport type PluralLiteralType = Exclude<LiteralType, 'null'>;\n\ntype ColumnSqlConvertArg = {\n [sqlConvert]: 'column';\n type: string;\n value: unknown;\n plural: boolean;\n isEnum: boolean;\n isComparison: boolean;\n};\n\ntype SqlConvertArg =\n | ColumnSqlConvertArg\n | {\n [sqlConvert]: 'literal';\n type: LiteralType;\n value: LiteralValue;\n plural: boolean;\n };\n\nfunction isSqlConvert(value: unknown): value is SqlConvertArg {\n return value !== null && typeof value === 'object' && sqlConvert in value;\n}\n\nexport function sqlConvertSingularLiteralArg(\n value: string | boolean | number | null,\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type: value === null ? 'null' : (typeof value as LiteralType),\n value,\n plural: false,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertPluralLiteralArg(\n type: PluralLiteralType,\n value: PluralLiteralType[],\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type,\n value,\n plural: true,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertColumnArg(\n serverColumnSchema: ServerColumnSchema,\n value: unknown,\n plural: boolean,\n isComparison: boolean,\n): SQLQuery {\n return sql.value({\n [sqlConvert]: 'column',\n type: serverColumnSchema.type,\n isEnum: serverColumnSchema.isEnum,\n value,\n plural: plural || serverColumnSchema.isArray,\n isComparison,\n });\n}\n\nclass ReusingFormat implements FormatConfig {\n readonly #seen: Map<unknown, number> = new Map();\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n if (this.#seen.has(value)) {\n return {\n placeholder: `$${this.#seen.get(value)}`,\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#seen.set(value, this.#seen.size + 1);\n return {placeholder: `$${this.#seen.size}`, value};\n };\n}\n\nfunction stringify(arg: SqlConvertArg): string | null {\n if (arg.value === null) {\n return null;\n }\n if (arg.plural) {\n return JSON.stringify(arg.value);\n }\n if (arg[sqlConvert] === 'literal' && arg.type === 'string') {\n return arg.value as unknown as string;\n }\n if (\n arg[sqlConvert] === 'column' &&\n (arg.isEnum || isPgStringType(arg.type))\n ) {\n return arg.value as string;\n }\n return JSON.stringify(arg.value);\n}\n\nclass SQLConvertFormat implements FormatConfig {\n readonly #seen: Map<unknown, Map<string, number>> = new Map();\n #size = 0;\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n assert(isSqlConvert(value), 'JsonPackedFormat can only take JsonPackArgs.');\n const byType = this.#seen.get(value.value);\n if (byType?.has(value.type)) {\n return {\n placeholder: createPlaceholder(byType.get(value.type)!, value),\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#size++;\n if (byType) {\n byType.set(value.type, this.#size);\n } else {\n this.#seen.set(value.value, new Map([[value.type, this.#size]]));\n }\n return {\n placeholder: createPlaceholder(this.#size, value),\n value: stringify(value),\n };\n };\n}\n\nfunction createPlaceholder(index: number, arg: SqlConvertArg) {\n if (arg.type === 'null') {\n assert(arg.value === null, \"Args of type 'null' must have value null\");\n assert(!arg.plural, \"Args of type 'null' must not be plural\");\n return `$${index}`;\n }\n\n if (arg[sqlConvert] === 'literal') {\n const {value} = arg;\n if (Array.isArray(value)) {\n const elType = pgTypeForLiteralType(arg.type);\n return formatPlural(index, `value::${elType}`);\n }\n return `$${index}::text::${pgTypeForLiteralType(arg.type)}`;\n }\n\n const common = formatCommonToSingularAndPlural(index, arg);\n return arg.plural ? formatPlural(index, common) : common;\n}\n\nfunction formatCommonToSingularAndPlural(\n index: number,\n arg: ColumnSqlConvertArg,\n) {\n // Ok, so what is with all the `::text` casts\n // before the final cast?\n // This is to force the statement to describe its arguments\n // as being text. Without the text cast the args are described as\n // being bool/json/numeric/whatever and the bindings try to coerce\n // the inputs to those types.\n const valuePlaceholder = arg.plural ? 'value' : `$${index}`;\n switch (arg.type) {\n case 'date':\n case 'timestamp':\n case 'timestamp without time zone':\n return `to_timestamp(${valuePlaceholder}::text::bigint / 1000.0) AT TIME ZONE 'UTC'`;\n case 'timestamptz':\n case 'timestamp with time zone':\n return `to_timestamp(${valuePlaceholder}::text::bigint / 1000.0)`;\n // uuid: cast to native uuid type for proper comparison and index usage\n case 'uuid':\n return `${valuePlaceholder}::text::uuid`;\n }\n if (arg.isEnum) {\n return `${valuePlaceholder}::text::\"${arg.type}\"`;\n }\n if (isPgStringType(arg.type)) {\n // For comparison cast to the general `text` type, not the\n // specific column type (i.e. `arg.type`), because we don't want to\n // force the value being compared to the size/max-size of the column\n // type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n if (isPgNumberType(arg.type)) {\n // For comparison cast to `double precision` which uses IEEE 754 (the same\n // representation as JavaScript numbers which will accurately\n // represent any number value from zql) not the specific column type\n // (i.e. `arg.type`), because we don't want to force the value being\n // compared to the range and precision of the column type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text::double precision`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n return `${valuePlaceholder}::text::${arg.type}`;\n}\n\nfunction formatPlural(index: number, select: string) {\n return `ARRAY(\n SELECT ${select} FROM jsonb_array_elements_text($${index}::text::jsonb)\n )`;\n}\n\nfunction pgTypeForLiteralType(type: Exclude<LiteralType, 'null'>) {\n switch (type) {\n case 'boolean':\n return 'boolean';\n case 'number':\n // `double precision` uses IEEE 754, the same representation as JavaScript\n // numbers, and so this will accurately represent any number value\n // from zql\n return 'double precision';\n case 'string':\n return 'text';\n default:\n unreachable(type);\n }\n}\n\nexport const sql = baseSql.default;\n\nconst PREVIOUSLY_SEEN_VALUE = Symbol('PREVIOUSLY_SEEN_VALUE');\n\nfunction formatFn(\n items: readonly SQLItem[],\n {escapeIdentifier, formatValue}: FormatConfig,\n): {\n text: string;\n values: unknown[];\n} {\n // Create an empty query object.\n let text = '';\n const values = [];\n\n const localIdentifiers = new Map<unknown, string>();\n\n for (const item of items) {\n switch (item.type) {\n // If this is just raw text, we add it directly to the query text.\n case SQLItemType.RAW: {\n text += item.text;\n break;\n }\n\n // If we got a value SQL item, add a placeholder and add the value to our\n // placeholder values array.\n case SQLItemType.VALUE: {\n const {placeholder, value} = formatValue(item.value, values.length);\n text += placeholder;\n if (value !== PREVIOUSLY_SEEN_VALUE) {\n values.push(value);\n }\n\n break;\n }\n\n // If we got an identifier type, escape the strings and get a local\n // identifier for non-string identifiers.\n case SQLItemType.IDENTIFIER: {\n // This is a specific addition for Zero as Zero\n // does not support dots in identifiers.\n // If a dot is found, we assume it is a namespace\n // and split the identifier into its parts.\n const names =\n item.names.length === 1 &&\n typeof item.names[0] === 'string' &&\n item.names[0].includes('.')\n ? item.names[0].split('.')\n : item.names;\n\n text += names\n .map((name): string => {\n if (typeof name === 'string') return escapeIdentifier(name);\n\n if (!localIdentifiers.has(name))\n localIdentifiers.set(name, `__local_${localIdentifiers.size}__`);\n\n return escapeIdentifier(localIdentifiers.get(name)!);\n })\n .join('.');\n break;\n }\n }\n }\n\n if (text.trim()) {\n const lines = text.split('\\n');\n const min = Math.min(\n ...lines.filter(l => l.trim() !== '').map(l => /^\\s*/.exec(l)![0].length),\n );\n if (min) {\n text = lines.map(line => line.substr(min)).join('\\n');\n }\n }\n return {\n text: text.trim(),\n values,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sql.js","names":["#seen","#size"],"sources":["../../../../z2s/src/sql.ts"],"sourcesContent":["import {\n escapePostgresIdentifier,\n escapeSQLiteIdentifier,\n} from '@databases/escape-identifier';\nimport type {FormatConfig, SQLItem, SQLQuery} from '@databases/sql';\nimport baseSql, {SQLItemType} from '@databases/sql';\nimport {assert, unreachable} from '../../shared/src/asserts.ts';\nimport {\n isPgNumberType,\n isPgStringType,\n} from '../../zero-cache/src/types/pg-data-type.ts';\nimport type {LiteralValue} from '../../zero-protocol/src/ast.ts';\nimport type {ServerColumnSchema} from '../../zero-types/src/server-schema.ts';\n\nexport function formatPg(sql: SQLQuery) {\n const format = new ReusingFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatPgInternalConvert(sql: SQLQuery) {\n const format = new SQLConvertFormat(escapePostgresIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nexport function formatSqlite(sql: SQLQuery) {\n const format = new ReusingFormat(escapeSQLiteIdentifier);\n return sql.format((items: readonly SQLItem[]) => formatFn(items, format));\n}\n\nconst sqlConvert = Symbol('fromJson');\n\nexport type LiteralType = 'boolean' | 'number' | 'string' | 'null';\nexport type PluralLiteralType = Exclude<LiteralType, 'null'>;\n\ntype ColumnSqlConvertArg = {\n [sqlConvert]: 'column';\n type: string;\n value: unknown;\n plural: boolean;\n isEnum: boolean;\n isComparison: boolean;\n};\n\ntype SqlConvertArg =\n | ColumnSqlConvertArg\n | {\n [sqlConvert]: 'literal';\n type: LiteralType;\n value: LiteralValue;\n plural: boolean;\n };\n\nfunction isSqlConvert(value: unknown): value is SqlConvertArg {\n return value !== null && typeof value === 'object' && sqlConvert in value;\n}\n\nexport function sqlConvertSingularLiteralArg(\n value: string | boolean | number | null,\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type: value === null ? 'null' : (typeof value as LiteralType),\n value,\n plural: false,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertPluralLiteralArg(\n type: PluralLiteralType,\n value: PluralLiteralType[],\n): SQLQuery {\n const arg: SqlConvertArg = {\n [sqlConvert]: 'literal',\n type,\n value,\n plural: true,\n };\n return sql.value(arg);\n}\n\nexport function sqlConvertColumnArg(\n serverColumnSchema: ServerColumnSchema,\n value: unknown,\n plural: boolean,\n isComparison: boolean,\n): SQLQuery {\n return sql.value({\n [sqlConvert]: 'column',\n type: serverColumnSchema.type,\n isEnum: serverColumnSchema.isEnum,\n value,\n plural: plural || serverColumnSchema.isArray,\n isComparison,\n });\n}\n\nclass ReusingFormat implements FormatConfig {\n readonly #seen: Map<unknown, number> = new Map();\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n if (this.#seen.has(value)) {\n return {\n placeholder: `$${this.#seen.get(value)}`,\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#seen.set(value, this.#seen.size + 1);\n return {placeholder: `$${this.#seen.size}`, value};\n };\n}\n\nfunction stringify(arg: SqlConvertArg): string | null {\n if (arg.value === null) {\n return null;\n }\n if (arg.plural) {\n return JSON.stringify(arg.value);\n }\n if (arg[sqlConvert] === 'literal' && arg.type === 'string') {\n return arg.value as unknown as string;\n }\n if (\n arg[sqlConvert] === 'column' &&\n (arg.isEnum || isPgStringType(arg.type))\n ) {\n return arg.value as string;\n }\n return JSON.stringify(arg.value);\n}\n\nclass SQLConvertFormat implements FormatConfig {\n readonly #seen: Map<unknown, Map<string, number>> = new Map();\n #size = 0;\n readonly escapeIdentifier: (str: string) => string;\n\n constructor(escapeIdentifier: (str: string) => string) {\n this.escapeIdentifier = escapeIdentifier;\n }\n\n formatValue = (value: unknown) => {\n assert(isSqlConvert(value), 'JsonPackedFormat can only take JsonPackArgs.');\n const byType = this.#seen.get(value.value);\n if (byType?.has(value.type)) {\n return {\n placeholder: createPlaceholder(byType.get(value.type)!, value),\n value: PREVIOUSLY_SEEN_VALUE,\n };\n }\n this.#size++;\n if (byType) {\n byType.set(value.type, this.#size);\n } else {\n this.#seen.set(value.value, new Map([[value.type, this.#size]]));\n }\n return {\n placeholder: createPlaceholder(this.#size, value),\n value: stringify(value),\n };\n };\n}\n\nfunction createPlaceholder(index: number, arg: SqlConvertArg) {\n if (arg.type === 'null') {\n assert(arg.value === null, \"Args of type 'null' must have value null\");\n assert(!arg.plural, \"Args of type 'null' must not be plural\");\n return `$${index}`;\n }\n\n if (arg[sqlConvert] === 'literal') {\n const {value} = arg;\n if (Array.isArray(value)) {\n const elType = pgTypeForLiteralType(arg.type);\n return formatPlural(index, `value::${elType}`);\n }\n return `$${index}::text::${pgTypeForLiteralType(arg.type)}`;\n }\n\n const common = formatCommonToSingularAndPlural(index, arg);\n return arg.plural ? formatPlural(index, common) : common;\n}\n\nfunction formatCommonToSingularAndPlural(\n index: number,\n arg: ColumnSqlConvertArg,\n) {\n // Ok, so what is with all the `::text` casts\n // before the final cast?\n // This is to force the statement to describe its arguments\n // as being text. Without the text cast the args are described as\n // being bool/json/numeric/whatever and the bindings try to coerce\n // the inputs to those types.\n const valuePlaceholder = arg.plural ? 'value' : `$${index}`;\n let atTimeZone = ` AT TIME ZONE 'UTC'`;\n switch (arg.type) {\n case 'timestamptz':\n // @ts-expect-error Fallthrough intended\n case 'timestamp with time zone':\n atTimeZone = '';\n // fallthrough\n\n case 'date':\n case 'timestamp':\n case 'timestamp without time zone':\n return `to_timestamp(${valuePlaceholder}::text::bigint / 1000.0)${atTimeZone}`;\n\n case 'timetz':\n // @ts-expect-error Fallthrough intended\n case 'time with time zone':\n atTimeZone = '';\n // fallthrough\n\n case 'time':\n case 'time without time zone':\n return `(${valuePlaceholder}::text::int * interval'1ms')::time${atTimeZone}`;\n\n // uuid: cast to native uuid type for proper comparison and index usage\n case 'uuid':\n return `${valuePlaceholder}::text::uuid`;\n }\n if (arg.isEnum) {\n return `${valuePlaceholder}::text::\"${arg.type}\"`;\n }\n if (isPgStringType(arg.type)) {\n // For comparison cast to the general `text` type, not the\n // specific column type (i.e. `arg.type`), because we don't want to\n // force the value being compared to the size/max-size of the column\n // type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n if (isPgNumberType(arg.type)) {\n // For comparison cast to `double precision` which uses IEEE 754 (the same\n // representation as JavaScript numbers which will accurately\n // represent any number value from zql) not the specific column type\n // (i.e. `arg.type`), because we don't want to force the value being\n // compared to the range and precision of the column type before comparison.\n return arg.isComparison\n ? `${valuePlaceholder}::text::double precision`\n : `${valuePlaceholder}::text::${arg.type}`;\n }\n return `${valuePlaceholder}::text::${arg.type}`;\n}\n\nfunction formatPlural(index: number, select: string) {\n return `ARRAY(\n SELECT ${select} FROM jsonb_array_elements_text($${index}::text::jsonb)\n )`;\n}\n\nfunction pgTypeForLiteralType(type: Exclude<LiteralType, 'null'>) {\n switch (type) {\n case 'boolean':\n return 'boolean';\n case 'number':\n // `double precision` uses IEEE 754, the same representation as JavaScript\n // numbers, and so this will accurately represent any number value\n // from zql\n return 'double precision';\n case 'string':\n return 'text';\n default:\n unreachable(type);\n }\n}\n\nexport const sql = baseSql.default;\n\nconst PREVIOUSLY_SEEN_VALUE = Symbol('PREVIOUSLY_SEEN_VALUE');\n\nfunction formatFn(\n items: readonly SQLItem[],\n {escapeIdentifier, formatValue}: FormatConfig,\n): {\n text: string;\n values: unknown[];\n} {\n // Create an empty query object.\n let text = '';\n const values = [];\n\n const localIdentifiers = new Map<unknown, string>();\n\n for (const item of items) {\n switch (item.type) {\n // If this is just raw text, we add it directly to the query text.\n case SQLItemType.RAW: {\n text += item.text;\n break;\n }\n\n // If we got a value SQL item, add a placeholder and add the value to our\n // placeholder values array.\n case SQLItemType.VALUE: {\n const {placeholder, value} = formatValue(item.value, values.length);\n text += placeholder;\n if (value !== PREVIOUSLY_SEEN_VALUE) {\n values.push(value);\n }\n\n break;\n }\n\n // If we got an identifier type, escape the strings and get a local\n // identifier for non-string identifiers.\n case SQLItemType.IDENTIFIER: {\n // This is a specific addition for Zero as Zero\n // does not support dots in identifiers.\n // If a dot is found, we assume it is a namespace\n // and split the identifier into its parts.\n const names =\n item.names.length === 1 &&\n typeof item.names[0] === 'string' &&\n item.names[0].includes('.')\n ? item.names[0].split('.')\n : item.names;\n\n text += names\n .map((name): string => {\n if (typeof name === 'string') return escapeIdentifier(name);\n\n if (!localIdentifiers.has(name))\n localIdentifiers.set(name, `__local_${localIdentifiers.size}__`);\n\n return escapeIdentifier(localIdentifiers.get(name)!);\n })\n .join('.');\n break;\n }\n }\n }\n\n if (text.trim()) {\n const lines = text.split('\\n');\n const min = Math.min(\n ...lines.filter(l => l.trim() !== '').map(l => /^\\s*/.exec(l)![0].length),\n );\n if (min) {\n text = lines.map(line => line.substr(min)).join('\\n');\n }\n }\n return {\n text: text.trim(),\n values,\n };\n}\n"],"mappings":"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"}
|
package/out/zero/package.js
CHANGED
package/out/zero/package.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"0.26.2-canary.
|
|
1
|
+
{"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"0.26.2-canary.6\",\n \"description\": \"Zero is a web framework for serverless web development.\",\n \"author\": \"Rocicorp, Inc.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rocicorp/mono.git\",\n \"directory\": \"packages/zero\"\n },\n \"license\": \"Apache-2.0\",\n \"homepage\": \"https://zero.rocicorp.dev\",\n \"bugs\": {\n \"url\": \"https://bugs.rocicorp.dev\"\n },\n \"scripts\": {\n \"build\": \"node --experimental-strip-types --no-warnings tool/build.ts\",\n \"build:watch\": \"node --experimental-strip-types --no-warnings tool/build.ts --watch\",\n \"check-types\": \"tsc -p tsconfig.client.json && tsc -p tsconfig.server.json\",\n \"check-types:client:watch\": \"tsc -p tsconfig.client.json --watch\",\n \"check-types:server:watch\": \"tsc -p tsconfig.server.json --watch\",\n \"format\": \"prettier --write .\",\n \"check-format\": \"prettier --check .\",\n \"lint\": \"oxlint --type-aware src/\",\n \"docs\": \"node --experimental-strip-types --no-warnings tool/generate-docs.ts\",\n \"docs:server\": \"node --watch --experimental-strip-types --no-warnings tool/generate-docs.ts --server\"\n },\n \"dependencies\": {\n \"@badrap/valita\": \"0.3.11\",\n \"@databases/escape-identifier\": \"^1.0.3\",\n \"@databases/sql\": \"^3.3.0\",\n \"@dotenvx/dotenvx\": \"^1.39.0\",\n \"@drdgvhbh/postgres-error-codes\": \"^0.0.6\",\n \"@fastify/cors\": \"^10.0.0\",\n \"@fastify/websocket\": \"^11.0.0\",\n \"@google-cloud/precise-date\": \"^4.0.0\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/api-logs\": \"^0.203.0\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.62.0\",\n \"@opentelemetry/exporter-metrics-otlp-http\": \"^0.203.0\",\n \"@opentelemetry/resources\": \"^2.0.1\",\n \"@opentelemetry/sdk-metrics\": \"^2.0.1\",\n \"@opentelemetry/sdk-node\": \"^0.203.0\",\n \"@opentelemetry/sdk-trace-node\": \"^2.0.1\",\n \"@postgresql-typed/oids\": \"^0.2.0\",\n \"@rocicorp/lock\": \"^1.0.4\",\n \"@rocicorp/logger\": \"^5.4.0\",\n \"@rocicorp/resolver\": \"^1.0.2\",\n \"@rocicorp/zero-sqlite3\": \"^1.0.15\",\n \"@standard-schema/spec\": \"^1.0.0\",\n \"@types/basic-auth\": \"^1.1.8\",\n \"@types/ws\": \"^8.5.12\",\n \"basic-auth\": \"^2.0.1\",\n \"chalk\": \"^5.3.0\",\n \"chalk-template\": \"^1.1.0\",\n \"chokidar\": \"^4.0.1\",\n \"cloudevents\": \"^10.0.0\",\n \"command-line-args\": \"^6.0.1\",\n \"command-line-usage\": \"^7.0.3\",\n \"compare-utf8\": \"^0.1.1\",\n \"defu\": \"^6.1.4\",\n \"eventemitter3\": \"^5.0.1\",\n \"fastify\": \"^5.0.0\",\n \"is-in-subnet\": \"^4.0.1\",\n \"jose\": \"^5.9.3\",\n \"js-xxhash\": \"^4.0.0\",\n \"json-custom-numbers\": \"^3.1.1\",\n \"kasi\": \"^1.1.0\",\n \"nanoid\": \"^5.1.2\",\n \"parse-prometheus-text-format\": \"^1.1.1\",\n \"pg-format\": \"npm:pg-format-fix@^1.0.5\",\n \"postgres\": \"3.4.7\",\n \"prettier\": \"^3.8.1\",\n \"semver\": \"^7.5.4\",\n \"tsx\": \"^4.21.0\",\n \"url-pattern\": \"^1.0.3\",\n \"urlpattern-polyfill\": \"^10.1.0\",\n \"ws\": \"^8.18.1\"\n },\n \"devDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"@vitest/runner\": \"4.1.0\",\n \"analyze-query\": \"0.0.0\",\n \"ast-to-zql\": \"0.0.0\",\n \"expo-sqlite\": \">=15\",\n \"replicache\": \"15.2.1\",\n \"shared\": \"0.0.0\",\n \"typedoc\": \"^0.28.17\",\n \"typedoc-plugin-markdown\": \"^4.10.0\",\n \"typescript\": \"~5.9.3\",\n \"vite\": \"8.0.0\",\n \"vitest\": \"4.1.0\",\n \"zero-cache\": \"0.0.0\",\n \"zero-client\": \"0.0.0\",\n \"zero-pg\": \"0.0.0\",\n \"zero-protocol\": \"0.0.0\",\n \"zero-react\": \"0.0.0\",\n \"zero-server\": \"0.0.0\",\n \"zero-solid\": \"0.0.0\",\n \"zqlite\": \"0.0.0\"\n },\n \"peerDependencies\": {\n \"expo-sqlite\": \">=15\",\n \"@op-engineering/op-sqlite\": \">=15\"\n },\n \"peerDependenciesMeta\": {\n \"expo-sqlite\": {\n \"optional\": true\n },\n \"@op-engineering/op-sqlite\": {\n \"optional\": true\n }\n },\n \"type\": \"module\",\n \"main\": \"out/zero/src/zero.js\",\n \"module\": \"out/zero/src/zero.js\",\n \"types\": \"out/zero/src/zero.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./out/zero/src/zero.d.ts\",\n \"default\": \"./out/zero/src/zero.js\"\n },\n \"./bindings\": {\n \"types\": \"./out/zero/src/bindings.d.ts\",\n \"default\": \"./out/zero/src/bindings.js\"\n },\n \"./change-protocol/v0\": {\n \"types\": \"./out/zero/src/change-protocol/v0.d.ts\",\n \"default\": \"./out/zero/src/change-protocol/v0.js\"\n },\n \"./expo-sqlite\": {\n \"types\": \"./out/zero/src/expo-sqlite.d.ts\",\n \"default\": \"./out/zero/src/expo-sqlite.js\"\n },\n \"./op-sqlite\": {\n \"types\": \"./out/zero/src/op-sqlite.d.ts\",\n \"default\": \"./out/zero/src/op-sqlite.js\"\n },\n \"./pg\": {\n \"types\": \"./out/zero/src/pg.d.ts\",\n \"default\": \"./out/zero/src/pg.js\"\n },\n \"./react\": {\n \"types\": \"./out/zero/src/react.d.ts\",\n \"default\": \"./out/zero/src/react.js\"\n },\n \"./react-native\": {\n \"types\": \"./out/zero/src/react-native.d.ts\",\n \"default\": \"./out/zero/src/react-native.js\"\n },\n \"./server\": {\n \"types\": \"./out/zero/src/server.d.ts\",\n \"default\": \"./out/zero/src/server.js\"\n },\n \"./server/adapters/drizzle\": {\n \"types\": \"./out/zero/src/adapters/drizzle.d.ts\",\n \"default\": \"./out/zero/src/adapters/drizzle.js\"\n },\n \"./server/adapters/prisma\": {\n \"types\": \"./out/zero/src/adapters/prisma.d.ts\",\n \"default\": \"./out/zero/src/adapters/prisma.js\"\n },\n \"./server/adapters/pg\": {\n \"types\": \"./out/zero/src/adapters/pg.d.ts\",\n \"default\": \"./out/zero/src/adapters/pg.js\"\n },\n \"./server/adapters/postgresjs\": {\n \"types\": \"./out/zero/src/adapters/postgresjs.d.ts\",\n \"default\": \"./out/zero/src/adapters/postgresjs.js\"\n },\n \"./solid\": {\n \"types\": \"./out/zero/src/solid.d.ts\",\n \"default\": \"./out/zero/src/solid.js\"\n },\n \"./sqlite\": {\n \"types\": \"./out/zero/src/sqlite.d.ts\",\n \"default\": \"./out/zero/src/sqlite.js\"\n },\n \"./zqlite\": {\n \"types\": \"./out/zero/src/zqlite.d.ts\",\n \"default\": \"./out/zero/src/zqlite.js\"\n }\n },\n \"bin\": {\n \"zero-build-schema\": \"./out/zero/src/build-schema.js\",\n \"zero-cache\": \"./out/zero/src/cli.js\",\n \"zero-cache-dev\": \"./out/zero/src/zero-cache-dev.js\",\n \"zero-deploy-permissions\": \"./out/zero/src/deploy-permissions.js\",\n \"zero-out\": \"./out/zero/src/zero-out.js\",\n \"ast-to-zql\": \"./out/zero/src/ast-to-zql.js\",\n \"analyze-query\": \"./out/zero/src/analyze-query.js\",\n \"transform-query\": \"./out/zero/src/transform-query.js\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"files\": [\n \"out\",\n \"!*.tsbuildinfo\"\n ]\n}"],"mappings":""}
|
|
@@ -12,7 +12,7 @@ import { AutoResetSignal } from "../../change-streamer/schema/tables.js";
|
|
|
12
12
|
import { ChangeProcessor } from "../../replicator/change-processor.js";
|
|
13
13
|
import { ReplicationStatusPublisher } from "../../replicator/replication-status.js";
|
|
14
14
|
import { initReplica } from "../common/replica-schema.js";
|
|
15
|
-
import { WebSocket } from "ws";
|
|
15
|
+
import { WebSocket as WebSocket$1 } from "ws";
|
|
16
16
|
//#region ../zero-cache/src/services/change-source/custom/change-source.ts
|
|
17
17
|
/**
|
|
18
18
|
* Initializes a Custom change source before streaming changes from the
|
|
@@ -63,7 +63,7 @@ var CustomChangeSource = class {
|
|
|
63
63
|
url.searchParams.set("lastWatermark", clientWatermark);
|
|
64
64
|
url.searchParams.set("replicaVersion", replicaVersion);
|
|
65
65
|
}
|
|
66
|
-
const ws = new WebSocket(url);
|
|
66
|
+
const ws = new WebSocket$1(url);
|
|
67
67
|
const { instream, outstream } = stream(this.#lc, ws, changeStreamMessageSchema, { coalesce: (curr) => curr });
|
|
68
68
|
return {
|
|
69
69
|
changes: instream,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-source.js","names":["#lc","#upstreamUri","#shard","#replicationConfig","#startStream"],"sources":["../../../../../../../zero-cache/src/services/change-source/custom/change-source.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {WebSocket} from 'ws';\nimport {assert, unreachable} from '../../../../../shared/src/asserts.ts';\nimport {\n stringify,\n type JSONObject,\n} from '../../../../../shared/src/bigint-json.ts';\nimport {deepEqual} from '../../../../../shared/src/json.ts';\nimport type {SchemaValue} from '../../../../../zero-schema/src/table-schema.ts';\nimport {Database} from '../../../../../zqlite/src/db.ts';\nimport {computeZqlSpecs} from '../../../db/lite-tables.ts';\nimport {StatementRunner} from '../../../db/statements.ts';\nimport type {ShardConfig, ShardID} from '../../../types/shards.ts';\nimport {stream} from '../../../types/streams.ts';\nimport {\n AutoResetSignal,\n type ReplicationConfig,\n} from '../../change-streamer/schema/tables.ts';\nimport {ChangeProcessor} from '../../replicator/change-processor.ts';\nimport {ReplicationStatusPublisher} from '../../replicator/replication-status.ts';\nimport {\n createReplicationStateTables,\n getSubscriptionState,\n initReplicationState,\n type SubscriptionState,\n} from '../../replicator/schema/replication-state.ts';\nimport type {ChangeSource, ChangeStream} from '../change-source.ts';\nimport {initReplica} from '../common/replica-schema.ts';\nimport {changeStreamMessageSchema} from '../protocol/current/downstream.ts';\nimport {\n type BackfillRequest,\n type ChangeSourceUpstream,\n} from '../protocol/current/upstream.ts';\n\n/** Server context to store with the initial sync metadata for debugging. */\nexport type ServerContext = JSONObject;\n\n/**\n * Initializes a Custom change source before streaming changes from the\n * corresponding logical replication stream.\n */\nexport async function initializeCustomChangeSource(\n lc: LogContext,\n upstreamURI: string,\n shard: ShardConfig,\n replicaDbFile: string,\n context: ServerContext,\n): Promise<{subscriptionState: SubscriptionState; changeSource: ChangeSource}> {\n await initReplica(\n lc,\n `replica-${shard.appID}-${shard.shardNum}`,\n replicaDbFile,\n (log, tx) => initialSync(log, shard, tx, upstreamURI, context),\n );\n\n const replica = new Database(lc, replicaDbFile);\n const subscriptionState = getSubscriptionState(new StatementRunner(replica));\n replica.close();\n\n if (shard.publications.length) {\n // Verify that the publications match what has been synced.\n const requested = [...shard.publications].sort();\n const replicated = subscriptionState.publications.sort();\n if (!deepEqual(requested, replicated)) {\n throw new Error(\n `Invalid ShardConfig. Requested publications [${requested}] do not match synced publications: [${replicated}]`,\n );\n }\n }\n\n const changeSource = new CustomChangeSource(\n lc,\n upstreamURI,\n shard,\n subscriptionState,\n );\n\n return {subscriptionState, changeSource};\n}\n\nclass CustomChangeSource implements ChangeSource {\n readonly #lc: LogContext;\n readonly #upstreamUri: string;\n readonly #shard: ShardID;\n readonly #replicationConfig: ReplicationConfig;\n\n constructor(\n lc: LogContext,\n upstreamUri: string,\n shard: ShardID,\n replicationConfig: ReplicationConfig,\n ) {\n this.#lc = lc.withContext('component', 'change-source');\n this.#upstreamUri = upstreamUri;\n this.#shard = shard;\n this.#replicationConfig = replicationConfig;\n }\n\n initialSync(): ChangeStream {\n return this.#startStream();\n }\n\n startStream(\n clientWatermark: string,\n backfillRequests: BackfillRequest[] = [],\n ): Promise<ChangeStream> {\n if (backfillRequests?.length) {\n throw new Error(\n 'backfill is yet not supported for custom change sources',\n );\n }\n return Promise.resolve(this.#startStream(clientWatermark));\n }\n\n #startStream(clientWatermark?: string): ChangeStream {\n const {publications, replicaVersion} = this.#replicationConfig;\n const {appID, shardNum} = this.#shard;\n const url = new URL(this.#upstreamUri);\n url.searchParams.set('appID', appID);\n url.searchParams.set('shardNum', String(shardNum));\n for (const pub of publications) {\n url.searchParams.append('publications', pub);\n }\n if (clientWatermark) {\n assert(\n replicaVersion.length,\n 'replicaVersion is required when clientWatermark is set',\n );\n url.searchParams.set('lastWatermark', clientWatermark);\n url.searchParams.set('replicaVersion', replicaVersion);\n }\n\n const ws = new WebSocket(url);\n const {instream, outstream} = stream(\n this.#lc,\n ws,\n changeStreamMessageSchema,\n // Upstream acks coalesce. If upstream exhibits back-pressure,\n // only the last ACK is kept / buffered.\n {coalesce: (curr: ChangeSourceUpstream) => curr},\n );\n return {changes: instream, acks: outstream};\n }\n}\n\n/**\n * Initial sync for a custom change source makes a request to the\n * change source endpoint with no `replicaVersion` or `lastWatermark`.\n * The initial transaction returned by the endpoint is treated as\n * the initial sync, and the commit watermark of that transaction\n * becomes the `replicaVersion` of the initialized replica.\n *\n * Note that this is equivalent to how the LSN of the Postgres WAL\n * at initial sync time is the `replicaVersion` (and starting\n * version for all initially-synced rows).\n */\nexport async function initialSync(\n lc: LogContext,\n shard: ShardConfig,\n tx: Database,\n upstreamURI: string,\n context: ServerContext,\n) {\n const {appID: id, publications} = shard;\n const changeSource = new CustomChangeSource(lc, upstreamURI, shard, {\n replicaVersion: '', // ignored for initialSync()\n publications,\n });\n const {changes} = changeSource.initialSync();\n\n createReplicationStateTables(tx);\n const processor = new ChangeProcessor(\n new StatementRunner(tx),\n 'initial-sync',\n (_, err) => {\n throw err;\n },\n );\n\n const statusPublisher = new ReplicationStatusPublisher(tx);\n try {\n let num = 0;\n for await (const change of changes) {\n const [tag] = change;\n switch (tag) {\n case 'begin': {\n const {commitWatermark} = change[2];\n lc.info?.(\n `initial sync of shard ${id} at replicaVersion ${commitWatermark}`,\n );\n statusPublisher.publish(\n lc,\n 'Initializing',\n `Copying upstream tables at version ${commitWatermark}`,\n 5000,\n );\n initReplicationState(\n tx,\n [...publications].sort(),\n commitWatermark,\n context,\n false,\n );\n processor.processMessage(lc, change);\n break;\n }\n case 'data':\n processor.processMessage(lc, change);\n if (++num % 1000 === 0) {\n lc.debug?.(`processed ${num} changes`);\n }\n break;\n case 'commit':\n processor.processMessage(lc, change);\n validateInitiallySyncedData(lc, tx, shard);\n lc.info?.(`finished initial-sync of ${num} changes`);\n return;\n\n case 'status':\n break; // Ignored\n // @ts-expect-error: falls through if the tag is not 'reset-required\n case 'control': {\n const {tag, message} = change[1];\n if (tag === 'reset-required') {\n throw new AutoResetSignal(\n message ?? 'auto-reset signaled by change source',\n );\n }\n }\n // falls through\n case 'rollback':\n throw new Error(\n `unexpected message during initial-sync: ${stringify(change)}`,\n );\n default:\n unreachable(change);\n }\n }\n throw new Error(\n `change source ${upstreamURI} closed before initial-sync completed`,\n );\n } catch (e) {\n await statusPublisher.publishAndThrowError(lc, 'Initializing', e);\n } finally {\n statusPublisher.stop();\n }\n}\n\n// Verify that the upstream tables expected by the sync logic\n// have been properly initialized.\nfunction getRequiredTables({\n appID,\n shardNum,\n}: ShardID): Record<string, Record<string, SchemaValue>> {\n return {\n [`${appID}_${shardNum}.clients`]: {\n clientGroupID: {type: 'string'},\n clientID: {type: 'string'},\n lastMutationID: {type: 'number'},\n userID: {type: 'string'},\n },\n [`${appID}_${shardNum}.mutations`]: {\n clientGroupID: {type: 'string'},\n clientID: {type: 'string'},\n mutationID: {type: 'number'},\n mutation: {type: 'json'},\n },\n [`${appID}.permissions`]: {\n permissions: {type: 'json'},\n hash: {type: 'string'},\n },\n };\n}\n\nfunction validateInitiallySyncedData(\n lc: LogContext,\n db: Database,\n shard: ShardID,\n) {\n const tables = computeZqlSpecs(lc, db, {includeBackfillingColumns: true});\n const required = getRequiredTables(shard);\n for (const [name, columns] of Object.entries(required)) {\n const table = tables.get(name)?.zqlSpec;\n if (!table) {\n throw new Error(\n `Upstream is missing the \"${name}\" table. (Found ${[\n ...tables.keys(),\n ]})` +\n `Please ensure that each table has a unique index over one ` +\n `or more non-null columns.`,\n );\n }\n for (const [col, {type}] of Object.entries(columns)) {\n const found = table[col];\n if (!found) {\n throw new Error(\n `Upstream \"${table}\" table is missing the \"${col}\" column`,\n );\n }\n if (found.type !== type) {\n throw new Error(\n `Upstream \"${table}.${col}\" column is a ${found.type} type but must be a ${type} type.`,\n );\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"change-source.js","names":["#lc","#upstreamUri","#shard","#replicationConfig","#startStream"],"sources":["../../../../../../../zero-cache/src/services/change-source/custom/change-source.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {WebSocket} from 'ws';\nimport {assert, unreachable} from '../../../../../shared/src/asserts.ts';\nimport {\n stringify,\n type JSONObject,\n} from '../../../../../shared/src/bigint-json.ts';\nimport {deepEqual} from '../../../../../shared/src/json.ts';\nimport type {SchemaValue} from '../../../../../zero-schema/src/table-schema.ts';\nimport {Database} from '../../../../../zqlite/src/db.ts';\nimport {computeZqlSpecs} from '../../../db/lite-tables.ts';\nimport {StatementRunner} from '../../../db/statements.ts';\nimport type {ShardConfig, ShardID} from '../../../types/shards.ts';\nimport {stream} from '../../../types/streams.ts';\nimport {\n AutoResetSignal,\n type ReplicationConfig,\n} from '../../change-streamer/schema/tables.ts';\nimport {ChangeProcessor} from '../../replicator/change-processor.ts';\nimport {ReplicationStatusPublisher} from '../../replicator/replication-status.ts';\nimport {\n createReplicationStateTables,\n getSubscriptionState,\n initReplicationState,\n type SubscriptionState,\n} from '../../replicator/schema/replication-state.ts';\nimport type {ChangeSource, ChangeStream} from '../change-source.ts';\nimport {initReplica} from '../common/replica-schema.ts';\nimport {changeStreamMessageSchema} from '../protocol/current/downstream.ts';\nimport {\n type BackfillRequest,\n type ChangeSourceUpstream,\n} from '../protocol/current/upstream.ts';\n\n/** Server context to store with the initial sync metadata for debugging. */\nexport type ServerContext = JSONObject;\n\n/**\n * Initializes a Custom change source before streaming changes from the\n * corresponding logical replication stream.\n */\nexport async function initializeCustomChangeSource(\n lc: LogContext,\n upstreamURI: string,\n shard: ShardConfig,\n replicaDbFile: string,\n context: ServerContext,\n): Promise<{subscriptionState: SubscriptionState; changeSource: ChangeSource}> {\n await initReplica(\n lc,\n `replica-${shard.appID}-${shard.shardNum}`,\n replicaDbFile,\n (log, tx) => initialSync(log, shard, tx, upstreamURI, context),\n );\n\n const replica = new Database(lc, replicaDbFile);\n const subscriptionState = getSubscriptionState(new StatementRunner(replica));\n replica.close();\n\n if (shard.publications.length) {\n // Verify that the publications match what has been synced.\n const requested = [...shard.publications].sort();\n const replicated = subscriptionState.publications.sort();\n if (!deepEqual(requested, replicated)) {\n throw new Error(\n `Invalid ShardConfig. Requested publications [${requested}] do not match synced publications: [${replicated}]`,\n );\n }\n }\n\n const changeSource = new CustomChangeSource(\n lc,\n upstreamURI,\n shard,\n subscriptionState,\n );\n\n return {subscriptionState, changeSource};\n}\n\nclass CustomChangeSource implements ChangeSource {\n readonly #lc: LogContext;\n readonly #upstreamUri: string;\n readonly #shard: ShardID;\n readonly #replicationConfig: ReplicationConfig;\n\n constructor(\n lc: LogContext,\n upstreamUri: string,\n shard: ShardID,\n replicationConfig: ReplicationConfig,\n ) {\n this.#lc = lc.withContext('component', 'change-source');\n this.#upstreamUri = upstreamUri;\n this.#shard = shard;\n this.#replicationConfig = replicationConfig;\n }\n\n initialSync(): ChangeStream {\n return this.#startStream();\n }\n\n startStream(\n clientWatermark: string,\n backfillRequests: BackfillRequest[] = [],\n ): Promise<ChangeStream> {\n if (backfillRequests?.length) {\n throw new Error(\n 'backfill is yet not supported for custom change sources',\n );\n }\n return Promise.resolve(this.#startStream(clientWatermark));\n }\n\n #startStream(clientWatermark?: string): ChangeStream {\n const {publications, replicaVersion} = this.#replicationConfig;\n const {appID, shardNum} = this.#shard;\n const url = new URL(this.#upstreamUri);\n url.searchParams.set('appID', appID);\n url.searchParams.set('shardNum', String(shardNum));\n for (const pub of publications) {\n url.searchParams.append('publications', pub);\n }\n if (clientWatermark) {\n assert(\n replicaVersion.length,\n 'replicaVersion is required when clientWatermark is set',\n );\n url.searchParams.set('lastWatermark', clientWatermark);\n url.searchParams.set('replicaVersion', replicaVersion);\n }\n\n const ws = new WebSocket(url);\n const {instream, outstream} = stream(\n this.#lc,\n ws,\n changeStreamMessageSchema,\n // Upstream acks coalesce. If upstream exhibits back-pressure,\n // only the last ACK is kept / buffered.\n {coalesce: (curr: ChangeSourceUpstream) => curr},\n );\n return {changes: instream, acks: outstream};\n }\n}\n\n/**\n * Initial sync for a custom change source makes a request to the\n * change source endpoint with no `replicaVersion` or `lastWatermark`.\n * The initial transaction returned by the endpoint is treated as\n * the initial sync, and the commit watermark of that transaction\n * becomes the `replicaVersion` of the initialized replica.\n *\n * Note that this is equivalent to how the LSN of the Postgres WAL\n * at initial sync time is the `replicaVersion` (and starting\n * version for all initially-synced rows).\n */\nexport async function initialSync(\n lc: LogContext,\n shard: ShardConfig,\n tx: Database,\n upstreamURI: string,\n context: ServerContext,\n) {\n const {appID: id, publications} = shard;\n const changeSource = new CustomChangeSource(lc, upstreamURI, shard, {\n replicaVersion: '', // ignored for initialSync()\n publications,\n });\n const {changes} = changeSource.initialSync();\n\n createReplicationStateTables(tx);\n const processor = new ChangeProcessor(\n new StatementRunner(tx),\n 'initial-sync',\n (_, err) => {\n throw err;\n },\n );\n\n const statusPublisher = new ReplicationStatusPublisher(tx);\n try {\n let num = 0;\n for await (const change of changes) {\n const [tag] = change;\n switch (tag) {\n case 'begin': {\n const {commitWatermark} = change[2];\n lc.info?.(\n `initial sync of shard ${id} at replicaVersion ${commitWatermark}`,\n );\n statusPublisher.publish(\n lc,\n 'Initializing',\n `Copying upstream tables at version ${commitWatermark}`,\n 5000,\n );\n initReplicationState(\n tx,\n [...publications].sort(),\n commitWatermark,\n context,\n false,\n );\n processor.processMessage(lc, change);\n break;\n }\n case 'data':\n processor.processMessage(lc, change);\n if (++num % 1000 === 0) {\n lc.debug?.(`processed ${num} changes`);\n }\n break;\n case 'commit':\n processor.processMessage(lc, change);\n validateInitiallySyncedData(lc, tx, shard);\n lc.info?.(`finished initial-sync of ${num} changes`);\n return;\n\n case 'status':\n break; // Ignored\n // @ts-expect-error: falls through if the tag is not 'reset-required\n case 'control': {\n const {tag, message} = change[1];\n if (tag === 'reset-required') {\n throw new AutoResetSignal(\n message ?? 'auto-reset signaled by change source',\n );\n }\n }\n // falls through\n case 'rollback':\n throw new Error(\n `unexpected message during initial-sync: ${stringify(change)}`,\n );\n default:\n unreachable(change);\n }\n }\n throw new Error(\n `change source ${upstreamURI} closed before initial-sync completed`,\n );\n } catch (e) {\n await statusPublisher.publishAndThrowError(lc, 'Initializing', e);\n } finally {\n statusPublisher.stop();\n }\n}\n\n// Verify that the upstream tables expected by the sync logic\n// have been properly initialized.\nfunction getRequiredTables({\n appID,\n shardNum,\n}: ShardID): Record<string, Record<string, SchemaValue>> {\n return {\n [`${appID}_${shardNum}.clients`]: {\n clientGroupID: {type: 'string'},\n clientID: {type: 'string'},\n lastMutationID: {type: 'number'},\n userID: {type: 'string'},\n },\n [`${appID}_${shardNum}.mutations`]: {\n clientGroupID: {type: 'string'},\n clientID: {type: 'string'},\n mutationID: {type: 'number'},\n mutation: {type: 'json'},\n },\n [`${appID}.permissions`]: {\n permissions: {type: 'json'},\n hash: {type: 'string'},\n },\n };\n}\n\nfunction validateInitiallySyncedData(\n lc: LogContext,\n db: Database,\n shard: ShardID,\n) {\n const tables = computeZqlSpecs(lc, db, {includeBackfillingColumns: true});\n const required = getRequiredTables(shard);\n for (const [name, columns] of Object.entries(required)) {\n const table = tables.get(name)?.zqlSpec;\n if (!table) {\n throw new Error(\n `Upstream is missing the \"${name}\" table. (Found ${[\n ...tables.keys(),\n ]})` +\n `Please ensure that each table has a unique index over one ` +\n `or more non-null columns.`,\n );\n }\n for (const [col, {type}] of Object.entries(columns)) {\n const found = table[col];\n if (!found) {\n throw new Error(\n `Upstream \"${table}\" table is missing the \"${col}\" column`,\n );\n }\n if (found.type !== type) {\n throw new Error(\n `Upstream \"${table}.${col}\" column is a ${found.type} type but must be a ${type} type.`,\n );\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyCA,eAAsB,6BACpB,IACA,aACA,OACA,eACA,SAC6E;AAC7E,OAAM,YACJ,IACA,WAAW,MAAM,MAAM,GAAG,MAAM,YAChC,gBACC,KAAK,OAAO,YAAY,KAAK,OAAO,IAAI,aAAa,QAAQ,CAC/D;CAED,MAAM,UAAU,IAAI,SAAS,IAAI,cAAc;CAC/C,MAAM,oBAAoB,qBAAqB,IAAI,gBAAgB,QAAQ,CAAC;AAC5E,SAAQ,OAAO;AAEf,KAAI,MAAM,aAAa,QAAQ;EAE7B,MAAM,YAAY,CAAC,GAAG,MAAM,aAAa,CAAC,MAAM;EAChD,MAAM,aAAa,kBAAkB,aAAa,MAAM;AACxD,MAAI,CAAC,UAAU,WAAW,WAAW,CACnC,OAAM,IAAI,MACR,gDAAgD,UAAU,uCAAuC,WAAW,GAC7G;;AAWL,QAAO;EAAC;EAAmB,cAPN,IAAI,mBACvB,IACA,aACA,OACA,kBACD;EAEuC;;AAG1C,IAAM,qBAAN,MAAiD;CAC/C;CACA;CACA;CACA;CAEA,YACE,IACA,aACA,OACA,mBACA;AACA,QAAA,KAAW,GAAG,YAAY,aAAa,gBAAgB;AACvD,QAAA,cAAoB;AACpB,QAAA,QAAc;AACd,QAAA,oBAA0B;;CAG5B,cAA4B;AAC1B,SAAO,MAAA,aAAmB;;CAG5B,YACE,iBACA,mBAAsC,EAAE,EACjB;AACvB,MAAI,kBAAkB,OACpB,OAAM,IAAI,MACR,0DACD;AAEH,SAAO,QAAQ,QAAQ,MAAA,YAAkB,gBAAgB,CAAC;;CAG5D,aAAa,iBAAwC;EACnD,MAAM,EAAC,cAAc,mBAAkB,MAAA;EACvC,MAAM,EAAC,OAAO,aAAY,MAAA;EAC1B,MAAM,MAAM,IAAI,IAAI,MAAA,YAAkB;AACtC,MAAI,aAAa,IAAI,SAAS,MAAM;AACpC,MAAI,aAAa,IAAI,YAAY,OAAO,SAAS,CAAC;AAClD,OAAK,MAAM,OAAO,aAChB,KAAI,aAAa,OAAO,gBAAgB,IAAI;AAE9C,MAAI,iBAAiB;AACnB,UACE,eAAe,QACf,yDACD;AACD,OAAI,aAAa,IAAI,iBAAiB,gBAAgB;AACtD,OAAI,aAAa,IAAI,kBAAkB,eAAe;;EAGxD,MAAM,KAAK,IAAI,YAAU,IAAI;EAC7B,MAAM,EAAC,UAAU,cAAa,OAC5B,MAAA,IACA,IACA,2BAGA,EAAC,WAAW,SAA+B,MAAK,CACjD;AACD,SAAO;GAAC,SAAS;GAAU,MAAM;GAAU;;;;;;;;;;;;;;AAe/C,eAAsB,YACpB,IACA,OACA,IACA,aACA,SACA;CACA,MAAM,EAAC,OAAO,IAAI,iBAAgB;CAKlC,MAAM,EAAC,YAJc,IAAI,mBAAmB,IAAI,aAAa,OAAO;EAClE,gBAAgB;EAChB;EACD,CAAC,CAC6B,aAAa;AAE5C,8BAA6B,GAAG;CAChC,MAAM,YAAY,IAAI,gBACpB,IAAI,gBAAgB,GAAG,EACvB,iBACC,GAAG,QAAQ;AACV,QAAM;GAET;CAED,MAAM,kBAAkB,IAAI,2BAA2B,GAAG;AAC1D,KAAI;EACF,IAAI,MAAM;AACV,aAAW,MAAM,UAAU,SAAS;GAClC,MAAM,CAAC,OAAO;AACd,WAAQ,KAAR;IACE,KAAK,SAAS;KACZ,MAAM,EAAC,oBAAmB,OAAO;AACjC,QAAG,OACD,yBAAyB,GAAG,qBAAqB,kBAClD;AACD,qBAAgB,QACd,IACA,gBACA,sCAAsC,mBACtC,IACD;AACD,0BACE,IACA,CAAC,GAAG,aAAa,CAAC,MAAM,EACxB,iBACA,SACA,MACD;AACD,eAAU,eAAe,IAAI,OAAO;AACpC;;IAEF,KAAK;AACH,eAAU,eAAe,IAAI,OAAO;AACpC,SAAI,EAAE,MAAM,QAAS,EACnB,IAAG,QAAQ,aAAa,IAAI,UAAU;AAExC;IACF,KAAK;AACH,eAAU,eAAe,IAAI,OAAO;AACpC,iCAA4B,IAAI,IAAI,MAAM;AAC1C,QAAG,OAAO,4BAA4B,IAAI,UAAU;AACpD;IAEF,KAAK,SACH;IAEF,KAAK,WAAW;KACd,MAAM,EAAC,KAAK,YAAW,OAAO;AAC9B,SAAI,QAAQ,iBACV,OAAM,IAAI,gBACR,WAAW,uCACZ;;IAIL,KAAK,WACH,OAAM,IAAI,MACR,2CAA2C,UAAU,OAAO,GAC7D;IACH,QACE,aAAY,OAAO;;;AAGzB,QAAM,IAAI,MACR,iBAAiB,YAAY,uCAC9B;UACM,GAAG;AACV,QAAM,gBAAgB,qBAAqB,IAAI,gBAAgB,EAAE;WACzD;AACR,kBAAgB,MAAM;;;AAM1B,SAAS,kBAAkB,EACzB,OACA,YACuD;AACvD,QAAO;GACJ,GAAG,MAAM,GAAG,SAAS,YAAY;GAChC,eAAe,EAAC,MAAM,UAAS;GAC/B,UAAU,EAAC,MAAM,UAAS;GAC1B,gBAAgB,EAAC,MAAM,UAAS;GAChC,QAAQ,EAAC,MAAM,UAAS;GACzB;GACA,GAAG,MAAM,GAAG,SAAS,cAAc;GAClC,eAAe,EAAC,MAAM,UAAS;GAC/B,UAAU,EAAC,MAAM,UAAS;GAC1B,YAAY,EAAC,MAAM,UAAS;GAC5B,UAAU,EAAC,MAAM,QAAO;GACzB;GACA,GAAG,MAAM,gBAAgB;GACxB,aAAa,EAAC,MAAM,QAAO;GAC3B,MAAM,EAAC,MAAM,UAAS;GACvB;EACF;;AAGH,SAAS,4BACP,IACA,IACA,OACA;CACA,MAAM,SAAS,gBAAgB,IAAI,IAAI,EAAC,2BAA2B,MAAK,CAAC;CACzE,MAAM,WAAW,kBAAkB,MAAM;AACzC,MAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,SAAS,EAAE;EACtD,MAAM,QAAQ,OAAO,IAAI,KAAK,EAAE;AAChC,MAAI,CAAC,MACH,OAAM,IAAI,MACR,4BAA4B,KAAK,kBAAkB,CACjD,GAAG,OAAO,MAAM,CACjB,CAAC,sFAGH;AAEH,OAAK,MAAM,CAAC,KAAK,EAAC,WAAU,OAAO,QAAQ,QAAQ,EAAE;GACnD,MAAM,QAAQ,MAAM;AACpB,OAAI,CAAC,MACH,OAAM,IAAI,MACR,aAAa,MAAM,0BAA0B,IAAI,UAClD;AAEH,OAAI,MAAM,SAAS,KACjB,OAAM,IAAI,MACR,aAAa,MAAM,GAAG,IAAI,gBAAgB,MAAM,KAAK,sBAAsB,KAAK,QACjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/pg/change-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAqBjD,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,0BAA0B,CAAC;AAKlC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,2BAA2B,CAAC;AAEpD,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAC,YAAY,EAAe,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAEL,KAAK,QAAQ,EACd,MAAM,wCAAwC,CAAC;AAUhD,OAAO,KAAK,EAEV,mBAAmB,EAEpB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAGV,eAAe,IAAI,gBAAgB,EACpC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/pg/change-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAqBjD,OAAO,KAAK,EAGV,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,0BAA0B,CAAC;AAKlC,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,2BAA2B,CAAC;AAEpD,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,8CAA8C,CAAC;AACtD,OAAO,KAAK,EAAC,YAAY,EAAe,MAAM,qBAAqB,CAAC;AAEpE,OAAO,EAEL,KAAK,QAAQ,EACd,MAAM,wCAAwC,CAAC;AAUhD,OAAO,KAAK,EAEV,mBAAmB,EAEpB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAGV,eAAe,IAAI,gBAAgB,EACpC,MAAM,yCAAyC,CAAC;AA2BjD;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,UAAU,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,YAAY,CAAA;CAAC,CAAC,CAqC7E;AA8YD,qBAAa,KAAM,YAAW,QAAQ;;gBAIxB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;IAI9B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI;IAgC3C,GAAG,CAAC,SAAS,EAAE,WAAW;CAoB3B;AAmkBD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,gBAAgB,WAwB3E"}
|
|
@@ -320,7 +320,7 @@ var ChangeMaker = class {
|
|
|
320
320
|
const errorDetails = { error: message };
|
|
321
321
|
if (err instanceof UnsupportedSchemaChangeError) {
|
|
322
322
|
errorDetails.reason = err.description;
|
|
323
|
-
errorDetails.context = err.
|
|
323
|
+
errorDetails.context = err.event.context;
|
|
324
324
|
} else errorDetails.reason = String(err);
|
|
325
325
|
return [["rollback", { tag: "rollback" }], ["control", {
|
|
326
326
|
tag: "reset-required",
|
|
@@ -333,7 +333,7 @@ var ChangeMaker = class {
|
|
|
333
333
|
const { lsn, msg, err, lastLogTime } = error;
|
|
334
334
|
const now = Date.now();
|
|
335
335
|
if (now - lastLogTime > 6e4) {
|
|
336
|
-
this.#lc.error?.(`Unable to continue replication from LSN ${fromBigInt(lsn)}: ${String(err)}`, err instanceof UnsupportedSchemaChangeError ? err.
|
|
336
|
+
this.#lc.error?.(`Unable to continue replication from LSN ${fromBigInt(lsn)}: ${String(err)}`, err instanceof UnsupportedSchemaChangeError ? err.event.context : {
|
|
337
337
|
...msg,
|
|
338
338
|
content: void 0
|
|
339
339
|
});
|
|
@@ -371,16 +371,24 @@ var ChangeMaker = class {
|
|
|
371
371
|
relations: msg.relations.map(makeRelation)
|
|
372
372
|
}]];
|
|
373
373
|
case "message":
|
|
374
|
-
if (msg.prefix
|
|
374
|
+
if (!msg.prefix.startsWith(this.#shardPrefix)) {
|
|
375
375
|
this.#lc.debug?.("ignoring message for different shard", msg.prefix);
|
|
376
376
|
return [];
|
|
377
377
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
378
|
+
switch (msg.prefix.substring(this.#shardPrefix.length)) {
|
|
379
|
+
case "":
|
|
380
|
+
case "/ddl": return this.#handleDdlMessage(msg);
|
|
381
|
+
default:
|
|
382
|
+
this.#lc.debug?.("ignoring unknown message type", msg.prefix);
|
|
383
|
+
return [];
|
|
384
|
+
}
|
|
385
|
+
case "commit":
|
|
386
|
+
this.#lastSnapshotInTx = void 0;
|
|
387
|
+
return [[
|
|
388
|
+
"commit",
|
|
389
|
+
msg,
|
|
390
|
+
{ watermark: toStateVersionString(must(msg.commitLsn)) }
|
|
391
|
+
]];
|
|
384
392
|
case "relation": return this.#handleRelation(msg);
|
|
385
393
|
case "type": return [];
|
|
386
394
|
case "origin": return [];
|
|
@@ -388,14 +396,33 @@ var ChangeMaker = class {
|
|
|
388
396
|
}
|
|
389
397
|
}
|
|
390
398
|
#preSchema;
|
|
391
|
-
#
|
|
399
|
+
#lastSnapshotInTx;
|
|
400
|
+
#handleDdlMessage(msg) {
|
|
392
401
|
const event = this.#parseReplicationEvent(msg.content);
|
|
393
402
|
clearTimeout(this.#replicaIdentityTimer);
|
|
394
|
-
|
|
395
|
-
|
|
403
|
+
let previousSchema;
|
|
404
|
+
const { type } = event;
|
|
405
|
+
switch (type) {
|
|
406
|
+
case "ddlStart":
|
|
407
|
+
this.#preSchema = event.schema;
|
|
408
|
+
return [];
|
|
409
|
+
case "ddlUpdate":
|
|
410
|
+
previousSchema = must(this.#preSchema, `ddlUpdate received without a ddlStart`);
|
|
411
|
+
break;
|
|
412
|
+
case "schemaSnapshot":
|
|
413
|
+
previousSchema = this.#lastSnapshotInTx ?? null;
|
|
414
|
+
break;
|
|
415
|
+
default:
|
|
416
|
+
this.#lc.info?.(`ignoring unknown ddl message type: ${type}`);
|
|
417
|
+
return [];
|
|
418
|
+
}
|
|
419
|
+
this.#lastSnapshotInTx = event.schema;
|
|
420
|
+
if (!previousSchema) {
|
|
421
|
+
this.#lc.info?.(`received ${msg.prefix}/${type} event`);
|
|
396
422
|
return [];
|
|
397
423
|
}
|
|
398
|
-
|
|
424
|
+
this.#lc.info?.(`processing ${msg.prefix}/${type} event`, event);
|
|
425
|
+
const changes = this.#makeSchemaChanges(previousSchema, event).map((change) => ["data", change]);
|
|
399
426
|
this.#lc.withContext("tag", event.event.tag).withContext("query", event.context.query).info?.(`${changes.length} schema change(s)`, { changes });
|
|
400
427
|
const replicaIdentities = replicaIdentitiesForTablesWithoutPrimaryKeys(event.schema);
|
|
401
428
|
if (replicaIdentities) this.#replicaIdentityTimer = setTimeout(async () => {
|
|
@@ -547,7 +574,7 @@ var ChangeMaker = class {
|
|
|
547
574
|
}
|
|
548
575
|
});
|
|
549
576
|
}
|
|
550
|
-
const alwaysBackfill = ddlTag
|
|
577
|
+
const alwaysBackfill = ddlTag !== "ALTER TABLE";
|
|
551
578
|
for (const id of added) {
|
|
552
579
|
const { name, ...spec } = must(newColumns.get(id));
|
|
553
580
|
const column = {
|
|
@@ -706,11 +733,11 @@ function makeRelation(relation) {
|
|
|
706
733
|
var UnsupportedSchemaChangeError = class extends Error {
|
|
707
734
|
name = "UnsupportedSchemaChangeError";
|
|
708
735
|
description;
|
|
709
|
-
|
|
710
|
-
constructor(description,
|
|
736
|
+
event;
|
|
737
|
+
constructor(description, event, options) {
|
|
711
738
|
super(`Replication halted. Resync the replica to recover: ${description}`, options);
|
|
712
739
|
this.description = description;
|
|
713
|
-
this.
|
|
740
|
+
this.event = event;
|
|
714
741
|
}
|
|
715
742
|
};
|
|
716
743
|
var MissingEventTriggerSupport = class extends Error {
|