@rocicorp/zero 1.8.0-canary.1 → 1.8.0-canary.2

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.
@@ -1,6 +1,6 @@
1
1
  var package_default = {
2
2
  name: "@rocicorp/zero",
3
- version: "1.8.0-canary.1",
3
+ version: "1.8.0-canary.2",
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" },
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.8.0-canary.1\",\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.2\",\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 \"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 \"peerDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"drizzle-orm\": \"^0.45.2\",\n \"expo-sqlite\": \">=15\",\n \"kysely\": \"^0.28.17\",\n \"pg\": \"^8.16.3\",\n \"react\": \"^19.2.6\",\n \"solid-js\": \"^1.9.4\"\n },\n \"peerDependenciesMeta\": {\n \"@op-engineering/op-sqlite\": {\n \"optional\": true\n },\n \"drizzle-orm\": {\n \"optional\": true\n },\n \"expo-sqlite\": {\n \"optional\": true\n },\n \"kysely\": {\n \"optional\": true\n },\n \"pg\": {\n \"optional\": true\n },\n \"react\": {\n \"optional\": true\n },\n \"solid-js\": {\n \"optional\": true\n }\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"pnpm@11.5.3\"\n}\n"],"mappings":""}
1
+ {"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.8.0-canary.2\",\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.2\",\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 \"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 \"peerDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"drizzle-orm\": \"^0.45.2\",\n \"expo-sqlite\": \">=15\",\n \"kysely\": \"^0.28.17\",\n \"pg\": \"^8.16.3\",\n \"react\": \"^19.2.6\",\n \"solid-js\": \"^1.9.4\"\n },\n \"peerDependenciesMeta\": {\n \"@op-engineering/op-sqlite\": {\n \"optional\": true\n },\n \"drizzle-orm\": {\n \"optional\": true\n },\n \"expo-sqlite\": {\n \"optional\": true\n },\n \"kysely\": {\n \"optional\": true\n },\n \"pg\": {\n \"optional\": true\n },\n \"react\": {\n \"optional\": true\n },\n \"solid-js\": {\n \"optional\": true\n }\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"pnpm@11.5.3\"\n}\n"],"mappings":""}
@@ -1,6 +1,6 @@
1
1
  import { parse, valita_exports } from "../../../../shared/src/valita.js";
2
2
  import { Database } from "../../../../zqlite/src/db.js";
3
- import SQLite3Database from "@rocicorp/zero-sqlite3";
3
+ import Sqlite3Database from "@rocicorp/zero-sqlite3";
4
4
  //#region ../zero-cache/src/services/litestream/vfs-watermark-reader.ts
5
5
  var DEFAULT_VFS_DATABASE_URI = "file:zero-backup.db?vfs=litestream&mode=ro";
6
6
  var DEFAULT_VFS_LOG_LEVEL = "info";
@@ -27,7 +27,7 @@ var VfsBackupWatermarkReader = class {
27
27
  env["LITESTREAM_REPLICA_URL"] = options.replicaURL;
28
28
  env["LITESTREAM_LOG_LEVEL"] = (options.logLevel ?? DEFAULT_VFS_LOG_LEVEL).toUpperCase();
29
29
  setOptionalEnv(env, "LITESTREAM_LOG_FILE", options.logFile);
30
- const loaderFactory = deps.loaderFactory ?? (() => new SQLite3Database(":memory:"));
30
+ const loaderFactory = deps.loaderFactory ?? (() => new Sqlite3Database(":memory:"));
31
31
  const databaseFactory = deps.databaseFactory ?? ((lc, uri) => new Database(lc, uri, { readonly: true }));
32
32
  this.#loader = loaderFactory();
33
33
  this.#loader.loadExtension(options.extensionPath);
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * The current version of Zero.
4
4
  */
5
- var version = "1.8.0-canary.1";
5
+ var version = "1.8.0-canary.2";
6
6
  //#endregion
7
7
  export { version };
8
8
 
@@ -1,7 +1,7 @@
1
1
  import { manualSpan } from "../../otel/src/span.js";
2
2
  import { version } from "../../otel/src/version.js";
3
3
  import { trace } from "@opentelemetry/api";
4
- import SQLite3Database, { SqliteError } from "@rocicorp/zero-sqlite3";
4
+ import Sqlite3Database, { SqliteError } from "@rocicorp/zero-sqlite3";
5
5
  //#region ../zqlite/src/db.ts
6
6
  var tracer = trace.getTracer("view-syncer", version);
7
7
  var AUTO_VACUUM_INCREMENTAL = 2;
@@ -17,7 +17,7 @@ var Database = class {
17
17
  constructor(lc, path, options, slowQueryThreshold = 100) {
18
18
  try {
19
19
  this.#lc = lc.withContext("class", "Database").withContext("path", path);
20
- this.#db = new SQLite3Database(path, options);
20
+ this.#db = new Sqlite3Database(path, options);
21
21
  this.#threshold = slowQueryThreshold;
22
22
  this.pragma("case_sensitive_like = ON");
23
23
  const [{ page_size: pageSize }] = this.pragma("page_size");
@@ -112,6 +112,11 @@ function nullableAwareRangeComparison(field, value, operator, columnType) {
112
112
  if (columnType.optional !== true) return comparison;
113
113
  return operator === ">" ? sql`(${value} IS NULL OR ${comparison})` : sql`(${sql.ident(field)} IS NULL OR ${comparison})`;
114
114
  }
115
+ function sargableLeadingStartBound(field, value, operator, columnType) {
116
+ if (columnType.optional === true) return;
117
+ const inclusiveOperator = operator === ">" ? ">=" : "<=";
118
+ return sql`${sql.ident(field)} ${sql.__dangerous__rawValue(inclusiveOperator)} ${value}`;
119
+ }
115
120
  /**
116
121
  * The ordering could be complex such as:
117
122
  * `ORDER BY a ASC, b DESC, c ASC`
@@ -131,6 +136,7 @@ function nullableAwareRangeComparison(field, value, operator, columnType) {
131
136
  function gatherStartConstraints(start, reverse, order, columnTypes) {
132
137
  const constraints = [];
133
138
  const { row: from, basis } = start;
139
+ let leadingBound;
134
140
  for (let i = 0; i < order.length; i++) {
135
141
  const group = [];
136
142
  const [iField, iDirection] = order[i];
@@ -138,6 +144,7 @@ function gatherStartConstraints(start, reverse, order, columnTypes) {
138
144
  const columnType = columnTypes[iField];
139
145
  const constraintValue = toSQLiteType(from[iField], columnType.type);
140
146
  const operator = iDirection === "asc" ? reverse ? "<" : ">" : reverse ? ">" : "<";
147
+ if (i === 0) leadingBound = sargableLeadingStartBound(iField, constraintValue, operator, columnType);
141
148
  group.push(nullableAwareRangeComparison(iField, constraintValue, operator, columnType));
142
149
  } else {
143
150
  const [jField] = order[j];
@@ -151,7 +158,8 @@ function gatherStartConstraints(start, reverse, order, columnTypes) {
151
158
  const columnType = columnTypes[field];
152
159
  return nullableAwareEquality(field, toSQLiteType(from[field], columnType.type), columnType);
153
160
  }), sql` AND `)})`);
154
- return sql`(${sql.join(constraints, sql` OR `)})`;
161
+ const lexicographicStart = sql`(${sql.join(constraints, sql` OR `)})`;
162
+ return leadingBound === void 0 ? lexicographicStart : sql`(${leadingBound} AND ${lexicographicStart})`;
155
163
  }
156
164
  //#endregion
157
165
  export { buildSelectQuery, toSQLiteType };
@@ -1 +1 @@
1
- {"version":3,"file":"query-builder.js","names":[],"sources":["../../../../zqlite/src/query-builder.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport {assert} from '../../shared/src/asserts.ts';\nimport type {\n Condition,\n Ordering,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport type {\n SchemaValue,\n ValueType,\n} from '../../zero-schema/src/table-schema.ts';\nimport type {Constraint} from '../../zql/src/ivm/constraint.ts';\nimport type {MultiConstraint, Start} from '../../zql/src/ivm/operator.ts';\nimport {sql} from './internal/sql.ts';\n\n/**\n * Condition type without correlated subqueries.\n * This matches the output of transformFilters from zql/builder/filter.ts\n */\nexport type NoSubqueryCondition = Exclude<\n Condition,\n {type: 'correlatedSubquery'}\n>;\n\nexport function buildSelectQuery(\n tableName: string,\n columns: Record<string, SchemaValue>,\n constraint: Constraint | undefined,\n filters: NoSubqueryCondition | undefined,\n order: Ordering | undefined,\n reverse: boolean | undefined,\n start: Start | undefined,\n multiConstraints?: readonly MultiConstraint[] | undefined,\n) {\n let query = sql`SELECT ${sql.join(\n Object.keys(columns).map(c => sql.ident(c)),\n sql`,`,\n )} FROM ${sql.ident(tableName)}`;\n const constraints: SQLQuery[] = constraintsToSQL(constraint, columns);\n\n if (multiConstraints) {\n for (const mc of multiConstraints) {\n if (mc.length > 0) {\n constraints.push(multiConstraintToSQL(mc, columns));\n }\n }\n }\n\n if (start) {\n assert(order !== undefined, 'start requires ordering');\n constraints.push(gatherStartConstraints(start, reverse, order, columns));\n }\n\n if (filters) {\n constraints.push(filtersToSQL(filters));\n }\n\n if (constraints.length > 0) {\n query = sql`${query} WHERE ${sql.join(constraints, sql` AND `)}`;\n }\n\n if (order && order.length > 0) {\n return sql`${query} ${orderByToSQL(order, !!reverse)}`;\n }\n return query;\n}\n\nexport function constraintsToSQL(\n constraint: Constraint | undefined,\n columns: Record<string, SchemaValue>,\n) {\n if (!constraint) {\n return [];\n }\n\n const constraints: SQLQuery[] = [];\n for (const [key, value] of Object.entries(constraint)) {\n constraints.push(\n sql`${sql.ident(key)} = ${toSQLiteType(value, columns[key].type)}`,\n );\n }\n\n return constraints;\n}\n\n/**\n * Builds a single batched IN clause from a `MultiConstraint`. All entries\n * are assumed to share the same shape (the keys of the first entry);\n * FlippedJoin derives them from the same parentKey for all children.\n *\n * Single-column form: `col IN (?, ?, ?)`\n * Compound form: `(a, b) IN (VALUES (?, ?), (?, ?), …)`\n *\n * NOTE: SQLite optimizes `col IN (literal-list)` using the column's index;\n * verified via EXPLAIN QUERY PLAN — see query-builder.test.ts.\n */\nexport function multiConstraintToSQL(\n multiConstraint: MultiConstraint,\n columns: Record<string, SchemaValue>,\n): SQLQuery {\n assert(multiConstraint.length > 0, 'multiConstraint must be non-empty');\n // All entries share the same keys; pull the column list from the first.\n const keys = Object.keys(multiConstraint[0]);\n assert(keys.length > 0, 'multiConstraint entries must have at least one key');\n // Subsequent entries must share the first entry's shape — the SQL form\n // is `(col_a, col_b, …) IN VALUES (…)`, with one binding per key per\n // entry. Heterogeneous keys would silently produce incorrect bindings.\n for (let i = 1; i < multiConstraint.length; i++) {\n const entry = multiConstraint[i];\n assert(\n Object.keys(entry).length === keys.length && keys.every(k => k in entry),\n () =>\n `multiConstraint entries must share the same keys (entry 0: [${keys.join(\n ',',\n )}], entry ${i}: [${Object.keys(entry).join(',')}])`,\n );\n }\n\n if (keys.length === 1) {\n const key = keys[0];\n const colType = columns[key].type;\n return sql`${sql.ident(key)} IN (${sql.join(\n multiConstraint.map(c => sql`${toSQLiteType(c[key], colType)}`),\n sql`,`,\n )})`;\n }\n\n // Compound: `(col_a, col_b, …) IN (VALUES (?, ?, …), …)`\n const colList = sql`(${sql.join(\n keys.map(k => sql.ident(k)),\n sql`,`,\n )})`;\n const rows = multiConstraint.map(\n c =>\n sql`(${sql.join(\n keys.map(k => sql`${toSQLiteType(c[k], columns[k].type)}`),\n sql`,`,\n )})`,\n );\n return sql`${colList} IN (VALUES ${sql.join(rows, sql`,`)})`;\n}\n\nexport function orderByToSQL(order: Ordering, reverse: boolean): SQLQuery {\n if (reverse) {\n return sql`ORDER BY ${sql.join(\n order.map(\n s =>\n sql`${sql.ident(s[0])} ${sql.__dangerous__rawValue(\n s[1] === 'asc' ? 'desc' : 'asc',\n )}`,\n ),\n sql`, `,\n )}`;\n } else {\n return sql`ORDER BY ${sql.join(\n order.map(\n s => sql`${sql.ident(s[0])} ${sql.__dangerous__rawValue(s[1])}`,\n ),\n sql`, `,\n )}`;\n }\n}\n\n/**\n * Converts filters (conditions) to SQL WHERE clause.\n * This applies all filters present in the AST for a query to the source.\n */\nexport function filtersToSQL(filters: NoSubqueryCondition): SQLQuery {\n switch (filters.type) {\n case 'simple':\n return simpleConditionToSQL(filters);\n case 'and':\n return filters.conditions.length > 0\n ? sql`(${sql.join(\n filters.conditions.map(condition =>\n filtersToSQL(condition as NoSubqueryCondition),\n ),\n sql` AND `,\n )})`\n : sql`TRUE`;\n case 'or':\n return filters.conditions.length > 0\n ? sql`(${sql.join(\n filters.conditions.map(condition =>\n filtersToSQL(condition as NoSubqueryCondition),\n ),\n sql` OR `,\n )})`\n : sql`FALSE`;\n }\n}\n\nfunction simpleConditionToSQL(filter: SimpleCondition): SQLQuery {\n const {op} = filter;\n if (op === 'IN' || op === 'NOT IN') {\n switch (filter.right.type) {\n case 'literal':\n return sql`${valuePositionToSQL(\n filter.left,\n )} ${sql.__dangerous__rawValue(\n filter.op,\n )} (SELECT value FROM json_each(${JSON.stringify(\n filter.right.value,\n )}))`;\n case 'static':\n throw new Error(\n 'Static parameters must be replaced before conversion to SQL',\n );\n }\n }\n if (\n op === 'LIKE' ||\n op === 'NOT LIKE' ||\n op === 'ILIKE' ||\n op === 'NOT ILIKE'\n ) {\n return likeConditionToSQL(filter);\n }\n\n return sql`${valuePositionToSQL(filter.left)} ${sql.__dangerous__rawValue(\n filter.op,\n )} ${valuePositionToSQL(filter.right)}`;\n}\n\nfunction likeConditionToSQL(filter: SimpleCondition): SQLQuery {\n const {op} = filter;\n // Mirror Postgres pattern-matching semantics:\n // * LIKE is case-sensitive. The replica connection runs with\n // `PRAGMA case_sensitive_like = ON` (see db.ts), so the bare LIKE\n // operator is case-sensitive.\n // * ILIKE is case-insensitive. We lower() both operands using the\n // Unicode-aware lower() that @rocicorp/zero-sqlite3 provides via ICU,\n // mirroring the toLowerCase() used by the in-memory IVM matcher\n // (see zql/src/builder/like.ts).\n // * Backslash is the default escape character in Postgres and in the IVM\n // matcher, but SQLite has no default, so we specify `ESCAPE '\\'`\n // explicitly. The SQL literal '\\' is a single backslash (SQLite does not\n // process backslash escapes inside string literals).\n const caseInsensitive = op === 'ILIKE' || op === 'NOT ILIKE';\n const negated = op === 'NOT LIKE' || op === 'NOT ILIKE';\n const likeOp = sql.__dangerous__rawValue(negated ? 'NOT LIKE' : 'LIKE');\n\n const left = valuePositionToSQL(filter.left);\n const right = valuePositionToSQL(filter.right);\n if (caseInsensitive) {\n return sql`lower(${left}) ${likeOp} lower(${right}) ESCAPE '\\\\'`;\n }\n return sql`${left} ${likeOp} ${right} ESCAPE '\\\\'`;\n}\n\nfunction valuePositionToSQL(value: ValuePosition): SQLQuery {\n switch (value.type) {\n case 'column':\n return sql.ident(value.name);\n case 'literal':\n return sql`${toSQLiteType(value.value, getJsType(value.value))}`;\n case 'static':\n throw new Error(\n 'Static parameters must be replaced before conversion to SQL',\n );\n }\n}\n\nfunction getJsType(value: unknown): ValueType {\n if (value === null) {\n return 'null';\n }\n return typeof value === 'string'\n ? 'string'\n : typeof value === 'number'\n ? 'number'\n : typeof value === 'boolean'\n ? 'boolean'\n : 'json';\n}\n\nexport function toSQLiteType(v: unknown, type: ValueType): unknown {\n switch (type) {\n case 'boolean':\n return v === null ? null : v ? 1 : 0;\n case 'number':\n case 'string':\n case 'null':\n return v;\n case 'json':\n return JSON.stringify(v);\n }\n}\n\nfunction nullableAwareEquality(\n field: string,\n value: unknown,\n columnType: SchemaValue,\n): SQLQuery {\n // Use = instead of IS for non-nullable columns to enable better\n // index usage in SQLite.\n return columnType.optional === true\n ? sql`${sql.ident(field)} IS ${value}`\n : sql`${sql.ident(field)} = ${value}`;\n}\n\nfunction nullableAwareRangeComparison(\n field: string,\n value: unknown,\n operator: '>' | '<',\n columnType: SchemaValue,\n): SQLQuery {\n // For non-nullable columns, skip IS NULL checks to avoid breaking\n // SQLite's MULTI-INDEX OR optimization, which falls back to a full\n // table scan when any OR branch involves NULL.\n // See: https://github.com/rocicorp/mono/pull/5542\n const comparison = sql`${sql.ident(field)} ${sql.__dangerous__rawValue(\n operator,\n )} ${value}`;\n if (columnType.optional !== true) {\n return comparison;\n }\n\n return operator === '>'\n ? sql`(${value} IS NULL OR ${comparison})`\n : sql`(${sql.ident(field)} IS NULL OR ${comparison})`;\n}\n\n/**\n * The ordering could be complex such as:\n * `ORDER BY a ASC, b DESC, c ASC`\n *\n * In those cases, we need to encode the constraints as various\n * `OR` clauses.\n *\n * E.g.,\n *\n * to get the row after (a = 1, b = 2, c = 3) would be:\n *\n * `WHERE a > 1 OR (a = 1 AND b < 2) OR (a = 1 AND b = 2 AND c > 3)`\n *\n * - after vs before flips the comparison operators.\n * - inclusive adds a final `OR` clause for the exact match.\n */\nfunction gatherStartConstraints(\n start: Start,\n reverse: boolean | undefined,\n order: Ordering,\n columnTypes: Record<string, SchemaValue>,\n): SQLQuery {\n const constraints: SQLQuery[] = [];\n const {row: from, basis} = start;\n\n for (let i = 0; i < order.length; i++) {\n const group: SQLQuery[] = [];\n const [iField, iDirection] = order[i];\n for (let j = 0; j <= i; j++) {\n if (j === i) {\n const columnType = columnTypes[iField];\n const constraintValue = toSQLiteType(from[iField], columnType.type);\n const operator =\n iDirection === 'asc' ? (reverse ? '<' : '>') : reverse ? '>' : '<';\n group.push(\n nullableAwareRangeComparison(\n iField,\n constraintValue,\n operator,\n columnType,\n ),\n );\n } else {\n const [jField] = order[j];\n const columnType = columnTypes[jField];\n const value = toSQLiteType(from[jField], columnType.type);\n group.push(nullableAwareEquality(jField, value, columnType));\n }\n }\n constraints.push(sql`(${sql.join(group, sql` AND `)})`);\n }\n\n if (basis === 'at') {\n constraints.push(\n sql`(${sql.join(\n order.map(([field]) => {\n const columnType = columnTypes[field];\n const value = toSQLiteType(from[field], columnType.type);\n return nullableAwareEquality(field, value, columnType);\n }),\n sql` AND `,\n )})`,\n );\n }\n\n return sql`(${sql.join(constraints, sql` OR `)})`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"query-builder.js","names":[],"sources":["../../../../zqlite/src/query-builder.ts"],"sourcesContent":["import type {SQLQuery} from '@databases/sql';\nimport {assert} from '../../shared/src/asserts.ts';\nimport type {\n Condition,\n Ordering,\n SimpleCondition,\n ValuePosition,\n} from '../../zero-protocol/src/ast.ts';\nimport type {\n SchemaValue,\n ValueType,\n} from '../../zero-schema/src/table-schema.ts';\nimport type {Constraint} from '../../zql/src/ivm/constraint.ts';\nimport type {MultiConstraint, Start} from '../../zql/src/ivm/operator.ts';\nimport {sql} from './internal/sql.ts';\n\n/**\n * Condition type without correlated subqueries.\n * This matches the output of transformFilters from zql/builder/filter.ts\n */\nexport type NoSubqueryCondition = Exclude<\n Condition,\n {type: 'correlatedSubquery'}\n>;\n\nexport function buildSelectQuery(\n tableName: string,\n columns: Record<string, SchemaValue>,\n constraint: Constraint | undefined,\n filters: NoSubqueryCondition | undefined,\n order: Ordering | undefined,\n reverse: boolean | undefined,\n start: Start | undefined,\n multiConstraints?: readonly MultiConstraint[] | undefined,\n) {\n let query = sql`SELECT ${sql.join(\n Object.keys(columns).map(c => sql.ident(c)),\n sql`,`,\n )} FROM ${sql.ident(tableName)}`;\n const constraints: SQLQuery[] = constraintsToSQL(constraint, columns);\n\n if (multiConstraints) {\n for (const mc of multiConstraints) {\n if (mc.length > 0) {\n constraints.push(multiConstraintToSQL(mc, columns));\n }\n }\n }\n\n if (start) {\n assert(order !== undefined, 'start requires ordering');\n constraints.push(gatherStartConstraints(start, reverse, order, columns));\n }\n\n if (filters) {\n constraints.push(filtersToSQL(filters));\n }\n\n if (constraints.length > 0) {\n query = sql`${query} WHERE ${sql.join(constraints, sql` AND `)}`;\n }\n\n if (order && order.length > 0) {\n return sql`${query} ${orderByToSQL(order, !!reverse)}`;\n }\n return query;\n}\n\nexport function constraintsToSQL(\n constraint: Constraint | undefined,\n columns: Record<string, SchemaValue>,\n) {\n if (!constraint) {\n return [];\n }\n\n const constraints: SQLQuery[] = [];\n for (const [key, value] of Object.entries(constraint)) {\n constraints.push(\n sql`${sql.ident(key)} = ${toSQLiteType(value, columns[key].type)}`,\n );\n }\n\n return constraints;\n}\n\n/**\n * Builds a single batched IN clause from a `MultiConstraint`. All entries\n * are assumed to share the same shape (the keys of the first entry);\n * FlippedJoin derives them from the same parentKey for all children.\n *\n * Single-column form: `col IN (?, ?, ?)`\n * Compound form: `(a, b) IN (VALUES (?, ?), (?, ?), …)`\n *\n * NOTE: SQLite optimizes `col IN (literal-list)` using the column's index;\n * verified via EXPLAIN QUERY PLAN — see query-builder.test.ts.\n */\nexport function multiConstraintToSQL(\n multiConstraint: MultiConstraint,\n columns: Record<string, SchemaValue>,\n): SQLQuery {\n assert(multiConstraint.length > 0, 'multiConstraint must be non-empty');\n // All entries share the same keys; pull the column list from the first.\n const keys = Object.keys(multiConstraint[0]);\n assert(keys.length > 0, 'multiConstraint entries must have at least one key');\n // Subsequent entries must share the first entry's shape — the SQL form\n // is `(col_a, col_b, …) IN VALUES (…)`, with one binding per key per\n // entry. Heterogeneous keys would silently produce incorrect bindings.\n for (let i = 1; i < multiConstraint.length; i++) {\n const entry = multiConstraint[i];\n assert(\n Object.keys(entry).length === keys.length && keys.every(k => k in entry),\n () =>\n `multiConstraint entries must share the same keys (entry 0: [${keys.join(\n ',',\n )}], entry ${i}: [${Object.keys(entry).join(',')}])`,\n );\n }\n\n if (keys.length === 1) {\n const key = keys[0];\n const colType = columns[key].type;\n return sql`${sql.ident(key)} IN (${sql.join(\n multiConstraint.map(c => sql`${toSQLiteType(c[key], colType)}`),\n sql`,`,\n )})`;\n }\n\n // Compound: `(col_a, col_b, …) IN (VALUES (?, ?, …), …)`\n const colList = sql`(${sql.join(\n keys.map(k => sql.ident(k)),\n sql`,`,\n )})`;\n const rows = multiConstraint.map(\n c =>\n sql`(${sql.join(\n keys.map(k => sql`${toSQLiteType(c[k], columns[k].type)}`),\n sql`,`,\n )})`,\n );\n return sql`${colList} IN (VALUES ${sql.join(rows, sql`,`)})`;\n}\n\nexport function orderByToSQL(order: Ordering, reverse: boolean): SQLQuery {\n if (reverse) {\n return sql`ORDER BY ${sql.join(\n order.map(\n s =>\n sql`${sql.ident(s[0])} ${sql.__dangerous__rawValue(\n s[1] === 'asc' ? 'desc' : 'asc',\n )}`,\n ),\n sql`, `,\n )}`;\n } else {\n return sql`ORDER BY ${sql.join(\n order.map(\n s => sql`${sql.ident(s[0])} ${sql.__dangerous__rawValue(s[1])}`,\n ),\n sql`, `,\n )}`;\n }\n}\n\n/**\n * Converts filters (conditions) to SQL WHERE clause.\n * This applies all filters present in the AST for a query to the source.\n */\nexport function filtersToSQL(filters: NoSubqueryCondition): SQLQuery {\n switch (filters.type) {\n case 'simple':\n return simpleConditionToSQL(filters);\n case 'and':\n return filters.conditions.length > 0\n ? sql`(${sql.join(\n filters.conditions.map(condition =>\n filtersToSQL(condition as NoSubqueryCondition),\n ),\n sql` AND `,\n )})`\n : sql`TRUE`;\n case 'or':\n return filters.conditions.length > 0\n ? sql`(${sql.join(\n filters.conditions.map(condition =>\n filtersToSQL(condition as NoSubqueryCondition),\n ),\n sql` OR `,\n )})`\n : sql`FALSE`;\n }\n}\n\nfunction simpleConditionToSQL(filter: SimpleCondition): SQLQuery {\n const {op} = filter;\n if (op === 'IN' || op === 'NOT IN') {\n switch (filter.right.type) {\n case 'literal':\n return sql`${valuePositionToSQL(\n filter.left,\n )} ${sql.__dangerous__rawValue(\n filter.op,\n )} (SELECT value FROM json_each(${JSON.stringify(\n filter.right.value,\n )}))`;\n case 'static':\n throw new Error(\n 'Static parameters must be replaced before conversion to SQL',\n );\n }\n }\n if (\n op === 'LIKE' ||\n op === 'NOT LIKE' ||\n op === 'ILIKE' ||\n op === 'NOT ILIKE'\n ) {\n return likeConditionToSQL(filter);\n }\n\n return sql`${valuePositionToSQL(filter.left)} ${sql.__dangerous__rawValue(\n filter.op,\n )} ${valuePositionToSQL(filter.right)}`;\n}\n\nfunction likeConditionToSQL(filter: SimpleCondition): SQLQuery {\n const {op} = filter;\n // Mirror Postgres pattern-matching semantics:\n // * LIKE is case-sensitive. The replica connection runs with\n // `PRAGMA case_sensitive_like = ON` (see db.ts), so the bare LIKE\n // operator is case-sensitive.\n // * ILIKE is case-insensitive. We lower() both operands using the\n // Unicode-aware lower() that @rocicorp/zero-sqlite3 provides via ICU,\n // mirroring the toLowerCase() used by the in-memory IVM matcher\n // (see zql/src/builder/like.ts).\n // * Backslash is the default escape character in Postgres and in the IVM\n // matcher, but SQLite has no default, so we specify `ESCAPE '\\'`\n // explicitly. The SQL literal '\\' is a single backslash (SQLite does not\n // process backslash escapes inside string literals).\n const caseInsensitive = op === 'ILIKE' || op === 'NOT ILIKE';\n const negated = op === 'NOT LIKE' || op === 'NOT ILIKE';\n const likeOp = sql.__dangerous__rawValue(negated ? 'NOT LIKE' : 'LIKE');\n\n const left = valuePositionToSQL(filter.left);\n const right = valuePositionToSQL(filter.right);\n if (caseInsensitive) {\n return sql`lower(${left}) ${likeOp} lower(${right}) ESCAPE '\\\\'`;\n }\n return sql`${left} ${likeOp} ${right} ESCAPE '\\\\'`;\n}\n\nfunction valuePositionToSQL(value: ValuePosition): SQLQuery {\n switch (value.type) {\n case 'column':\n return sql.ident(value.name);\n case 'literal':\n return sql`${toSQLiteType(value.value, getJsType(value.value))}`;\n case 'static':\n throw new Error(\n 'Static parameters must be replaced before conversion to SQL',\n );\n }\n}\n\nfunction getJsType(value: unknown): ValueType {\n if (value === null) {\n return 'null';\n }\n return typeof value === 'string'\n ? 'string'\n : typeof value === 'number'\n ? 'number'\n : typeof value === 'boolean'\n ? 'boolean'\n : 'json';\n}\n\nexport function toSQLiteType(v: unknown, type: ValueType): unknown {\n switch (type) {\n case 'boolean':\n return v === null ? null : v ? 1 : 0;\n case 'number':\n case 'string':\n case 'null':\n return v;\n case 'json':\n return JSON.stringify(v);\n }\n}\n\nfunction nullableAwareEquality(\n field: string,\n value: unknown,\n columnType: SchemaValue,\n): SQLQuery {\n // Use = instead of IS for non-nullable columns to enable better\n // index usage in SQLite.\n return columnType.optional === true\n ? sql`${sql.ident(field)} IS ${value}`\n : sql`${sql.ident(field)} = ${value}`;\n}\n\nfunction nullableAwareRangeComparison(\n field: string,\n value: unknown,\n operator: '>' | '<',\n columnType: SchemaValue,\n): SQLQuery {\n // For non-nullable columns, skip IS NULL checks to avoid breaking\n // SQLite's MULTI-INDEX OR optimization, which falls back to a full\n // table scan when any OR branch involves NULL.\n // See: https://github.com/rocicorp/mono/pull/5542\n const comparison = sql`${sql.ident(field)} ${sql.__dangerous__rawValue(\n operator,\n )} ${value}`;\n if (columnType.optional !== true) {\n return comparison;\n }\n\n return operator === '>'\n ? sql`(${value} IS NULL OR ${comparison})`\n : sql`(${sql.ident(field)} IS NULL OR ${comparison})`;\n}\n\nfunction sargableLeadingStartBound(\n field: string,\n value: unknown,\n operator: '>' | '<',\n columnType: SchemaValue,\n): SQLQuery | undefined {\n if (columnType.optional === true) {\n return undefined;\n }\n\n const inclusiveOperator = operator === '>' ? '>=' : '<=';\n return sql`${sql.ident(field)} ${sql.__dangerous__rawValue(\n inclusiveOperator,\n )} ${value}`;\n}\n\n/**\n * The ordering could be complex such as:\n * `ORDER BY a ASC, b DESC, c ASC`\n *\n * In those cases, we need to encode the constraints as various\n * `OR` clauses.\n *\n * E.g.,\n *\n * to get the row after (a = 1, b = 2, c = 3) would be:\n *\n * `WHERE a > 1 OR (a = 1 AND b < 2) OR (a = 1 AND b = 2 AND c > 3)`\n *\n * - after vs before flips the comparison operators.\n * - inclusive adds a final `OR` clause for the exact match.\n */\nfunction gatherStartConstraints(\n start: Start,\n reverse: boolean | undefined,\n order: Ordering,\n columnTypes: Record<string, SchemaValue>,\n): SQLQuery {\n const constraints: SQLQuery[] = [];\n const {row: from, basis} = start;\n let leadingBound: SQLQuery | undefined;\n\n for (let i = 0; i < order.length; i++) {\n const group: SQLQuery[] = [];\n const [iField, iDirection] = order[i];\n for (let j = 0; j <= i; j++) {\n if (j === i) {\n const columnType = columnTypes[iField];\n const constraintValue = toSQLiteType(from[iField], columnType.type);\n const operator =\n iDirection === 'asc' ? (reverse ? '<' : '>') : reverse ? '>' : '<';\n if (i === 0) {\n leadingBound = sargableLeadingStartBound(\n iField,\n constraintValue,\n operator,\n columnType,\n );\n }\n group.push(\n nullableAwareRangeComparison(\n iField,\n constraintValue,\n operator,\n columnType,\n ),\n );\n } else {\n const [jField] = order[j];\n const columnType = columnTypes[jField];\n const value = toSQLiteType(from[jField], columnType.type);\n group.push(nullableAwareEquality(jField, value, columnType));\n }\n }\n constraints.push(sql`(${sql.join(group, sql` AND `)})`);\n }\n\n if (basis === 'at') {\n constraints.push(\n sql`(${sql.join(\n order.map(([field]) => {\n const columnType = columnTypes[field];\n const value = toSQLiteType(from[field], columnType.type);\n return nullableAwareEquality(field, value, columnType);\n }),\n sql` AND `,\n )})`,\n );\n }\n\n const lexicographicStart = sql`(${sql.join(constraints, sql` OR `)})`;\n return leadingBound === undefined\n ? lexicographicStart\n : sql`(${leadingBound} AND ${lexicographicStart})`;\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { must } from "../../shared/src/must.js";
3
3
  import { buildSelectQuery } from "./query-builder.js";
4
4
  import { compileInline } from "./internal/sql-inline.js";
5
5
  import { SQLiteStatFanout } from "./sqlite-stat-fanout.js";
6
- import SQLite3Database from "@rocicorp/zero-sqlite3";
6
+ import Sqlite3Database from "@rocicorp/zero-sqlite3";
7
7
  //#region ../zqlite/src/sqlite-cost-model.ts
8
8
  /**
9
9
  * Creates a SQLite-based cost model for query planning.
@@ -66,13 +66,13 @@ function removeCorrelatedSubqueries(condition) {
66
66
  function getScanstatusLoops(stmt) {
67
67
  const loops = [];
68
68
  for (let idx = 0;; idx++) {
69
- const selectId = stmt.scanStatus(idx, SQLite3Database.SQLITE_SCANSTAT_SELECTID, 1);
69
+ const selectId = stmt.scanStatus(idx, Sqlite3Database.SQLITE_SCANSTAT_SELECTID, 1);
70
70
  if (selectId === void 0) break;
71
71
  loops.push({
72
72
  selectId: must(selectId),
73
- parentId: must(stmt.scanStatus(idx, SQLite3Database.SQLITE_SCANSTAT_PARENTID, 1)),
74
- explain: must(stmt.scanStatus(idx, SQLite3Database.SQLITE_SCANSTAT_EXPLAIN, 1)),
75
- est: must(stmt.scanStatus(idx, SQLite3Database.SQLITE_SCANSTAT_EST, 1))
73
+ parentId: must(stmt.scanStatus(idx, Sqlite3Database.SQLITE_SCANSTAT_PARENTID, 1)),
74
+ explain: must(stmt.scanStatus(idx, Sqlite3Database.SQLITE_SCANSTAT_EXPLAIN, 1)),
75
+ est: must(stmt.scanStatus(idx, Sqlite3Database.SQLITE_SCANSTAT_EST, 1))
76
76
  });
77
77
  }
78
78
  return loops.sort((a, b) => a.selectId - b.selectId);
@@ -8,7 +8,7 @@ import { timeSampled } from "../../otel/src/maybe-time.js";
8
8
  import { compile, format, sql } from "./internal/sql.js";
9
9
  import { StatementCache } from "./internal/statement-cache.js";
10
10
  import { buildSelectQuery, toSQLiteType } from "./query-builder.js";
11
- import SQLite3Database from "@rocicorp/zero-sqlite3";
11
+ import Sqlite3Database from "@rocicorp/zero-sqlite3";
12
12
  //#region ../zqlite/src/table-source.ts
13
13
  var eventCount = 0;
14
14
  /**
@@ -154,10 +154,10 @@ var TableSource = class {
154
154
  let totalNvisit = 0;
155
155
  const planLines = [];
156
156
  for (let i = 0;; i++) {
157
- const nvisit = cachedStatement.statement.scanStatus(i, SQLite3Database.SQLITE_SCANSTAT_NVISIT, 1);
157
+ const nvisit = cachedStatement.statement.scanStatus(i, Sqlite3Database.SQLITE_SCANSTAT_NVISIT, 1);
158
158
  if (nvisit === void 0) break;
159
159
  totalNvisit += Number(nvisit);
160
- const explain = cachedStatement.statement.scanStatus(i, SQLite3Database.SQLITE_SCANSTAT_EXPLAIN, 1);
160
+ const explain = cachedStatement.statement.scanStatus(i, Sqlite3Database.SQLITE_SCANSTAT_EXPLAIN, 1);
161
161
  if (typeof explain === "string" && explain.length > 0) planLines.push(explain);
162
162
  }
163
163
  if (totalNvisit !== 0) debug.recordNVisit(this.#table, sqlAndBindings.text, totalNvisit);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocicorp/zero",
3
- "version": "1.8.0-canary.1",
3
+ "version": "1.8.0-canary.2",
4
4
  "description": "Zero is a web framework for serverless web development.",
5
5
  "homepage": "https://zero.rocicorp.dev",
6
6
  "bugs": {