@rocicorp/zero 1.10.0-canary.13 → 1.10.0-canary.15
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/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/db/create.d.ts.map +1 -1
- package/out/zero-cache/src/db/create.js +4 -1
- package/out/zero-cache/src/db/create.js.map +1 -1
- package/out/zero-cache/src/db/index-predicate.d.ts +4 -0
- package/out/zero-cache/src/db/index-predicate.d.ts.map +1 -0
- package/out/zero-cache/src/db/index-predicate.js +46 -0
- package/out/zero-cache/src/db/index-predicate.js.map +1 -0
- package/out/zero-cache/src/db/lite-tables.d.ts +10 -2
- package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js +8 -3
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/specs.d.ts +41 -0
- package/out/zero-cache/src/db/specs.d.ts.map +1 -1
- package/out/zero-cache/src/db/specs.js +30 -3
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +34 -2
- 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 +34 -8
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +2 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +1512 -228
- 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/index-predicate.d.ts +19 -0
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +521 -0
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +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 +9 -0
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +136 -19
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.js +80 -12
- package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +126 -19
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +2 -0
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +3 -0
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +1 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +16 -16
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +2 -1
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js +1 -0
- package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +2 -1
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
package/out/zero/package.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var package_default = {
|
|
2
2
|
name: "@rocicorp/zero",
|
|
3
|
-
version: "1.10.0-canary.
|
|
3
|
+
version: "1.10.0-canary.15",
|
|
4
4
|
description: "Zero is a web framework for serverless web development.",
|
|
5
5
|
homepage: "https://zero.rocicorp.dev",
|
|
6
6
|
bugs: { "url": "https://bugs.rocicorp.dev" },
|
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\": \"1.10.0-canary.
|
|
1
|
+
{"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.10.0-canary.15\",\n \"description\": \"Zero is a web framework for serverless web development.\",\n \"homepage\": \"https://zero.rocicorp.dev\",\n \"bugs\": {\n \"url\": \"https://bugs.rocicorp.dev\"\n },\n \"license\": \"Apache-2.0\",\n \"author\": \"Rocicorp, Inc.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rocicorp/mono.git\",\n \"directory\": \"packages/zero\"\n },\n \"bin\": {\n \"analyze-query\": \"./out/zero/src/analyze-query.js\",\n \"ast-to-zql\": \"./out/zero/src/ast-to-zql.js\",\n \"transform-query\": \"./out/zero/src/transform-query.js\",\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 },\n \"files\": [\n \"out\",\n \"!*.tsbuildinfo\"\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 \"./analyze\": {\n \"types\": \"./out/zero/src/analyze.d.ts\",\n \"default\": \"./out/zero/src/analyze.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/kysely\": {\n \"types\": \"./out/zero/src/adapters/kysely.d.ts\",\n \"default\": \"./out/zero/src/adapters/kysely.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 \"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\": \"oxfmt .\",\n \"check-format\": \"oxfmt --check .\",\n \"lint\": \"oxlint --quiet --config ../../oxlint.config.ts 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 \"fmt\": \"oxfmt .\",\n \"check-fmt\": \"oxfmt --check .\"\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.218.0\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.76.0\",\n \"@opentelemetry/exporter-metrics-otlp-http\": \"^0.218.0\",\n \"@opentelemetry/resources\": \"^2.7.1\",\n \"@opentelemetry/sdk-metrics\": \"^2.7.1\",\n \"@opentelemetry/sdk-node\": \"^0.218.0\",\n \"@opentelemetry/sdk-trace-node\": \"^2.7.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.41.1\",\n \"@postgresql-typed/oids\": \"^0.2.0\",\n \"@rocicorp/lock\": \"^1.0.4\",\n \"@rocicorp/logger\": \"^6.1.0\",\n \"@rocicorp/resolver\": \"^1.0.2\",\n \"@rocicorp/zero-sqlite3\": \"^1.1.4\",\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-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.2.0\",\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 \"oxfmt\": \"^0.45.0\",\n \"parse-prometheus-text-format\": \"^1.1.1\",\n \"pg-format\": \"npm:pg-format-fix@^1.0.5\",\n \"postgres\": \"3.4.7\",\n \"semver\": \"^7.5.4\",\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.6\",\n \"analyze-query\": \"workspace:*\",\n \"ast-to-zql\": \"workspace:*\",\n \"expo-sqlite\": \">=15\",\n \"oxc-parser\": \"^0.129.0\",\n \"replicache\": \"workspace:*\",\n \"shared\": \"workspace:*\",\n \"syncpack\": \"^14.3.0\",\n \"typedoc\": \"^0.28.17\",\n \"typedoc-plugin-markdown\": \"^4.10.0\",\n \"typescript\": \"~6.0.2\",\n \"vite\": \"^8.0.13\",\n \"vitest\": \"^4.1.6\",\n \"zero-cache\": \"workspace:*\",\n \"zero-client\": \"workspace:*\",\n \"zero-pg\": \"workspace:*\",\n \"zero-react\": \"workspace:*\",\n \"zero-server\": \"workspace:*\",\n \"zero-solid\": \"workspace:*\",\n \"zqlite\": \"workspace:*\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"pnpm@11.11.0\"\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/create.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/create.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,UAAU,EAAE,aAAa,EAAE,aAAa,EAAC,MAAM,YAAY,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,UAe7C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAUpE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAerE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assertValidLiteColumnSpec } from "../types/lite.js";
|
|
2
2
|
import { id, idList } from "../types/sql.js";
|
|
3
|
+
import { liteIndexPredicateSQL } from "./index-predicate.js";
|
|
3
4
|
//#region ../zero-cache/src/db/create.ts
|
|
4
5
|
/**
|
|
5
6
|
* `spec` always comes from `mapPostgresToLiteColumn` so we only need to support
|
|
@@ -27,7 +28,9 @@ function createLiteTableStatement(spec) {
|
|
|
27
28
|
}
|
|
28
29
|
function createLiteIndexStatement(index) {
|
|
29
30
|
const columns = Object.entries(index.columns).map(([name, dir]) => `${id(name)} ${dir}`).join(",");
|
|
30
|
-
|
|
31
|
+
const unique = index.unique && !index.predicate ? "UNIQUE" : "";
|
|
32
|
+
const predicate = index.predicate ? ` WHERE ${liteIndexPredicateSQL(index.predicate)}` : "";
|
|
33
|
+
return `CREATE ${unique} INDEX ${id(index.name)} ON ${id(index.tableName)} (${columns})${predicate};`;
|
|
31
34
|
}
|
|
32
35
|
//#endregion
|
|
33
36
|
export { createLiteIndexStatement, createLiteTableStatement, liteColumnDef };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","names":[],"sources":["../../../../../zero-cache/src/db/create.ts"],"sourcesContent":["import {assertValidLiteColumnSpec} from '../types/lite.ts';\nimport {id, idList} from '../types/sql.ts';\nimport type {ColumnSpec, LiteIndexSpec, LiteTableSpec} from './specs.ts';\n\n/**\n * `spec` always comes from `mapPostgresToLiteColumn` so we only need to support\n * the output of that function.\n */\nexport function liteColumnDef(spec: ColumnSpec) {\n assertValidLiteColumnSpec(spec);\n\n let def = id(spec.dataType);\n\n if (spec.characterMaximumLength) {\n def += `(${spec.characterMaximumLength})`;\n }\n if (spec.notNull) {\n def += ' NOT NULL';\n }\n if (spec.dflt) {\n def += ` DEFAULT ${spec.dflt}`;\n }\n return def;\n}\n\n/**\n * Constructs a `CREATE TABLE` statement for a {@link TableSpec}.\n */\nexport function createLiteTableStatement(spec: LiteTableSpec): string {\n const defs = Object.entries(spec.columns)\n .sort(([_a, {pos: a}], [_b, {pos: b}]) => a - b)\n .map(([name, columnSpec]) => `${id(name)} ${liteColumnDef(columnSpec)}`);\n if (spec.primaryKey) {\n defs.push(`PRIMARY KEY (${idList(spec.primaryKey)})`);\n }\n\n const createStmt = `CREATE TABLE ${id(spec.name)} (`;\n return [createStmt, defs.join(',\\n'), ');'].join('\\n');\n}\n\nexport function createLiteIndexStatement(index: LiteIndexSpec): string {\n const columns = Object.entries(index.columns)\n .map(([name, dir]) => `${id(name)} ${dir}`)\n .join(',');\n const unique = index.unique ? 'UNIQUE' : '';\n return `CREATE ${unique} INDEX ${id(index.name)} ON ${id(\n index.tableName,\n )} (${columns});`;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.js","names":[],"sources":["../../../../../zero-cache/src/db/create.ts"],"sourcesContent":["import {assertValidLiteColumnSpec} from '../types/lite.ts';\nimport {id, idList} from '../types/sql.ts';\nimport {liteIndexPredicateSQL} from './index-predicate.ts';\nimport type {ColumnSpec, LiteIndexSpec, LiteTableSpec} from './specs.ts';\n\n/**\n * `spec` always comes from `mapPostgresToLiteColumn` so we only need to support\n * the output of that function.\n */\nexport function liteColumnDef(spec: ColumnSpec) {\n assertValidLiteColumnSpec(spec);\n\n let def = id(spec.dataType);\n\n if (spec.characterMaximumLength) {\n def += `(${spec.characterMaximumLength})`;\n }\n if (spec.notNull) {\n def += ' NOT NULL';\n }\n if (spec.dflt) {\n def += ` DEFAULT ${spec.dflt}`;\n }\n return def;\n}\n\n/**\n * Constructs a `CREATE TABLE` statement for a {@link TableSpec}.\n */\nexport function createLiteTableStatement(spec: LiteTableSpec): string {\n const defs = Object.entries(spec.columns)\n .sort(([_a, {pos: a}], [_b, {pos: b}]) => a - b)\n .map(([name, columnSpec]) => `${id(name)} ${liteColumnDef(columnSpec)}`);\n if (spec.primaryKey) {\n defs.push(`PRIMARY KEY (${idList(spec.primaryKey)})`);\n }\n\n const createStmt = `CREATE TABLE ${id(spec.name)} (`;\n return [createStmt, defs.join(',\\n'), ');'].join('\\n');\n}\n\nexport function createLiteIndexStatement(index: LiteIndexSpec): string {\n const columns = Object.entries(index.columns)\n .map(([name, dir]) => `${id(name)} ${dir}`)\n .join(',');\n // Partial indexes are never unique on the replica. Their uniqueness is\n // not needed (a partial index cannot serve as a row key), and a UNIQUE\n // partial index would turn any divergence between PostgreSQL's and\n // SQLite's evaluation of the predicate into a replication failure.\n const unique = index.unique && !index.predicate ? 'UNIQUE' : '';\n const predicate = index.predicate\n ? ` WHERE ${liteIndexPredicateSQL(index.predicate)}`\n : '';\n return `CREATE ${unique} INDEX ${id(index.name)} ON ${id(\n index.tableName,\n )} (${columns})${predicate};`;\n}\n"],"mappings":";;;;;;;;AASA,SAAgB,cAAc,MAAkB;CAC9C,0BAA0B,IAAI;CAE9B,IAAI,MAAM,GAAG,KAAK,QAAQ;CAE1B,IAAI,KAAK,wBACP,OAAO,IAAI,KAAK,uBAAuB;CAEzC,IAAI,KAAK,SACP,OAAO;CAET,IAAI,KAAK,MACP,OAAO,YAAY,KAAK;CAE1B,OAAO;AACT;;;;AAKA,SAAgB,yBAAyB,MAA6B;CACpE,MAAM,OAAO,OAAO,QAAQ,KAAK,OAAO,EACrC,MAAM,CAAC,IAAI,EAAC,KAAK,MAAK,CAAC,IAAI,EAAC,KAAK,SAAQ,IAAI,CAAC,EAC9C,KAAK,CAAC,MAAM,gBAAgB,GAAG,GAAG,IAAI,EAAE,GAAG,cAAc,UAAU,GAAG;CACzE,IAAI,KAAK,YACP,KAAK,KAAK,gBAAgB,OAAO,KAAK,UAAU,EAAE,EAAE;CAItD,OAAO;EAAC,gBAD2B,GAAG,KAAK,IAAI,EAAE;EAC7B,KAAK,KAAK,KAAK;EAAG;CAAI,EAAE,KAAK,IAAI;AACvD;AAEA,SAAgB,yBAAyB,OAA8B;CACrE,MAAM,UAAU,OAAO,QAAQ,MAAM,OAAO,EACzC,KAAK,CAAC,MAAM,SAAS,GAAG,GAAG,IAAI,EAAE,GAAG,KAAK,EACzC,KAAK,GAAG;CAKX,MAAM,SAAS,MAAM,UAAU,CAAC,MAAM,YAAY,WAAW;CAC7D,MAAM,YAAY,MAAM,YACpB,UAAU,sBAAsB,MAAM,SAAS,MAC/C;CACJ,OAAO,UAAU,OAAO,SAAS,GAAG,MAAM,IAAI,EAAE,MAAM,GACpD,MAAM,SACR,EAAE,IAAI,QAAQ,GAAG,UAAU;AAC7B"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IndexPredicate } from './specs.ts';
|
|
2
|
+
export declare function liteIndexPredicateSQL(predicate: IndexPredicate): string;
|
|
3
|
+
export declare function mapIndexPredicateColumns(predicate: IndexPredicate, map: (column: string) => string): IndexPredicate;
|
|
4
|
+
//# sourceMappingURL=index-predicate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-predicate.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/index-predicate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,cAAc,EAAsB,MAAM,YAAY,CAAC;AAIpE,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,CAiBvE;AAkBD,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,cAAc,EACzB,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC9B,cAAc,CAmBhB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { assert } from "../../../shared/src/asserts.js";
|
|
2
|
+
import { id, lit } from "../types/sql.js";
|
|
3
|
+
//#region ../zero-cache/src/db/index-predicate.ts
|
|
4
|
+
var CANONICAL_INTEGER_RE = /^-?(?:0|[1-9]\d*)$/;
|
|
5
|
+
function liteIndexPredicateSQL(predicate) {
|
|
6
|
+
switch (predicate.type) {
|
|
7
|
+
case "and":
|
|
8
|
+
case "or":
|
|
9
|
+
assert(predicate.conditions.length > 0, "empty index predicate");
|
|
10
|
+
return `(${predicate.conditions.map(liteIndexPredicateSQL).join(` ${predicate.type.toUpperCase()} `)})`;
|
|
11
|
+
case "not": return `(NOT ${liteIndexPredicateSQL(predicate.condition)})`;
|
|
12
|
+
case "null-test": return `${id(predicate.column)} ${predicate.op}`;
|
|
13
|
+
case "comparison": return `${id(predicate.column)} ${predicate.op} ${predicateValueSQL(predicate.value)}`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function predicateValueSQL(value) {
|
|
17
|
+
switch (value.type) {
|
|
18
|
+
case "boolean": return value.value ? "1" : "0";
|
|
19
|
+
case "integer":
|
|
20
|
+
assert(CANONICAL_INTEGER_RE.test(value.value), "invalid integer predicate");
|
|
21
|
+
return value.value;
|
|
22
|
+
case "string": return lit(value.value);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function mapIndexPredicateColumns(predicate, map) {
|
|
26
|
+
switch (predicate.type) {
|
|
27
|
+
case "and":
|
|
28
|
+
case "or": return {
|
|
29
|
+
...predicate,
|
|
30
|
+
conditions: predicate.conditions.map((condition) => mapIndexPredicateColumns(condition, map))
|
|
31
|
+
};
|
|
32
|
+
case "not": return {
|
|
33
|
+
...predicate,
|
|
34
|
+
condition: mapIndexPredicateColumns(predicate.condition, map)
|
|
35
|
+
};
|
|
36
|
+
case "null-test":
|
|
37
|
+
case "comparison": return {
|
|
38
|
+
...predicate,
|
|
39
|
+
column: map(predicate.column)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { liteIndexPredicateSQL, mapIndexPredicateColumns };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=index-predicate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-predicate.js","names":[],"sources":["../../../../../zero-cache/src/db/index-predicate.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport {id, lit} from '../types/sql.ts';\nimport type {IndexPredicate, IndexPredicateValue} from './specs.ts';\n\nconst CANONICAL_INTEGER_RE = /^-?(?:0|[1-9]\\d*)$/;\n\nexport function liteIndexPredicateSQL(predicate: IndexPredicate): string {\n switch (predicate.type) {\n case 'and':\n case 'or':\n assert(predicate.conditions.length > 0, 'empty index predicate');\n return `(${predicate.conditions\n .map(liteIndexPredicateSQL)\n .join(` ${predicate.type.toUpperCase()} `)})`;\n case 'not':\n return `(NOT ${liteIndexPredicateSQL(predicate.condition)})`;\n case 'null-test':\n return `${id(predicate.column)} ${predicate.op}`;\n case 'comparison':\n return `${id(predicate.column)} ${predicate.op} ${predicateValueSQL(\n predicate.value,\n )}`;\n }\n}\n\nfunction predicateValueSQL(value: IndexPredicateValue): string {\n switch (value.type) {\n case 'boolean':\n return value.value ? '1' : '0';\n case 'integer':\n // The PostgreSQL translator only constructs canonical decimal integers.\n assert(\n CANONICAL_INTEGER_RE.test(value.value),\n 'invalid integer predicate',\n );\n return value.value;\n case 'string':\n return lit(value.value);\n }\n}\n\nexport function mapIndexPredicateColumns(\n predicate: IndexPredicate,\n map: (column: string) => string,\n): IndexPredicate {\n switch (predicate.type) {\n case 'and':\n case 'or':\n return {\n ...predicate,\n conditions: predicate.conditions.map(condition =>\n mapIndexPredicateColumns(condition, map),\n ),\n };\n case 'not':\n return {\n ...predicate,\n condition: mapIndexPredicateColumns(predicate.condition, map),\n };\n case 'null-test':\n case 'comparison':\n return {...predicate, column: map(predicate.column)};\n }\n}\n"],"mappings":";;;AAIA,IAAM,uBAAuB;AAE7B,SAAgB,sBAAsB,WAAmC;CACvE,QAAQ,UAAU,MAAlB;EACE,KAAK;EACL,KAAK;GACH,OAAO,UAAU,WAAW,SAAS,GAAG,uBAAuB;GAC/D,OAAO,IAAI,UAAU,WAClB,IAAI,qBAAqB,EACzB,KAAK,IAAI,UAAU,KAAK,YAAY,EAAE,EAAE,EAAE;EAC/C,KAAK,OACH,OAAO,QAAQ,sBAAsB,UAAU,SAAS,EAAE;EAC5D,KAAK,aACH,OAAO,GAAG,GAAG,UAAU,MAAM,EAAE,GAAG,UAAU;EAC9C,KAAK,cACH,OAAO,GAAG,GAAG,UAAU,MAAM,EAAE,GAAG,UAAU,GAAG,GAAG,kBAChD,UAAU,KACZ;CACJ;AACF;AAEA,SAAS,kBAAkB,OAAoC;CAC7D,QAAQ,MAAM,MAAd;EACE,KAAK,WACH,OAAO,MAAM,QAAQ,MAAM;EAC7B,KAAK;GAEH,OACE,qBAAqB,KAAK,MAAM,KAAK,GACrC,2BACF;GACA,OAAO,MAAM;EACf,KAAK,UACH,OAAO,IAAI,MAAM,KAAK;CAC1B;AACF;AAEA,SAAgB,yBACd,WACA,KACgB;CAChB,QAAQ,UAAU,MAAlB;EACE,KAAK;EACL,KAAK,MACH,OAAO;GACL,GAAG;GACH,YAAY,UAAU,WAAW,KAAI,cACnC,yBAAyB,WAAW,GAAG,CACzC;EACF;EACF,KAAK,OACH,OAAO;GACL,GAAG;GACH,WAAW,yBAAyB,UAAU,WAAW,GAAG;EAC9D;EACF,KAAK;EACL,KAAK,cACH,OAAO;GAAC,GAAG;GAAW,QAAQ,IAAI,UAAU,MAAM;EAAC;CACvD;AACF"}
|
|
@@ -6,7 +6,15 @@ export type LiteTableSpecWithReplicationStatus = LiteTableSpec & {
|
|
|
6
6
|
readonly minRowVersion?: string | null;
|
|
7
7
|
};
|
|
8
8
|
export declare function listTables(db: Database, useColumnMetadata?: boolean, useTableMetadata?: boolean): LiteTableSpecWithReplicationStatus[];
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* An index as it exists on the replica. SQLite retains only the DDL text of a
|
|
11
|
+
* partial index, not a structured predicate, so replica indexes report a
|
|
12
|
+
* `partial` flag in place of the {@link LiteIndexSpec.predicate}.
|
|
13
|
+
*/
|
|
14
|
+
export type ReplicaIndexSpec = Omit<LiteIndexSpec, 'predicate'> & {
|
|
15
|
+
readonly partial?: boolean | undefined;
|
|
16
|
+
};
|
|
17
|
+
export declare function listIndexes(db: Database): ReplicaIndexSpec[];
|
|
10
18
|
export type ZqlSpecOptions = {
|
|
11
19
|
/**
|
|
12
20
|
* Controls whether to include backfilling columns in the computed
|
|
@@ -33,6 +41,6 @@ export type ZqlSpecOptions = {
|
|
|
33
41
|
* data types.
|
|
34
42
|
*/
|
|
35
43
|
export declare function computeZqlSpecs(lc: LogContext, replica: Database, opts: ZqlSpecOptions, tableSpecs?: Map<string, LiteAndZqlSpec>, fullTables?: Map<string, LiteTableSpec>): Map<string, LiteAndZqlSpec>;
|
|
36
|
-
export declare function computeZqlSpecsFromLiteSpecs(tables: LiteTableSpecWithReplicationStatus[], indexes: LiteIndexSpec[], { includeBackfillingColumns }: ZqlSpecOptions, tableSpecs?: Map<string, LiteAndZqlSpec>, fullTables?: Map<string, LiteTableSpec>, lc?: LogContext): Map<string, LiteAndZqlSpec>;
|
|
44
|
+
export declare function computeZqlSpecsFromLiteSpecs(tables: LiteTableSpecWithReplicationStatus[], indexes: readonly (LiteIndexSpec | ReplicaIndexSpec)[], { includeBackfillingColumns }: ZqlSpecOptions, tableSpecs?: Map<string, LiteAndZqlSpec>, fullTables?: Map<string, LiteTableSpec>, lc?: LogContext): Map<string, LiteAndZqlSpec>;
|
|
37
45
|
export declare function mustGetTableSpec(tableSpecs: Map<string, LiteAndZqlSpec>, tableName: string): LiteAndZqlSpec;
|
|
38
46
|
//# sourceMappingURL=lite-tables.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lite-tables.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/lite-tables.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AAcxD,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EAGd,MAAM,YAAY,CAAC;AAWpB,MAAM,MAAM,kCAAkC,GAAG,aAAa,GAAG;IAC/D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC,CAAC;AAOF,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,iBAAiB,UAAO,EACxB,gBAAgB,UAAO,GACtB,kCAAkC,EAAE,CAwFtC;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"lite-tables.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/lite-tables.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,2BAA2B,CAAC;AAcxD,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,aAAa,EAGd,MAAM,YAAY,CAAC;AAWpB,MAAM,MAAM,kCAAkC,GAAG,aAAa,GAAG;IAC/D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC,CAAC;AAOF,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,iBAAiB,UAAO,EACxB,gBAAgB,UAAO,GACtB,kCAAkC,EAAE,CAwFtC;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,GAAG;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC,CAAC;AAMF,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,GAAG,gBAAgB,EAAE,CAmD5D;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;;;OAMG;IACH,yBAAyB,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,cAAc,EACpB,UAAU,GAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAa,EACnD,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GACtC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAS7B;AASD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,kCAAkC,EAAE,EAC5C,OAAO,EAAE,SAAS,CAAC,aAAa,GAAG,gBAAgB,CAAC,EAAE,EACtD,EAAC,yBAAyB,EAAC,EAAE,cAAc,EAC3C,UAAU,GAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAa,EACnD,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACvC,EAAE,CAAC,EAAE,UAAU,GACd,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CA8E7B;AAED,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EACvC,SAAS,EAAE,MAAM,GAChB,cAAc,CAWhB"}
|
|
@@ -67,6 +67,7 @@ function listIndexes(db) {
|
|
|
67
67
|
idx.name as indexName,
|
|
68
68
|
idx.tbl_name as tableName,
|
|
69
69
|
info."unique" as "unique",
|
|
70
|
+
info.partial as partial,
|
|
70
71
|
col.name as column,
|
|
71
72
|
CASE WHEN col.desc = 0 THEN 'ASC' ELSE 'DESC' END as dir
|
|
72
73
|
FROM sqlite_master as idx
|
|
@@ -77,12 +78,13 @@ function listIndexes(db) {
|
|
|
77
78
|
idx.tbl_name NOT LIKE '_zero.%'
|
|
78
79
|
ORDER BY idx.name, col.seqno ASC`).all();
|
|
79
80
|
const ret = [];
|
|
80
|
-
for (const { indexName: name, tableName, unique, column, dir } of indexes) if (ret.at(-1)?.name === name) must(ret.at(-1)).columns[column] = dir;
|
|
81
|
+
for (const { indexName: name, tableName, unique, partial, column, dir } of indexes) if (ret.at(-1)?.name === name) must(ret.at(-1)).columns[column] = dir;
|
|
81
82
|
else ret.push({
|
|
82
83
|
tableName,
|
|
83
84
|
name,
|
|
84
85
|
columns: { [column]: dir },
|
|
85
|
-
unique: unique !== 0
|
|
86
|
+
unique: unique !== 0,
|
|
87
|
+
...partial === 0 ? {} : { partial: true }
|
|
86
88
|
});
|
|
87
89
|
return ret;
|
|
88
90
|
}
|
|
@@ -104,11 +106,14 @@ function listIndexes(db) {
|
|
|
104
106
|
function computeZqlSpecs(lc, replica, opts, tableSpecs = /* @__PURE__ */ new Map(), fullTables) {
|
|
105
107
|
return computeZqlSpecsFromLiteSpecs(listTables(replica), listIndexes(replica), opts, tableSpecs, fullTables, lc);
|
|
106
108
|
}
|
|
109
|
+
function isPartialIndex(idx) {
|
|
110
|
+
return "predicate" in idx && idx.predicate !== void 0 || "partial" in idx && idx.partial === true;
|
|
111
|
+
}
|
|
107
112
|
function computeZqlSpecsFromLiteSpecs(tables, indexes, { includeBackfillingColumns }, tableSpecs = /* @__PURE__ */ new Map(), fullTables, lc) {
|
|
108
113
|
tableSpecs.clear();
|
|
109
114
|
fullTables?.clear();
|
|
110
115
|
const uniqueIndexColumns = /* @__PURE__ */ new Map();
|
|
111
|
-
for (const { tableName, columns } of indexes.filter((idx) => idx.unique)) {
|
|
116
|
+
for (const { tableName, columns } of indexes.filter((idx) => idx.unique && !isPartialIndex(idx))) {
|
|
112
117
|
if (!uniqueIndexColumns.has(tableName)) uniqueIndexColumns.set(tableName, []);
|
|
113
118
|
uniqueIndexColumns.get(tableName)?.push(Object.keys(columns));
|
|
114
119
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lite-tables.js","names":[],"sources":["../../../../../zero-cache/src/db/lite-tables.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {difference} from '../../../shared/src/set-utils.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {primaryKeySchema} from '../../../zero-protocol/src/primary-key.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport {\n ColumnMetadataStore,\n metadataToLiteTypeString,\n} from '../services/replicator/schema/column-metadata.ts';\nimport {TableMetadataTracker} from '../services/replicator/schema/table-metadata.ts';\nimport {\n isArray,\n isEnum,\n liteTypeToZqlValueType,\n mapLiteDataTypeToZqlSchemaValue,\n nullableUpstream,\n} from '../types/lite.ts';\nimport * as PostgresTypeClass from './postgres-type-class-enum.ts';\nimport type {\n LiteAndZqlSpec,\n LiteIndexSpec,\n LiteTableSpec,\n MutableLiteIndexSpec,\n MutableLiteTableSpec,\n} from './specs.ts';\n\ntype ColumnInfo = {\n table: string;\n name: string;\n type: string;\n notNull: number;\n dflt: string | null;\n keyPos: number;\n};\n\nexport type LiteTableSpecWithReplicationStatus = LiteTableSpec & {\n readonly backfilling?: string[];\n readonly minRowVersion?: string | null;\n};\n\ntype MutableLiteTableSpecWithReplicationStatus = MutableLiteTableSpec & {\n backfilling: string[];\n minRowVersion: string | null;\n};\n\nexport function listTables(\n db: Database,\n useColumnMetadata = true,\n useTableMetadata = true,\n): LiteTableSpecWithReplicationStatus[] {\n const columns = db\n .prepare(\n `\n SELECT\n m.name as \"table\",\n p.name as name,\n p.type as type,\n p.\"notnull\" as \"notNull\",\n p.dflt_value as \"dflt\",\n p.pk as keyPos\n FROM sqlite_master as m\n LEFT JOIN pragma_table_info(m.name) as p\n WHERE m.type = 'table'\n AND m.name NOT LIKE 'sqlite_%'\n AND m.name NOT LIKE '_zero.%'\n AND m.name NOT LIKE '_litestream_%'\n `,\n )\n .all() as ColumnInfo[];\n\n const minRowVersions = useTableMetadata\n ? new TableMetadataTracker(db).getMinRowVersions()\n : new Map();\n const tables: LiteTableSpecWithReplicationStatus[] = [];\n let table: MutableLiteTableSpecWithReplicationStatus | undefined;\n\n columns.forEach(col => {\n if (col.table !== table?.name) {\n // New table\n table = {\n name: col.table,\n columns: {},\n backfilling: [],\n minRowVersion: minRowVersions.get(col.table) ?? null,\n };\n tables.push(table);\n }\n\n // Try to read from metadata table first, fall back to SQLite column type\n let dataType: string;\n let elemPgTypeClass:\n | typeof PostgresTypeClass.Base\n | typeof PostgresTypeClass.Enum\n | null;\n\n const metadata = useColumnMetadata\n ? ColumnMetadataStore.getInstance(db)?.getColumn(col.table, col.name)\n : undefined;\n if (metadata) {\n // Read from metadata table and convert to pipe notation\n dataType = metadataToLiteTypeString(metadata);\n elemPgTypeClass = metadata.isArray\n ? metadata.isEnum\n ? PostgresTypeClass.Enum\n : PostgresTypeClass.Base\n : null;\n } else {\n // Fall back to reading from SQLite column type (pipe notation)\n dataType = col.type;\n elemPgTypeClass = isArray(col.type)\n ? isEnum(col.type)\n ? PostgresTypeClass.Enum\n : PostgresTypeClass.Base\n : null;\n }\n\n table.columns[col.name] = {\n pos: Object.keys(table.columns).length + 1,\n dataType,\n characterMaximumLength: null,\n notNull: col.notNull !== 0,\n dflt: col.dflt,\n elemPgTypeClass,\n };\n if (metadata?.isBackfilling) {\n table.backfilling.push(col.name);\n }\n if (col.keyPos) {\n table.primaryKey ??= [];\n while (table.primaryKey.length < col.keyPos) {\n table.primaryKey.push('');\n }\n table.primaryKey[col.keyPos - 1] = col.name;\n }\n });\n\n return tables;\n}\n\nexport function listIndexes(db: Database): LiteIndexSpec[] {\n const indexes = db\n .prepare(\n `SELECT \n idx.name as indexName, \n idx.tbl_name as tableName, \n info.\"unique\" as \"unique\",\n col.name as column,\n CASE WHEN col.desc = 0 THEN 'ASC' ELSE 'DESC' END as dir\n FROM sqlite_master as idx\n JOIN pragma_index_list(idx.tbl_name) AS info ON info.name = idx.name\n JOIN pragma_index_xinfo(idx.name) as col\n WHERE idx.type = 'index' AND \n col.key = 1 AND\n idx.tbl_name NOT LIKE '_zero.%'\n ORDER BY idx.name, col.seqno ASC`,\n )\n .all() as {\n indexName: string;\n tableName: string;\n unique: number;\n column: string;\n dir: 'ASC' | 'DESC';\n }[];\n\n const ret: MutableLiteIndexSpec[] = [];\n for (const {indexName: name, tableName, unique, column, dir} of indexes) {\n if (ret.at(-1)?.name === name) {\n // Aggregate multiple column names into the array.\n must(ret.at(-1)).columns[column] = dir;\n } else {\n ret.push({\n tableName,\n name,\n columns: {[column]: dir},\n unique: unique !== 0,\n });\n }\n }\n\n return ret;\n}\n\nexport type ZqlSpecOptions = {\n /**\n * Controls whether to include backfilling columns in the computed\n * LiteAndZqlSpec. In general, backfilling columns should be include\n * in \"replication\" logic (copying data from upstream to the replica),\n * and excluded from \"sync\" logic (sending data from the replica to\n * clients).\n */\n includeBackfillingColumns: boolean;\n};\n\n/**\n * Computes a TableSpec \"view\" of the replicated data that is\n * suitable for processing / consumption for the client. This\n * includes:\n * * excluding tables without a PRIMARY KEY or UNIQUE INDEX\n * * excluding columns with types that are not supported by ZQL\n * * choosing columns to use as the primary key amongst those\n * in unique indexes\n *\n * @param tableSpecs an optional map to reset and populate\n * @param fullTables an optional map to receive the full table specs,\n * which may include tables and columns that are not synced to\n * the client because they lack a primary key or are of unsupported\n * data types.\n */\nexport function computeZqlSpecs(\n lc: LogContext,\n replica: Database,\n opts: ZqlSpecOptions,\n tableSpecs: Map<string, LiteAndZqlSpec> = new Map(),\n fullTables?: Map<string, LiteTableSpec>,\n): Map<string, LiteAndZqlSpec> {\n return computeZqlSpecsFromLiteSpecs(\n listTables(replica),\n listIndexes(replica),\n opts,\n tableSpecs,\n fullTables,\n lc,\n );\n}\n\nexport function computeZqlSpecsFromLiteSpecs(\n tables: LiteTableSpecWithReplicationStatus[],\n indexes: LiteIndexSpec[],\n {includeBackfillingColumns}: ZqlSpecOptions,\n tableSpecs: Map<string, LiteAndZqlSpec> = new Map(),\n fullTables?: Map<string, LiteTableSpec>,\n lc?: LogContext,\n): Map<string, LiteAndZqlSpec> {\n tableSpecs.clear();\n fullTables?.clear();\n\n const uniqueIndexColumns = new Map<string, string[][]>();\n for (const {tableName, columns} of indexes.filter(idx => idx.unique)) {\n if (!uniqueIndexColumns.has(tableName)) {\n uniqueIndexColumns.set(tableName, []);\n }\n uniqueIndexColumns.get(tableName)?.push(Object.keys(columns));\n }\n\n tables.forEach(fullTable => {\n fullTables?.set(fullTable.name, fullTable);\n\n const backfilling = new Set(fullTable.backfilling);\n // Only include columns that:\n // - have a defined ZQL Value\n // - aren't backfilling if `includeBackfillingColumns` is false\n const visibleColumns = Object.entries(fullTable.columns).filter(\n ([col, {dataType}]) =>\n liteTypeToZqlValueType(dataType) &&\n (includeBackfillingColumns || !backfilling.has(col)),\n );\n const notNullColumns = new Set(\n visibleColumns\n .filter(\n ([col, {dataType}]) =>\n !nullableUpstream(dataType) || fullTable.primaryKey?.includes(col),\n )\n .map(([col]) => col),\n );\n\n const uniqueKeys = uniqueIndexColumns.get(fullTable.name) ?? [];\n // Examine all column combinations that can serve as a primary key,\n // i.e. excluding indexes over nullable or unsynced columns.\n const keys = uniqueKeys.filter(\n key => difference(new Set(key), notNullColumns).size === 0,\n );\n if (keys.length === 0) {\n // Only include tables with a row key.\n //\n // Note that this will automatically exclude tables that are being\n // backfilled (when includeBackfillingColumns is `false`) since candidate\n // keys only include visible columns.\n lc?.debug?.(\n `not syncing table ${fullTable.name} because it ` +\n (backfilling.size ? 'is being backfilled' : 'has no primary key'),\n );\n return;\n }\n // Pick the \"best\" (i.e. shortest) key for default IVM operations.\n const primaryKey = keys.sort(keyCmp)[0];\n\n const tableSpec = {\n ...fullTable,\n columns: Object.fromEntries(visibleColumns),\n primaryKey: v.parse(primaryKey, primaryKeySchema),\n uniqueKeys: uniqueKeys.map(key => v.parse(key, primaryKeySchema)),\n allPotentialPrimaryKeys: keys.map(key => v.parse(key, primaryKeySchema)),\n minRowVersion: fullTable.minRowVersion ?? null,\n };\n\n tableSpecs.set(tableSpec.name, {\n tableSpec,\n zqlSpec: Object.fromEntries(\n Object.entries(tableSpec.columns).map(([name, {dataType}]) => [\n name,\n mapLiteDataTypeToZqlSchemaValue(dataType),\n ]),\n ),\n });\n });\n return tableSpecs;\n}\n\nexport function mustGetTableSpec(\n tableSpecs: Map<string, LiteAndZqlSpec>,\n tableName: string,\n): LiteAndZqlSpec {\n const tableSpec = tableSpecs.get(tableName);\n if (!tableSpec) {\n throw new Error(\n `table '${tableName}' is not one of: ${[...tableSpecs.keys()]\n .filter(t => !t.includes('.') && !t.startsWith('_litestream_'))\n .sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n }\n return tableSpec;\n}\n\n// Deterministic comparator for favoring shorter row keys.\nfunction keyCmp(a: string[], b: string[]) {\n if (a.length !== b.length) {\n return a.length - b.length; // Fewer columns are better.\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] < b[i]) {\n return -1;\n }\n if (a[i] > b[i]) {\n return 1;\n }\n }\n return 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lite-tables.js","names":[],"sources":["../../../../../zero-cache/src/db/lite-tables.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {must} from '../../../shared/src/must.ts';\nimport {difference} from '../../../shared/src/set-utils.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport {primaryKeySchema} from '../../../zero-protocol/src/primary-key.ts';\nimport type {Database} from '../../../zqlite/src/db.ts';\nimport {\n ColumnMetadataStore,\n metadataToLiteTypeString,\n} from '../services/replicator/schema/column-metadata.ts';\nimport {TableMetadataTracker} from '../services/replicator/schema/table-metadata.ts';\nimport {\n isArray,\n isEnum,\n liteTypeToZqlValueType,\n mapLiteDataTypeToZqlSchemaValue,\n nullableUpstream,\n} from '../types/lite.ts';\nimport * as PostgresTypeClass from './postgres-type-class-enum.ts';\nimport type {\n LiteAndZqlSpec,\n LiteIndexSpec,\n LiteTableSpec,\n MutableLiteIndexSpec,\n MutableLiteTableSpec,\n} from './specs.ts';\n\ntype ColumnInfo = {\n table: string;\n name: string;\n type: string;\n notNull: number;\n dflt: string | null;\n keyPos: number;\n};\n\nexport type LiteTableSpecWithReplicationStatus = LiteTableSpec & {\n readonly backfilling?: string[];\n readonly minRowVersion?: string | null;\n};\n\ntype MutableLiteTableSpecWithReplicationStatus = MutableLiteTableSpec & {\n backfilling: string[];\n minRowVersion: string | null;\n};\n\nexport function listTables(\n db: Database,\n useColumnMetadata = true,\n useTableMetadata = true,\n): LiteTableSpecWithReplicationStatus[] {\n const columns = db\n .prepare(\n `\n SELECT\n m.name as \"table\",\n p.name as name,\n p.type as type,\n p.\"notnull\" as \"notNull\",\n p.dflt_value as \"dflt\",\n p.pk as keyPos\n FROM sqlite_master as m\n LEFT JOIN pragma_table_info(m.name) as p\n WHERE m.type = 'table'\n AND m.name NOT LIKE 'sqlite_%'\n AND m.name NOT LIKE '_zero.%'\n AND m.name NOT LIKE '_litestream_%'\n `,\n )\n .all() as ColumnInfo[];\n\n const minRowVersions = useTableMetadata\n ? new TableMetadataTracker(db).getMinRowVersions()\n : new Map();\n const tables: LiteTableSpecWithReplicationStatus[] = [];\n let table: MutableLiteTableSpecWithReplicationStatus | undefined;\n\n columns.forEach(col => {\n if (col.table !== table?.name) {\n // New table\n table = {\n name: col.table,\n columns: {},\n backfilling: [],\n minRowVersion: minRowVersions.get(col.table) ?? null,\n };\n tables.push(table);\n }\n\n // Try to read from metadata table first, fall back to SQLite column type\n let dataType: string;\n let elemPgTypeClass:\n | typeof PostgresTypeClass.Base\n | typeof PostgresTypeClass.Enum\n | null;\n\n const metadata = useColumnMetadata\n ? ColumnMetadataStore.getInstance(db)?.getColumn(col.table, col.name)\n : undefined;\n if (metadata) {\n // Read from metadata table and convert to pipe notation\n dataType = metadataToLiteTypeString(metadata);\n elemPgTypeClass = metadata.isArray\n ? metadata.isEnum\n ? PostgresTypeClass.Enum\n : PostgresTypeClass.Base\n : null;\n } else {\n // Fall back to reading from SQLite column type (pipe notation)\n dataType = col.type;\n elemPgTypeClass = isArray(col.type)\n ? isEnum(col.type)\n ? PostgresTypeClass.Enum\n : PostgresTypeClass.Base\n : null;\n }\n\n table.columns[col.name] = {\n pos: Object.keys(table.columns).length + 1,\n dataType,\n characterMaximumLength: null,\n notNull: col.notNull !== 0,\n dflt: col.dflt,\n elemPgTypeClass,\n };\n if (metadata?.isBackfilling) {\n table.backfilling.push(col.name);\n }\n if (col.keyPos) {\n table.primaryKey ??= [];\n while (table.primaryKey.length < col.keyPos) {\n table.primaryKey.push('');\n }\n table.primaryKey[col.keyPos - 1] = col.name;\n }\n });\n\n return tables;\n}\n\n/**\n * An index as it exists on the replica. SQLite retains only the DDL text of a\n * partial index, not a structured predicate, so replica indexes report a\n * `partial` flag in place of the {@link LiteIndexSpec.predicate}.\n */\nexport type ReplicaIndexSpec = Omit<LiteIndexSpec, 'predicate'> & {\n readonly partial?: boolean | undefined;\n};\n\ntype MutableReplicaIndexSpec = Omit<MutableLiteIndexSpec, 'predicate'> & {\n partial?: boolean | undefined;\n};\n\nexport function listIndexes(db: Database): ReplicaIndexSpec[] {\n const indexes = db\n .prepare(\n `SELECT \n idx.name as indexName, \n idx.tbl_name as tableName, \n info.\"unique\" as \"unique\",\n info.partial as partial,\n col.name as column,\n CASE WHEN col.desc = 0 THEN 'ASC' ELSE 'DESC' END as dir\n FROM sqlite_master as idx\n JOIN pragma_index_list(idx.tbl_name) AS info ON info.name = idx.name\n JOIN pragma_index_xinfo(idx.name) as col\n WHERE idx.type = 'index' AND \n col.key = 1 AND\n idx.tbl_name NOT LIKE '_zero.%'\n ORDER BY idx.name, col.seqno ASC`,\n )\n .all() as {\n indexName: string;\n tableName: string;\n unique: number;\n partial: number;\n column: string;\n dir: 'ASC' | 'DESC';\n }[];\n\n const ret: MutableReplicaIndexSpec[] = [];\n for (const {\n indexName: name,\n tableName,\n unique,\n partial,\n column,\n dir,\n } of indexes) {\n if (ret.at(-1)?.name === name) {\n // Aggregate multiple column names into the array.\n must(ret.at(-1)).columns[column] = dir;\n } else {\n ret.push({\n tableName,\n name,\n columns: {[column]: dir},\n unique: unique !== 0,\n ...(partial === 0 ? {} : {partial: true}),\n });\n }\n }\n\n return ret;\n}\n\nexport type ZqlSpecOptions = {\n /**\n * Controls whether to include backfilling columns in the computed\n * LiteAndZqlSpec. In general, backfilling columns should be include\n * in \"replication\" logic (copying data from upstream to the replica),\n * and excluded from \"sync\" logic (sending data from the replica to\n * clients).\n */\n includeBackfillingColumns: boolean;\n};\n\n/**\n * Computes a TableSpec \"view\" of the replicated data that is\n * suitable for processing / consumption for the client. This\n * includes:\n * * excluding tables without a PRIMARY KEY or UNIQUE INDEX\n * * excluding columns with types that are not supported by ZQL\n * * choosing columns to use as the primary key amongst those\n * in unique indexes\n *\n * @param tableSpecs an optional map to reset and populate\n * @param fullTables an optional map to receive the full table specs,\n * which may include tables and columns that are not synced to\n * the client because they lack a primary key or are of unsupported\n * data types.\n */\nexport function computeZqlSpecs(\n lc: LogContext,\n replica: Database,\n opts: ZqlSpecOptions,\n tableSpecs: Map<string, LiteAndZqlSpec> = new Map(),\n fullTables?: Map<string, LiteTableSpec>,\n): Map<string, LiteAndZqlSpec> {\n return computeZqlSpecsFromLiteSpecs(\n listTables(replica),\n listIndexes(replica),\n opts,\n tableSpecs,\n fullTables,\n lc,\n );\n}\n\nfunction isPartialIndex(idx: LiteIndexSpec | ReplicaIndexSpec): boolean {\n return (\n ('predicate' in idx && idx.predicate !== undefined) ||\n ('partial' in idx && idx.partial === true)\n );\n}\n\nexport function computeZqlSpecsFromLiteSpecs(\n tables: LiteTableSpecWithReplicationStatus[],\n indexes: readonly (LiteIndexSpec | ReplicaIndexSpec)[],\n {includeBackfillingColumns}: ZqlSpecOptions,\n tableSpecs: Map<string, LiteAndZqlSpec> = new Map(),\n fullTables?: Map<string, LiteTableSpec>,\n lc?: LogContext,\n): Map<string, LiteAndZqlSpec> {\n tableSpecs.clear();\n fullTables?.clear();\n\n const uniqueIndexColumns = new Map<string, string[][]>();\n // A partial unique index only constrains the rows matching its predicate,\n // so it cannot serve as a row key.\n for (const {tableName, columns} of indexes.filter(\n idx => idx.unique && !isPartialIndex(idx),\n )) {\n if (!uniqueIndexColumns.has(tableName)) {\n uniqueIndexColumns.set(tableName, []);\n }\n uniqueIndexColumns.get(tableName)?.push(Object.keys(columns));\n }\n\n tables.forEach(fullTable => {\n fullTables?.set(fullTable.name, fullTable);\n\n const backfilling = new Set(fullTable.backfilling);\n // Only include columns that:\n // - have a defined ZQL Value\n // - aren't backfilling if `includeBackfillingColumns` is false\n const visibleColumns = Object.entries(fullTable.columns).filter(\n ([col, {dataType}]) =>\n liteTypeToZqlValueType(dataType) &&\n (includeBackfillingColumns || !backfilling.has(col)),\n );\n const notNullColumns = new Set(\n visibleColumns\n .filter(\n ([col, {dataType}]) =>\n !nullableUpstream(dataType) || fullTable.primaryKey?.includes(col),\n )\n .map(([col]) => col),\n );\n\n const uniqueKeys = uniqueIndexColumns.get(fullTable.name) ?? [];\n // Examine all column combinations that can serve as a primary key,\n // i.e. excluding indexes over nullable or unsynced columns.\n const keys = uniqueKeys.filter(\n key => difference(new Set(key), notNullColumns).size === 0,\n );\n if (keys.length === 0) {\n // Only include tables with a row key.\n //\n // Note that this will automatically exclude tables that are being\n // backfilled (when includeBackfillingColumns is `false`) since candidate\n // keys only include visible columns.\n lc?.debug?.(\n `not syncing table ${fullTable.name} because it ` +\n (backfilling.size ? 'is being backfilled' : 'has no primary key'),\n );\n return;\n }\n // Pick the \"best\" (i.e. shortest) key for default IVM operations.\n const primaryKey = keys.sort(keyCmp)[0];\n\n const tableSpec = {\n ...fullTable,\n columns: Object.fromEntries(visibleColumns),\n primaryKey: v.parse(primaryKey, primaryKeySchema),\n uniqueKeys: uniqueKeys.map(key => v.parse(key, primaryKeySchema)),\n allPotentialPrimaryKeys: keys.map(key => v.parse(key, primaryKeySchema)),\n minRowVersion: fullTable.minRowVersion ?? null,\n };\n\n tableSpecs.set(tableSpec.name, {\n tableSpec,\n zqlSpec: Object.fromEntries(\n Object.entries(tableSpec.columns).map(([name, {dataType}]) => [\n name,\n mapLiteDataTypeToZqlSchemaValue(dataType),\n ]),\n ),\n });\n });\n return tableSpecs;\n}\n\nexport function mustGetTableSpec(\n tableSpecs: Map<string, LiteAndZqlSpec>,\n tableName: string,\n): LiteAndZqlSpec {\n const tableSpec = tableSpecs.get(tableName);\n if (!tableSpec) {\n throw new Error(\n `table '${tableName}' is not one of: ${[...tableSpecs.keys()]\n .filter(t => !t.includes('.') && !t.startsWith('_litestream_'))\n .sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n }\n return tableSpec;\n}\n\n// Deterministic comparator for favoring shorter row keys.\nfunction keyCmp(a: string[], b: string[]) {\n if (a.length !== b.length) {\n return a.length - b.length; // Fewer columns are better.\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] < b[i]) {\n return -1;\n }\n if (a[i] > b[i]) {\n return 1;\n }\n }\n return 0;\n}\n"],"mappings":"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"}
|
|
@@ -13,6 +13,17 @@ export declare const columnSpec: v.ObjectType<{
|
|
|
13
13
|
dflt: v.Optional<string | null>;
|
|
14
14
|
}, undefined>;
|
|
15
15
|
export type ColumnSpec = Readonly<v.Infer<typeof columnSpec>>;
|
|
16
|
+
export declare const publishedColumnSpec: v.ObjectType<Omit<{
|
|
17
|
+
pos: v.Type<number>;
|
|
18
|
+
dataType: v.Type<string>;
|
|
19
|
+
pgTypeClass: v.Optional<"e" | "d" | "b" | "c" | "p" | "r" | "m">;
|
|
20
|
+
elemPgTypeClass: v.Optional<"e" | "d" | "b" | "c" | "p" | "r" | "m" | null>;
|
|
21
|
+
characterMaximumLength: v.Optional<number | null>;
|
|
22
|
+
notNull: v.Optional<boolean | null>;
|
|
23
|
+
dflt: v.Optional<string | null>;
|
|
24
|
+
}, "typeOID"> & {
|
|
25
|
+
typeOID: v.Type<number>;
|
|
26
|
+
}, undefined>;
|
|
16
27
|
export declare const liteTableSpec: v.ObjectType<{
|
|
17
28
|
name: v.Type<string>;
|
|
18
29
|
columns: v.Type<Record<string, {
|
|
@@ -106,11 +117,39 @@ export type LiteAndZqlSpec = {
|
|
|
106
117
|
export type TableSpec = Readonly<v.Infer<typeof tableSpec>>;
|
|
107
118
|
export type PublishedTableSpec = Readonly<v.Infer<typeof publishedTableSpec>>;
|
|
108
119
|
export declare const directionSchema: v.Type<"ASC" | "DESC">;
|
|
120
|
+
export type IndexPredicateValue = {
|
|
121
|
+
readonly type: 'boolean';
|
|
122
|
+
readonly value: boolean;
|
|
123
|
+
} | {
|
|
124
|
+
readonly type: 'integer';
|
|
125
|
+
readonly value: string;
|
|
126
|
+
} | {
|
|
127
|
+
readonly type: 'string';
|
|
128
|
+
readonly value: string;
|
|
129
|
+
};
|
|
130
|
+
export type IndexPredicate = {
|
|
131
|
+
readonly type: 'and' | 'or';
|
|
132
|
+
readonly conditions: readonly IndexPredicate[];
|
|
133
|
+
} | {
|
|
134
|
+
readonly type: 'not';
|
|
135
|
+
readonly condition: IndexPredicate;
|
|
136
|
+
} | {
|
|
137
|
+
readonly type: 'null-test';
|
|
138
|
+
readonly column: string;
|
|
139
|
+
readonly op: 'IS NULL' | 'IS NOT NULL';
|
|
140
|
+
} | {
|
|
141
|
+
readonly type: 'comparison';
|
|
142
|
+
readonly column: string;
|
|
143
|
+
readonly op: '=' | '<>' | '<' | '<=' | '>' | '>=';
|
|
144
|
+
readonly value: IndexPredicateValue;
|
|
145
|
+
};
|
|
146
|
+
export declare const indexPredicateSchema: v.Type<IndexPredicate>;
|
|
109
147
|
export declare const liteIndexSpec: v.ObjectType<{
|
|
110
148
|
name: v.Type<string>;
|
|
111
149
|
tableName: v.Type<string>;
|
|
112
150
|
unique: v.Type<boolean>;
|
|
113
151
|
columns: v.Type<Record<string, "ASC" | "DESC">>;
|
|
152
|
+
predicate: v.Optional<IndexPredicate>;
|
|
114
153
|
}, undefined>;
|
|
115
154
|
export type MutableLiteIndexSpec = v.Infer<typeof liteIndexSpec>;
|
|
116
155
|
export type LiteIndexSpec = Readonly<MutableLiteIndexSpec>;
|
|
@@ -119,6 +158,7 @@ export declare const indexSpec: v.ObjectType<Omit<{
|
|
|
119
158
|
tableName: v.Type<string>;
|
|
120
159
|
unique: v.Type<boolean>;
|
|
121
160
|
columns: v.Type<Record<string, "ASC" | "DESC">>;
|
|
161
|
+
predicate: v.Optional<IndexPredicate>;
|
|
122
162
|
}, "schema"> & {
|
|
123
163
|
schema: v.Type<string>;
|
|
124
164
|
}, undefined>;
|
|
@@ -128,6 +168,7 @@ export declare const publishedIndexSpec: v.ObjectType<Omit<Omit<{
|
|
|
128
168
|
tableName: v.Type<string>;
|
|
129
169
|
unique: v.Type<boolean>;
|
|
130
170
|
columns: v.Type<Record<string, "ASC" | "DESC">>;
|
|
171
|
+
predicate: v.Optional<IndexPredicate>;
|
|
131
172
|
}, "schema"> & {
|
|
132
173
|
schema: v.Type<string>;
|
|
133
174
|
}, "isReplicaIdentity" | "isPrimaryKey" | "isImmediate"> & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specs.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/specs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,CAAC,MAAM,+BAA+B,CAAC;AACnD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAC1E,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,0CAA0C,CAAC;AAI1E,eAAO,MAAM,iBAAiB,iDAQ7B,CAAC;AASF,eAAO,MAAM,UAAU;;;;;;;;aAarB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"specs.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/db/specs.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { literalUnion, valita_exports } from "../../../shared/src/valita.js";
|
|
1
|
+
import { literalUnion, readonlyArray, readonlyObject, valita_exports } from "../../../shared/src/valita.js";
|
|
2
2
|
//#region ../zero-cache/src/db/specs.ts
|
|
3
3
|
var pgTypeClassSchema = literalUnion("b", "c", "d", "e", "p", "r", "m");
|
|
4
4
|
var pgReplicaIdentitySchema = literalUnion("d", "n", "f", "i");
|
|
@@ -25,11 +25,38 @@ var publishedTableSpec = tableSpec.extend({
|
|
|
25
25
|
publications: valita_exports.record(valita_exports.object({ rowFilter: valita_exports.string().nullable() }))
|
|
26
26
|
});
|
|
27
27
|
var directionSchema = literalUnion("ASC", "DESC");
|
|
28
|
+
var indexPredicateValueSchema = valita_exports.union(readonlyObject({
|
|
29
|
+
type: valita_exports.literal("boolean"),
|
|
30
|
+
value: valita_exports.boolean()
|
|
31
|
+
}), readonlyObject({
|
|
32
|
+
type: valita_exports.literal("integer"),
|
|
33
|
+
value: valita_exports.string()
|
|
34
|
+
}), readonlyObject({
|
|
35
|
+
type: valita_exports.literal("string"),
|
|
36
|
+
value: valita_exports.string()
|
|
37
|
+
}));
|
|
38
|
+
var indexPredicateSchema = valita_exports.lazy(() => valita_exports.union(readonlyObject({
|
|
39
|
+
type: literalUnion("and", "or"),
|
|
40
|
+
conditions: readonlyArray(indexPredicateSchema)
|
|
41
|
+
}), readonlyObject({
|
|
42
|
+
type: valita_exports.literal("not"),
|
|
43
|
+
condition: indexPredicateSchema
|
|
44
|
+
}), readonlyObject({
|
|
45
|
+
type: valita_exports.literal("null-test"),
|
|
46
|
+
column: valita_exports.string(),
|
|
47
|
+
op: literalUnion("IS NULL", "IS NOT NULL")
|
|
48
|
+
}), readonlyObject({
|
|
49
|
+
type: valita_exports.literal("comparison"),
|
|
50
|
+
column: valita_exports.string(),
|
|
51
|
+
op: literalUnion("=", "<>", "<", "<=", ">", ">="),
|
|
52
|
+
value: indexPredicateValueSchema
|
|
53
|
+
})));
|
|
28
54
|
var indexSpec = valita_exports.object({
|
|
29
55
|
name: valita_exports.string(),
|
|
30
56
|
tableName: valita_exports.string(),
|
|
31
57
|
unique: valita_exports.boolean(),
|
|
32
|
-
columns: valita_exports.record(directionSchema)
|
|
58
|
+
columns: valita_exports.record(directionSchema),
|
|
59
|
+
predicate: indexPredicateSchema.optional()
|
|
33
60
|
}).extend({ schema: valita_exports.string() });
|
|
34
61
|
var publishedIndexSpec = indexSpec.extend({
|
|
35
62
|
isReplicaIdentity: valita_exports.boolean().optional(),
|
|
@@ -37,6 +64,6 @@ var publishedIndexSpec = indexSpec.extend({
|
|
|
37
64
|
isImmediate: valita_exports.boolean().optional()
|
|
38
65
|
});
|
|
39
66
|
//#endregion
|
|
40
|
-
export { columnSpec, indexSpec, publishedIndexSpec, publishedTableSpec, tableSpec };
|
|
67
|
+
export { columnSpec, indexSpec, publishedColumnSpec, publishedIndexSpec, publishedTableSpec, tableSpec };
|
|
41
68
|
|
|
42
69
|
//# sourceMappingURL=specs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specs.js","names":[],"sources":["../../../../../zero-cache/src/db/specs.ts"],"sourcesContent":["import type {DeepReadonly} from '../../../shared/src/json.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport type {SchemaValue} from '../../../zero-schema/src/table-schema.ts';\nimport * as PostgresReplicaIdentity from './postgres-replica-identity-enum.ts';\nimport * as PostgresTypeClass from './postgres-type-class-enum.ts';\n\nexport const pgTypeClassSchema = v.literalUnion(\n PostgresTypeClass.Base,\n PostgresTypeClass.Composite,\n PostgresTypeClass.Domain,\n PostgresTypeClass.Enum,\n PostgresTypeClass.Pseudo,\n PostgresTypeClass.Range,\n PostgresTypeClass.Multirange,\n);\n\nconst pgReplicaIdentitySchema = v.literalUnion(\n PostgresReplicaIdentity.Default,\n PostgresReplicaIdentity.Nothing,\n PostgresReplicaIdentity.Full,\n PostgresReplicaIdentity.Index,\n);\n\nexport const columnSpec = v.object({\n pos: v.number(),\n dataType: v.string(),\n pgTypeClass: pgTypeClassSchema.optional(),\n\n // If the column is an array, this will be the type of the\n // elements in the array. If the column is not an array,\n // this will be null.\n elemPgTypeClass: pgTypeClassSchema.nullable().optional(),\n\n characterMaximumLength: v.number().nullable().optional(),\n notNull: v.boolean().nullable().optional(),\n dflt: v.string().nullable().optional(),\n});\n\nexport type ColumnSpec = Readonly<v.Infer<typeof columnSpec>>;\n\
|
|
1
|
+
{"version":3,"file":"specs.js","names":[],"sources":["../../../../../zero-cache/src/db/specs.ts"],"sourcesContent":["import type {DeepReadonly} from '../../../shared/src/json.ts';\nimport * as v from '../../../shared/src/valita.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport type {SchemaValue} from '../../../zero-schema/src/table-schema.ts';\nimport * as PostgresReplicaIdentity from './postgres-replica-identity-enum.ts';\nimport * as PostgresTypeClass from './postgres-type-class-enum.ts';\n\nexport const pgTypeClassSchema = v.literalUnion(\n PostgresTypeClass.Base,\n PostgresTypeClass.Composite,\n PostgresTypeClass.Domain,\n PostgresTypeClass.Enum,\n PostgresTypeClass.Pseudo,\n PostgresTypeClass.Range,\n PostgresTypeClass.Multirange,\n);\n\nconst pgReplicaIdentitySchema = v.literalUnion(\n PostgresReplicaIdentity.Default,\n PostgresReplicaIdentity.Nothing,\n PostgresReplicaIdentity.Full,\n PostgresReplicaIdentity.Index,\n);\n\nexport const columnSpec = v.object({\n pos: v.number(),\n dataType: v.string(),\n pgTypeClass: pgTypeClassSchema.optional(),\n\n // If the column is an array, this will be the type of the\n // elements in the array. If the column is not an array,\n // this will be null.\n elemPgTypeClass: pgTypeClassSchema.nullable().optional(),\n\n characterMaximumLength: v.number().nullable().optional(),\n notNull: v.boolean().nullable().optional(),\n dflt: v.string().nullable().optional(),\n});\n\nexport type ColumnSpec = Readonly<v.Infer<typeof columnSpec>>;\n\nexport const publishedColumnSpec = columnSpec.extend({\n typeOID: v.number(),\n});\n\nexport const liteTableSpec = v.object({\n name: v.string(),\n columns: v.record(columnSpec),\n primaryKey: v.array(v.string()).optional(),\n});\n\nexport const tableSpec = liteTableSpec.extend({\n schema: v.string(),\n});\n\nexport const publishedTableSpec = tableSpec.extend({\n oid: v.number(),\n // Always present for new instances (e.g. from DDL triggers), but\n // may from `initialSchema` object stored in the `replicas` table.\n schemaOID: v.number().optional(),\n columns: v.record(publishedColumnSpec),\n replicaIdentity: pgReplicaIdentitySchema.optional(),\n publications: v.record(v.object({rowFilter: v.string().nullable()})),\n});\n\nexport type MutableLiteTableSpec = v.Infer<typeof liteTableSpec>;\n\nexport type LiteTableSpec = Readonly<MutableLiteTableSpec>;\n\nexport type LiteTableSpecWithKeysAndVersion = Omit<\n LiteTableSpec,\n 'primaryKey'\n> & {\n /**\n * All keys associated with a unique index. Includes indexes with\n * nullable columns.\n */\n uniqueKeys: PrimaryKey[];\n\n /**\n * The key selected to act as the \"primary key\". Primary keys\n * are not explicitly set on the replica, but an appropriate\n * unique index is required.\n */\n primaryKey: PrimaryKey; // note: required\n\n /**\n * All keys associated with a unique index over non-null\n * columns, i.e. suitable as a primary key.\n */\n allPotentialPrimaryKeys: PrimaryKey[];\n\n /**\n * The minimum `_0_version` value for every row in the table. If this is\n * present, `_0_version` value in the row itself should only be used if\n * it is greater (i.e. later) than the `minRowVersion`.\n */\n minRowVersion: string | null;\n};\n\nexport type LiteAndZqlSpec = {\n tableSpec: LiteTableSpecWithKeysAndVersion;\n zqlSpec: Record<string, SchemaValue>;\n};\n\nexport type TableSpec = Readonly<v.Infer<typeof tableSpec>>;\n\nexport type PublishedTableSpec = Readonly<v.Infer<typeof publishedTableSpec>>;\n\nexport const directionSchema = v.literalUnion('ASC', 'DESC');\n\nexport type IndexPredicateValue =\n | {readonly type: 'boolean'; readonly value: boolean}\n | {readonly type: 'integer'; readonly value: string}\n | {readonly type: 'string'; readonly value: string};\n\nexport type IndexPredicate =\n | {\n readonly type: 'and' | 'or';\n readonly conditions: readonly IndexPredicate[];\n }\n | {readonly type: 'not'; readonly condition: IndexPredicate}\n | {\n readonly type: 'null-test';\n readonly column: string;\n readonly op: 'IS NULL' | 'IS NOT NULL';\n }\n | {\n readonly type: 'comparison';\n readonly column: string;\n readonly op: '=' | '<>' | '<' | '<=' | '>' | '>=';\n readonly value: IndexPredicateValue;\n };\n\nconst indexPredicateValueSchema: v.Type<IndexPredicateValue> = v.union(\n v.readonlyObject({type: v.literal('boolean'), value: v.boolean()}),\n v.readonlyObject({type: v.literal('integer'), value: v.string()}),\n v.readonlyObject({type: v.literal('string'), value: v.string()}),\n);\n\nexport const indexPredicateSchema: v.Type<IndexPredicate> = v.lazy(() =>\n v.union(\n v.readonlyObject({\n type: v.literalUnion('and', 'or'),\n conditions: v.readonlyArray(indexPredicateSchema),\n }),\n v.readonlyObject({\n type: v.literal('not'),\n condition: indexPredicateSchema,\n }),\n v.readonlyObject({\n type: v.literal('null-test'),\n column: v.string(),\n op: v.literalUnion('IS NULL', 'IS NOT NULL'),\n }),\n v.readonlyObject({\n type: v.literal('comparison'),\n column: v.string(),\n op: v.literalUnion('=', '<>', '<', '<=', '>', '>='),\n value: indexPredicateValueSchema,\n }),\n ),\n);\n\nexport const liteIndexSpec = v.object({\n name: v.string(),\n tableName: v.string(),\n unique: v.boolean(),\n columns: v.record(directionSchema),\n predicate: indexPredicateSchema.optional(),\n});\n\nexport type MutableLiteIndexSpec = v.Infer<typeof liteIndexSpec>;\n\nexport type LiteIndexSpec = Readonly<MutableLiteIndexSpec>;\n\nexport const indexSpec = liteIndexSpec.extend({\n schema: v.string(),\n});\n\nexport type IndexSpec = DeepReadonly<v.Infer<typeof indexSpec>>;\n\nexport const publishedIndexSpec = indexSpec.extend({\n isReplicaIdentity: v.boolean().optional(),\n isPrimaryKey: v.boolean().optional(),\n isImmediate: v.boolean().optional(),\n});\n\nexport type PublishedIndexSpec = DeepReadonly<\n v.Infer<typeof publishedIndexSpec>\n>;\n"],"mappings":";;AAOA,IAAa,oBAAoB,aAC/B,KACA,KACA,KACA,KACA,KACA,KACA,GACF;AAEA,IAAM,0BAA0B,aAC9B,KACA,KACA,KACA,GACF;AAEA,IAAa,aAAa,eAAE,OAAO;CACjC,KAAK,eAAE,OAAO;CACd,UAAU,eAAE,OAAO;CACnB,aAAa,kBAAkB,SAAS;CAKxC,iBAAiB,kBAAkB,SAAS,EAAE,SAAS;CAEvD,wBAAwB,eAAE,OAAO,EAAE,SAAS,EAAE,SAAS;CACvD,SAAS,eAAE,QAAQ,EAAE,SAAS,EAAE,SAAS;CACzC,MAAM,eAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AACvC,CAAC;AAID,IAAa,sBAAsB,WAAW,OAAO,EACnD,SAAS,eAAE,OAAO,EACpB,CAAC;AAQD,IAAa,YANgB,eAAE,OAAO;CACpC,MAAM,eAAE,OAAO;CACf,SAAS,eAAE,OAAO,UAAU;CAC5B,YAAY,eAAE,MAAM,eAAE,OAAO,CAAC,EAAE,SAAS;AAC3C,CAEyB,EAAc,OAAO,EAC5C,QAAQ,eAAE,OAAO,EACnB,CAAC;AAED,IAAa,qBAAqB,UAAU,OAAO;CACjD,KAAK,eAAE,OAAO;CAGd,WAAW,eAAE,OAAO,EAAE,SAAS;CAC/B,SAAS,eAAE,OAAO,mBAAmB;CACrC,iBAAiB,wBAAwB,SAAS;CAClD,cAAc,eAAE,OAAO,eAAE,OAAO,EAAC,WAAW,eAAE,OAAO,EAAE,SAAS,EAAC,CAAC,CAAC;AACrE,CAAC;AA8CD,IAAa,kBAAkB,aAAe,OAAO,MAAM;AAyB3D,IAAM,4BAAyD,eAAE,MAC/D,eAAiB;CAAC,MAAM,eAAE,QAAQ,SAAS;CAAG,OAAO,eAAE,QAAQ;AAAC,CAAC,GACjE,eAAiB;CAAC,MAAM,eAAE,QAAQ,SAAS;CAAG,OAAO,eAAE,OAAO;AAAC,CAAC,GAChE,eAAiB;CAAC,MAAM,eAAE,QAAQ,QAAQ;CAAG,OAAO,eAAE,OAAO;AAAC,CAAC,CACjE;AAEA,IAAa,uBAA+C,eAAE,WAC5D,eAAE,MACA,eAAiB;CACf,MAAM,aAAe,OAAO,IAAI;CAChC,YAAY,cAAgB,oBAAoB;AAClD,CAAC,GACD,eAAiB;CACf,MAAM,eAAE,QAAQ,KAAK;CACrB,WAAW;AACb,CAAC,GACD,eAAiB;CACf,MAAM,eAAE,QAAQ,WAAW;CAC3B,QAAQ,eAAE,OAAO;CACjB,IAAI,aAAe,WAAW,aAAa;AAC7C,CAAC,GACD,eAAiB;CACf,MAAM,eAAE,QAAQ,YAAY;CAC5B,QAAQ,eAAE,OAAO;CACjB,IAAI,aAAe,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI;CAClD,OAAO;AACT,CAAC,CACH,CACF;AAcA,IAAa,YAZgB,eAAE,OAAO;CACpC,MAAM,eAAE,OAAO;CACf,WAAW,eAAE,OAAO;CACpB,QAAQ,eAAE,QAAQ;CAClB,SAAS,eAAE,OAAO,eAAe;CACjC,WAAW,qBAAqB,SAAS;AAC3C,CAMyB,EAAc,OAAO,EAC5C,QAAQ,eAAE,OAAO,EACnB,CAAC;AAID,IAAa,qBAAqB,UAAU,OAAO;CACjD,mBAAmB,eAAE,QAAQ,EAAE,SAAS;CACxC,cAAc,eAAE,QAAQ,EAAE,SAAS;CACnC,aAAa,eAAE,QAAQ,EAAE,SAAS;AACpC,CAAC"}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import type { LogContext } from '@rocicorp/logger';
|
|
2
2
|
import * as v from '../../../../../shared/src/valita.ts';
|
|
3
|
-
import type { PublishedTableSpec } from '../../../db/specs.ts';
|
|
3
|
+
import type { PublishedIndexSpec, PublishedTableSpec } from '../../../db/specs.ts';
|
|
4
4
|
import { type LexiVersion } from '../../../types/lexi-version.ts';
|
|
5
5
|
import { type PostgresDB } from '../../../types/pg.ts';
|
|
6
6
|
import { type ShardConfig, type ShardID } from '../../../types/shards.ts';
|
|
7
7
|
import type { Sink } from '../../../types/streams.ts';
|
|
8
|
+
import type { ChangeSource, ChangeStream } from '../change-source.ts';
|
|
8
9
|
import { type Listener } from '../common/change-stream-multiplexer.ts';
|
|
9
10
|
import { type InitializeResult, type RestoreOptions } from '../common/replica-restore.ts';
|
|
10
|
-
import type { DownstreamStatusMessage } from '../protocol/current.ts';
|
|
11
|
+
import type { BackfillRequest, DownstreamStatusMessage } from '../protocol/current.ts';
|
|
11
12
|
import type { ChangeStreamMessage } from '../protocol/current/downstream.ts';
|
|
13
|
+
import { streamBackfill } from './backfill-stream.ts';
|
|
12
14
|
import { type InitialSyncOptions, type ReplicaOptions, type ServerContext } from './initial-sync.ts';
|
|
13
15
|
import type { MessageMessage, MessageRelation as PostgresRelation } from './logical-replication/pgoutput.types.ts';
|
|
16
|
+
import { subscribe } from './logical-replication/stream.ts';
|
|
17
|
+
import { type PublishedTableWithReplicaIdentity } from './schema/published.ts';
|
|
18
|
+
import { type BackupOptions, type InternalShardConfig, type Replica } from './schema/shard.ts';
|
|
14
19
|
interface PurgeLock {
|
|
15
20
|
release(): Promise<void>;
|
|
16
21
|
}
|
|
@@ -20,6 +25,24 @@ interface PurgeLock {
|
|
|
20
25
|
* stream.
|
|
21
26
|
*/
|
|
22
27
|
export declare function initializePostgresChangeSource(lc: LogContext, upstreamURI: string, shard: ShardConfig, replicaDbFile: string, syncOptions: InitialSyncOptions, context: ServerContext, lagReportIntervalMs?: number, restoreOptions?: RestoreOptions, { backupV5 }?: ReplicaOptions, purgeLock?: PurgeLock | null, streamInboundTimeoutMs?: number | undefined): Promise<InitializeResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Postgres implementation of a {@link ChangeSource} backed by a logical
|
|
30
|
+
* replication stream.
|
|
31
|
+
*/
|
|
32
|
+
export declare class PostgresChangeSource implements ChangeSource {
|
|
33
|
+
#private;
|
|
34
|
+
constructor(lc: LogContext, upstreamUri: string, shard: ShardID, replica: Replica, backupOptions: BackupOptions, context: ServerContext, lagReportIntervalMs: number, textCopy?: boolean | undefined, streamInboundTimeoutMs?: number | undefined, deps?: {
|
|
35
|
+
subscribe?: typeof subscribe;
|
|
36
|
+
streamBackfill?: typeof streamBackfill;
|
|
37
|
+
});
|
|
38
|
+
stop(): Promise<void>;
|
|
39
|
+
startLagReporter(): Promise<{
|
|
40
|
+
firstCommitTimeMs: number;
|
|
41
|
+
nextSendTimeMs: number;
|
|
42
|
+
} | null>;
|
|
43
|
+
startStream(clientWatermark: string, backfillRequests?: BackfillRequest[]): Promise<ChangeStream>;
|
|
44
|
+
startStreamInternal(slot: string, clientWatermark: string, shardConfig: InternalShardConfig, backfillRequests: BackfillRequest[]): Promise<ChangeStream>;
|
|
45
|
+
}
|
|
23
46
|
export declare class Acker implements Listener {
|
|
24
47
|
#private;
|
|
25
48
|
constructor(acks: Sink<bigint>);
|
|
@@ -66,5 +89,14 @@ export declare class LagReporter {
|
|
|
66
89
|
processLagReportMessage(msg: MessageMessage): DownstreamStatusMessage;
|
|
67
90
|
}
|
|
68
91
|
export declare function relationDifferent(a: PublishedTableSpec, b: PostgresRelation): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Determines if an index was structurally changed (e.g. constraint dropped
|
|
94
|
+
* and recreated with different columns) vs cosmetically changed (e.g. the
|
|
95
|
+
* index spec changed because the table or a column was renamed).
|
|
96
|
+
*
|
|
97
|
+
* Compares boolean properties directly and resolves column names to their
|
|
98
|
+
* stable attnums (pg_attribute `attnum`) for the column comparison.
|
|
99
|
+
*/
|
|
100
|
+
export declare function isIndexStructurallyChanged(prev: PublishedIndexSpec, next: PublishedIndexSpec, prevTables: Map<number, PublishedTableWithReplicaIdentity>, nextTables: Map<number, PublishedTableWithReplicaIdentity>): boolean;
|
|
69
101
|
export {};
|
|
70
102
|
//# sourceMappingURL=change-source.d.ts.map
|
|
@@ -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;AAcjD,OAAO,KAAK,CAAC,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"change-source.d.ts","sourceRoot":"","sources":["../../../../../../../zero-cache/src/services/change-source/pg/change-source.ts"],"names":[],"mappings":"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"}
|