@lunora/d1 1.0.0-alpha.18 → 1.0.0-alpha.180

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/LICENSE.md CHANGED
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
103
103
  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
104
  CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
105
  specific language governing permissions and limitations under the License.
106
+
107
+ <!-- DEPENDENCIES -->
108
+ <!-- /DEPENDENCIES -->
109
+
110
+ <!-- TYPE_DEPENDENCIES -->
111
+ <!-- /TYPE_DEPENDENCIES -->
@@ -1,41 +1,80 @@
1
1
  /**
2
- * Canonical SQL identifier quoter shared by `@lunora/d1` and `@lunora/do`.
3
- *
4
- * Double-quotes a SQL identifier and escapes any embedded double quotes by
5
- * doubling them (`"` → `""`) — the ANSI/SQLite/Postgres rule. This is a
6
- * security-relevant primitive (it is the sole defense against identifier
7
- * injection wherever a table/column name is spliced into raw SQL), so it must
8
- * have exactly ONE definition rather than byte-identical copies that can drift.
9
- *
10
- * Like `shared/stable-key.ts`, it is deliberately **not** a package: `@lunora/d1`
11
- * and `@lunora/do` sit on the same tier with no lower-level package to host it,
12
- * so each imports this file by relative path and the bundler (packem/rollup)
13
- * inlines it — no runtime dependency edge, duplicated only in emitted output.
14
- * Keep it genuinely zero-dependency (relative/built-in imports only) or inlining
15
- * breaks. Consumers must drop `outDir`/`rootDir` from their `tsconfig.json` (a
16
- * set `rootDir` raises TS6059 for this out-of-package file under `tsc --noEmit`).
17
- */
2
+ * The optimistic-concurrency row version every global table carries alongside
3
+ * `id`/`_creationTime`.
4
+ *
5
+ * The CAS used to bind one parameter per physical column of the snapshot, so an
6
+ * `UPDATE` on a wide table bound `2N+2` parameters — over D1's 100-per-statement
7
+ * ceiling (workerd's `SQLITE_LIMIT_VARIABLE_NUMBER`) from 50 declared fields up,
8
+ * while `INSERT` at the same width stayed under it. The table provisioned, rows
9
+ * inserted, and the first `patch`/`replace`/soft-`delete` died with a raw
10
+ * `too many SQL variables` that redacts to "Internal error" on the way out.
11
+ *
12
+ * Guarding on this one column instead makes the CAS cost two parameters at any
13
+ * width. Every guarded write bumps it in SQL (`COALESCE(<col>, 0) + 1`), which
14
+ * costs no parameter of its own; `INSERT` leaves it NULL, and the NULL-safe
15
+ * comparison handles both that and rows written before the column existed.
16
+ *
17
+ * Not decoded into documents — `decodeGlobalRow` builds its result from the
18
+ * declared shape, so an undeclared physical column is invisible to callers.
19
+ *
20
+ * Bundler-inlined rather than owned by one package because BOTH producers of
21
+ * global-table DDL name it: `@lunora/sql-store`'s auto-provisioner (which runs
22
+ * the CAS) and `@lunora/d1/dialect`, which `lunora migrate generate` derives its
23
+ * `CREATE TABLE` from. Importing `@lunora/sql-store` would pull drizzle into the
24
+ * dependency-free dialect module the CLI reads; a second copy of the string is
25
+ * how the two shapes drift.
26
+ */
27
+ declare const OCC_VERSION_COLUMN = "_version";
28
+ /**
29
+ * Canonical SQL identifier quoter shared by `@lunora/d1` and `@lunora/do`.
30
+ *
31
+ * Double-quotes a SQL identifier and escapes any embedded double quotes by
32
+ * doubling them (`"` → `""`) — the ANSI/SQLite/Postgres rule. This is a
33
+ * security-relevant primitive (it is the sole defense against identifier
34
+ * injection wherever a table/column name is spliced into raw SQL), so it must
35
+ * have exactly ONE definition rather than byte-identical copies that can drift.
36
+ *
37
+ * Like `shared/stable-key.ts`, it is deliberately **not** a package: `@lunora/d1`
38
+ * and `@lunora/do` sit on the same tier with no lower-level package to host it,
39
+ * so each imports this file by relative path and the bundler (packem/rollup)
40
+ * inlines it — no runtime dependency edge, duplicated only in emitted output.
41
+ * Keep it genuinely zero-dependency (relative/built-in imports only) or inlining
42
+ * breaks. Consumers must drop `outDir`/`rootDir` from their `tsconfig.json` (a
43
+ * set `rootDir` raises TS6059 for this out-of-package file under `tsc --noEmit`).
44
+ */
18
45
  declare const quoteIdentifier: (name: string) => string;
19
46
  /** SQLite column type affinities Lunora emits. */
20
47
  type SqlAffinity = "BLOB" | "INTEGER" | "REAL" | "TEXT";
21
48
  /**
22
- * SQLite affinity for a column by its validator `kind`, chosen so the value the
23
- * D1 layer serializes round-trips intact:
24
- * - `boolean` → INTEGER (stored as 1/0)
25
- * - `number`/`timestamp`/`date` → REAL (numeric, never coerced to text)
26
- * - `bytes` → BLOB
27
- * - everything else → TEXT — string/id/literal, `bigint` (serialized as a
28
- * decimal string), and object/array/record/union/any (JSON). A numeric affinity
29
- * would coerce a numeric-looking string and corrupt the decode.
30
- */
49
+ * SQLite affinity for a column by its validator `kind`, chosen so the value the
50
+ * D1 layer serializes round-trips intact:
51
+ * - `boolean` → INTEGER (stored as 1/0)
52
+ * - `number`/`timestamp`/`date` → REAL (numeric, never coerced to text)
53
+ * - `bytes` → BLOB
54
+ * - everything else → TEXT — string/id/literal, `bigint` (the order-preserving
55
+ * 40-character key `bigintSqlKey` builds: a sign character plus 39 digits, so
56
+ * text comparison agrees with numeric comparison and an index range scan is
57
+ * correct), and object/array/record/union/any (JSON). A numeric affinity would
58
+ * coerce a numeric-looking string and corrupt the decode.
59
+ */
31
60
  declare const sqlAffinityForKind: (kind: string | undefined) => SqlAffinity;
61
+ /**
62
+ * Most columns one D1 table may carry, framework columns included.
63
+ *
64
+ * D1 runs Workerd's SQLite build, which sets `SQLITE_LIMIT_COLUMN` to 100 where
65
+ * stock SQLite allows 2,000. Exported so the two producers of global-table DDL
66
+ * — the runtime auto-provisioner in `@lunora/sql-store` and the
67
+ * `lunora migrate generate` emitter — check the same number rather than each
68
+ * carrying its own copy.
69
+ */
70
+ declare const MAX_D1_TABLE_COLUMNS = 100;
32
71
  /** Framework columns every global table carries: the physical `id` (exposed as `_id`) and `_creationTime`. */
33
72
  declare const frameworkColumnDdl: () => ReadonlyArray<string>;
34
73
  /**
35
- * Resolve a schema field to its physical D1 column: `_id`/`id` both map to the
36
- * physical `id` column, `_creationTime` to its own, every other field to itself.
37
- */
74
+ * Resolve a schema field to its physical D1 column: `_id`/`id` both map to the
75
+ * physical `id` column, `_creationTime` to its own, every other field to itself.
76
+ */
38
77
  declare const columnRef: (field: string) => string;
39
- /** Physical index identifier — `&lt;table>_&lt;name>`, so two tables' like-named indexes don't collide in SQLite's flat index namespace. */
78
+ /** Physical index identifier — `<table>_<name>`, so two tables' like-named indexes don't collide in SQLite's flat index namespace. */
40
79
  declare const physicalIndexName: (tableName: string, indexName: string) => string;
41
- export { SqlAffinity, columnRef, frameworkColumnDdl, physicalIndexName, quoteIdentifier, sqlAffinityForKind };
80
+ export { MAX_D1_TABLE_COLUMNS, OCC_VERSION_COLUMN, SqlAffinity, columnRef, frameworkColumnDdl, physicalIndexName, quoteIdentifier, sqlAffinityForKind };
package/dist/dialect.d.ts CHANGED
@@ -1,41 +1,80 @@
1
1
  /**
2
- * Canonical SQL identifier quoter shared by `@lunora/d1` and `@lunora/do`.
3
- *
4
- * Double-quotes a SQL identifier and escapes any embedded double quotes by
5
- * doubling them (`"` → `""`) — the ANSI/SQLite/Postgres rule. This is a
6
- * security-relevant primitive (it is the sole defense against identifier
7
- * injection wherever a table/column name is spliced into raw SQL), so it must
8
- * have exactly ONE definition rather than byte-identical copies that can drift.
9
- *
10
- * Like `shared/stable-key.ts`, it is deliberately **not** a package: `@lunora/d1`
11
- * and `@lunora/do` sit on the same tier with no lower-level package to host it,
12
- * so each imports this file by relative path and the bundler (packem/rollup)
13
- * inlines it — no runtime dependency edge, duplicated only in emitted output.
14
- * Keep it genuinely zero-dependency (relative/built-in imports only) or inlining
15
- * breaks. Consumers must drop `outDir`/`rootDir` from their `tsconfig.json` (a
16
- * set `rootDir` raises TS6059 for this out-of-package file under `tsc --noEmit`).
17
- */
2
+ * The optimistic-concurrency row version every global table carries alongside
3
+ * `id`/`_creationTime`.
4
+ *
5
+ * The CAS used to bind one parameter per physical column of the snapshot, so an
6
+ * `UPDATE` on a wide table bound `2N+2` parameters — over D1's 100-per-statement
7
+ * ceiling (workerd's `SQLITE_LIMIT_VARIABLE_NUMBER`) from 50 declared fields up,
8
+ * while `INSERT` at the same width stayed under it. The table provisioned, rows
9
+ * inserted, and the first `patch`/`replace`/soft-`delete` died with a raw
10
+ * `too many SQL variables` that redacts to "Internal error" on the way out.
11
+ *
12
+ * Guarding on this one column instead makes the CAS cost two parameters at any
13
+ * width. Every guarded write bumps it in SQL (`COALESCE(<col>, 0) + 1`), which
14
+ * costs no parameter of its own; `INSERT` leaves it NULL, and the NULL-safe
15
+ * comparison handles both that and rows written before the column existed.
16
+ *
17
+ * Not decoded into documents — `decodeGlobalRow` builds its result from the
18
+ * declared shape, so an undeclared physical column is invisible to callers.
19
+ *
20
+ * Bundler-inlined rather than owned by one package because BOTH producers of
21
+ * global-table DDL name it: `@lunora/sql-store`'s auto-provisioner (which runs
22
+ * the CAS) and `@lunora/d1/dialect`, which `lunora migrate generate` derives its
23
+ * `CREATE TABLE` from. Importing `@lunora/sql-store` would pull drizzle into the
24
+ * dependency-free dialect module the CLI reads; a second copy of the string is
25
+ * how the two shapes drift.
26
+ */
27
+ declare const OCC_VERSION_COLUMN = "_version";
28
+ /**
29
+ * Canonical SQL identifier quoter shared by `@lunora/d1` and `@lunora/do`.
30
+ *
31
+ * Double-quotes a SQL identifier and escapes any embedded double quotes by
32
+ * doubling them (`"` → `""`) — the ANSI/SQLite/Postgres rule. This is a
33
+ * security-relevant primitive (it is the sole defense against identifier
34
+ * injection wherever a table/column name is spliced into raw SQL), so it must
35
+ * have exactly ONE definition rather than byte-identical copies that can drift.
36
+ *
37
+ * Like `shared/stable-key.ts`, it is deliberately **not** a package: `@lunora/d1`
38
+ * and `@lunora/do` sit on the same tier with no lower-level package to host it,
39
+ * so each imports this file by relative path and the bundler (packem/rollup)
40
+ * inlines it — no runtime dependency edge, duplicated only in emitted output.
41
+ * Keep it genuinely zero-dependency (relative/built-in imports only) or inlining
42
+ * breaks. Consumers must drop `outDir`/`rootDir` from their `tsconfig.json` (a
43
+ * set `rootDir` raises TS6059 for this out-of-package file under `tsc --noEmit`).
44
+ */
18
45
  declare const quoteIdentifier: (name: string) => string;
19
46
  /** SQLite column type affinities Lunora emits. */
20
47
  type SqlAffinity = "BLOB" | "INTEGER" | "REAL" | "TEXT";
21
48
  /**
22
- * SQLite affinity for a column by its validator `kind`, chosen so the value the
23
- * D1 layer serializes round-trips intact:
24
- * - `boolean` → INTEGER (stored as 1/0)
25
- * - `number`/`timestamp`/`date` → REAL (numeric, never coerced to text)
26
- * - `bytes` → BLOB
27
- * - everything else → TEXT — string/id/literal, `bigint` (serialized as a
28
- * decimal string), and object/array/record/union/any (JSON). A numeric affinity
29
- * would coerce a numeric-looking string and corrupt the decode.
30
- */
49
+ * SQLite affinity for a column by its validator `kind`, chosen so the value the
50
+ * D1 layer serializes round-trips intact:
51
+ * - `boolean` → INTEGER (stored as 1/0)
52
+ * - `number`/`timestamp`/`date` → REAL (numeric, never coerced to text)
53
+ * - `bytes` → BLOB
54
+ * - everything else → TEXT — string/id/literal, `bigint` (the order-preserving
55
+ * 40-character key `bigintSqlKey` builds: a sign character plus 39 digits, so
56
+ * text comparison agrees with numeric comparison and an index range scan is
57
+ * correct), and object/array/record/union/any (JSON). A numeric affinity would
58
+ * coerce a numeric-looking string and corrupt the decode.
59
+ */
31
60
  declare const sqlAffinityForKind: (kind: string | undefined) => SqlAffinity;
61
+ /**
62
+ * Most columns one D1 table may carry, framework columns included.
63
+ *
64
+ * D1 runs Workerd's SQLite build, which sets `SQLITE_LIMIT_COLUMN` to 100 where
65
+ * stock SQLite allows 2,000. Exported so the two producers of global-table DDL
66
+ * — the runtime auto-provisioner in `@lunora/sql-store` and the
67
+ * `lunora migrate generate` emitter — check the same number rather than each
68
+ * carrying its own copy.
69
+ */
70
+ declare const MAX_D1_TABLE_COLUMNS = 100;
32
71
  /** Framework columns every global table carries: the physical `id` (exposed as `_id`) and `_creationTime`. */
33
72
  declare const frameworkColumnDdl: () => ReadonlyArray<string>;
34
73
  /**
35
- * Resolve a schema field to its physical D1 column: `_id`/`id` both map to the
36
- * physical `id` column, `_creationTime` to its own, every other field to itself.
37
- */
74
+ * Resolve a schema field to its physical D1 column: `_id`/`id` both map to the
75
+ * physical `id` column, `_creationTime` to its own, every other field to itself.
76
+ */
38
77
  declare const columnRef: (field: string) => string;
39
- /** Physical index identifier — `&lt;table>_&lt;name>`, so two tables' like-named indexes don't collide in SQLite's flat index namespace. */
78
+ /** Physical index identifier — `<table>_<name>`, so two tables' like-named indexes don't collide in SQLite's flat index namespace. */
40
79
  declare const physicalIndexName: (tableName: string, indexName: string) => string;
41
- export { SqlAffinity, columnRef, frameworkColumnDdl, physicalIndexName, quoteIdentifier, sqlAffinityForKind };
80
+ export { MAX_D1_TABLE_COLUMNS, OCC_VERSION_COLUMN, SqlAffinity, columnRef, frameworkColumnDdl, physicalIndexName, quoteIdentifier, sqlAffinityForKind };
package/dist/dialect.mjs CHANGED
@@ -1,36 +1 @@
1
- import { quoteIdentifier } from './packem_shared/quoteIdentifier-B-ZeSe1V.mjs';
2
-
3
- const sqlAffinityForKind = (kind) => {
4
- switch (kind) {
5
- case "boolean": {
6
- return "INTEGER";
7
- }
8
- case "bytes": {
9
- return "BLOB";
10
- }
11
- case "date":
12
- case "number":
13
- case "timestamp": {
14
- return "REAL";
15
- }
16
- default: {
17
- return "TEXT";
18
- }
19
- }
20
- };
21
- const frameworkColumnDdl = () => [
22
- `${quoteIdentifier("id")} TEXT PRIMARY KEY`,
23
- `${quoteIdentifier("_creationTime")} REAL NOT NULL`
24
- ];
25
- const columnRef = (field) => {
26
- if (field === "_id" || field === "id") {
27
- return quoteIdentifier("id");
28
- }
29
- if (field === "_creationTime") {
30
- return quoteIdentifier("_creationTime");
31
- }
32
- return quoteIdentifier(field);
33
- };
34
- const physicalIndexName = (tableName, indexName) => quoteIdentifier(`${tableName}_${indexName}`);
35
-
36
- export { columnRef, frameworkColumnDdl, physicalIndexName, quoteIdentifier, sqlAffinityForKind };
1
+ import{quoteIdentifier as r}from"./packem_shared/quoteIdentifier-CObIFRhb.mjs";import{OCC_VERSION_COLUMN as T}from"./packem_shared/OCC_VERSION_COLUMN-ByC64Jgx.mjs";const o=e=>{switch(e){case"boolean":return"INTEGER";case"bytes":return"BLOB";case"date":case"number":case"timestamp":return"REAL";default:return"TEXT"}},i=100,c=()=>[`${r("id")} TEXT PRIMARY KEY`,`${r("_creationTime")} REAL NOT NULL`],a=e=>e==="_id"||e==="id"?r("id"):e==="_creationTime"?r("_creationTime"):r(e),s=(e,t)=>r(`${e}_${t}`);export{i as MAX_D1_TABLE_COLUMNS,T as OCC_VERSION_COLUMN,a as columnRef,c as frameworkColumnDdl,s as physicalIndexName,r as quoteIdentifier,o as sqlAffinityForKind};