@lunora/sql-store 1.0.0-alpha.100 → 1.0.0-alpha.102

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/README.md CHANGED
@@ -57,12 +57,12 @@ hand-rolled rewriting.
57
57
 
58
58
  The small per-engine `SqlDialect` value object carries only what drizzle can't
59
59
  infer from a dynamic, column-per-field schema: the framework columns every
60
- global table carries, column and companion-table types, value encode/decode
61
- (every engine stores SQLite-shaped values), `RETURNING` availability (with an
62
- affected-rows fallback for MySQL), unique-violation detection, the MySQL index
63
- key-prefix, and the system-catalog (`tableExists`) probe. Full-text search is
64
- not part of the dialect — the core probes FTS5 availability on the `exec` at
65
- runtime.
60
+ global table carries, column and companion-table types, `RETURNING` availability
61
+ (with an affected-rows fallback for MySQL), unique-violation detection, the MySQL index
62
+ key-prefix, and the system-catalog (`tableExists`) probe. The value codec is
63
+ **not** a dialect member — every engine stores SQLite-shaped values through the
64
+ core's own `sqliteEncode`/`sqliteDecode`. Full-text search is not part of the
65
+ dialect either — the core probes FTS5 availability on the `exec` at runtime.
66
66
 
67
67
  Reactivity is engine-independent: the writer is injected as `globalDb` into
68
68
  `createShardCtxDb`, whose `broadcast` hook drives live queries no matter which
@@ -85,7 +85,7 @@ seam from the root); consumers import everything from the root `@lunora/sql-stor
85
85
  `runSqlRankMigrations`, `runSqlSearchMigrations`, `runSqlCdcMigration`.
86
86
  - CDC log helpers: `readSqlCdcChanges`, `readSqlCdcChangedTables`,
87
87
  `readSqlCdcFloor`, `sweepSqlCdcRetention`.
88
- - Value codec building blocks a dialect reuses for `encode`/`decode`:
88
+ - Value codec building blocks (the core runs these on every engine):
89
89
  `sqliteEncode`, `sqliteDecode`, `decodeBigint`, `tryJsonParse`,
90
90
  `effectiveColumnKind`.
91
91
  - Types: `SqlCtxDbOptions`, `SqlCtxExec`, `SqlDialect`, `SqlExec`,
@@ -51,10 +51,18 @@ interface SqlDialect {
51
51
  /** Affected-rows extractor for the OCC fallback when `supportsReturning` is false (MySQL). */
52
52
  affectedRows?: (result: SqlRunResult) => number;
53
53
  /**
54
- * Storage SQL column type for a validator `kind`. SQLite affinity
55
- * (`TEXT`/`INTEGER`/`REAL`/`BLOB`); Postgres `TEXT`/`DOUBLE PRECISION`/
56
- * `BOOLEAN`/`JSONB`/`BYTEA`; MySQL `VARCHAR(255)`/`TEXT`/`DOUBLE`/
57
- * `TINYINT(1)`/`JSON`/`LONGBLOB`.
54
+ * Storage SQL column type for a validator `kind`. Every engine stores
55
+ * SQLite-shaped values (see `value-codec.ts`), so the types are the ones
56
+ * those forms fit, not the engine's richest equivalent:
57
+ *
58
+ * - SQLite affinity: `TEXT`/`INTEGER`/`REAL`/`BLOB`.
59
+ * - Postgres: `DOUBLE PRECISION` (number/date/timestamp), `BYTEA` (bytes),
60
+ * `INTEGER` (boolean, stored 1/0), `TEXT` for everything else — including
61
+ * the composites, which are JSON text rather than `JSONB`.
62
+ * - MySQL: `DOUBLE`, `LONGBLOB`, `TINYINT`, `VARCHAR(64)` (bigint as a
63
+ * decimal string), and `LONGTEXT` for everything else — strings unbounded
64
+ * so they never truncate, composites because their wire-marked form is not
65
+ * valid JSON and a `JSON` column would reject it on insert.
58
66
  */
59
67
  columnType: (kind: string | undefined) => string;
60
68
  /**
@@ -71,20 +79,6 @@ interface SqlDialect {
71
79
  real: string;
72
80
  text: string;
73
81
  };
74
- /**
75
- * Map a stored value back to its JS form, by effective validator `kind`
76
- * (inverse of `encode`). NOTE: currently **unused** by the store core, which
77
- * hard-codes `sqliteDecode` in `decodeGlobalRow` on every engine. Kept on the
78
- * seam for a future engine-native codec; an override here does not run today.
79
- */
80
- decode: (value: unknown, kind: string | undefined) => unknown;
81
- /**
82
- * Map a JS value to its bound storage form (boolean→1/0, bigint→string,
83
- * object→JSON on SQLite). NOTE: currently **unused** by the store core, which
84
- * hard-codes `sqliteEncode` as `serializeColumnValue` on every engine. Kept on
85
- * the seam for a future engine-native codec; an override here does not run today.
86
- */
87
- encode: (value: unknown) => unknown;
88
82
  /** The framework columns every global table carries — the `id` primary key and `_creationTime` — as `{ name, type }` so the DDL builder can quote each name through the engine's dialect. */
89
83
  frameworkColumns: () => ReadonlyArray<{
90
84
  name: string;
package/dist/dialect.d.ts CHANGED
@@ -51,10 +51,18 @@ interface SqlDialect {
51
51
  /** Affected-rows extractor for the OCC fallback when `supportsReturning` is false (MySQL). */
52
52
  affectedRows?: (result: SqlRunResult) => number;
53
53
  /**
54
- * Storage SQL column type for a validator `kind`. SQLite affinity
55
- * (`TEXT`/`INTEGER`/`REAL`/`BLOB`); Postgres `TEXT`/`DOUBLE PRECISION`/
56
- * `BOOLEAN`/`JSONB`/`BYTEA`; MySQL `VARCHAR(255)`/`TEXT`/`DOUBLE`/
57
- * `TINYINT(1)`/`JSON`/`LONGBLOB`.
54
+ * Storage SQL column type for a validator `kind`. Every engine stores
55
+ * SQLite-shaped values (see `value-codec.ts`), so the types are the ones
56
+ * those forms fit, not the engine's richest equivalent:
57
+ *
58
+ * - SQLite affinity: `TEXT`/`INTEGER`/`REAL`/`BLOB`.
59
+ * - Postgres: `DOUBLE PRECISION` (number/date/timestamp), `BYTEA` (bytes),
60
+ * `INTEGER` (boolean, stored 1/0), `TEXT` for everything else — including
61
+ * the composites, which are JSON text rather than `JSONB`.
62
+ * - MySQL: `DOUBLE`, `LONGBLOB`, `TINYINT`, `VARCHAR(64)` (bigint as a
63
+ * decimal string), and `LONGTEXT` for everything else — strings unbounded
64
+ * so they never truncate, composites because their wire-marked form is not
65
+ * valid JSON and a `JSON` column would reject it on insert.
58
66
  */
59
67
  columnType: (kind: string | undefined) => string;
60
68
  /**
@@ -71,20 +79,6 @@ interface SqlDialect {
71
79
  real: string;
72
80
  text: string;
73
81
  };
74
- /**
75
- * Map a stored value back to its JS form, by effective validator `kind`
76
- * (inverse of `encode`). NOTE: currently **unused** by the store core, which
77
- * hard-codes `sqliteDecode` in `decodeGlobalRow` on every engine. Kept on the
78
- * seam for a future engine-native codec; an override here does not run today.
79
- */
80
- decode: (value: unknown, kind: string | undefined) => unknown;
81
- /**
82
- * Map a JS value to its bound storage form (boolean→1/0, bigint→string,
83
- * object→JSON on SQLite). NOTE: currently **unused** by the store core, which
84
- * hard-codes `sqliteEncode` as `serializeColumnValue` on every engine. Kept on
85
- * the seam for a future engine-native codec; an override here does not run today.
86
- */
87
- encode: (value: unknown) => unknown;
88
82
  /** The framework columns every global table carries — the `id` primary key and `_creationTime` — as `{ name, type }` so the DDL builder can quote each name through the engine's dialect. */
89
83
  frameworkColumns: () => ReadonlyArray<{
90
84
  name: string;
package/dist/index.d.mts CHANGED
@@ -269,7 +269,10 @@ declare const effectiveColumnKind: (validator: ValidatorLike) => string | undefi
269
269
  * `ArrayBuffer` passes through. Required because `v.bytes()` validates
270
270
  * `value instanceof ArrayBuffer` and different backends return different BLOB
271
271
  * shapes (workerd D1 `ArrayBuffer`, node:sqlite `Uint8Array`, pg/mysql2 `Buffer`).
272
- * - `object`/`array`/`record`: JSON string → parsed value.
272
+ * - `object`/`array`/`record`/`geoPoint`: JSON string → parsed value. `geoPoint`
273
+ * belongs here because {@link sqliteEncode} keys off the runtime JS type and
274
+ * stores the `{ lat, lng }` object as JSON in a TEXT column; without the case
275
+ * it fell through to `default:` and every client read back the raw JSON text.
273
276
  * - `union`/`any`/`from`: parsed back only when the stored string is a JSON
274
277
  * non-scalar (a scalar member round-trips through SQLite's native column type).
275
278
  * `from` belongs to THIS group, not to `object`/`array`/`record`: an external
package/dist/index.d.ts CHANGED
@@ -269,7 +269,10 @@ declare const effectiveColumnKind: (validator: ValidatorLike) => string | undefi
269
269
  * `ArrayBuffer` passes through. Required because `v.bytes()` validates
270
270
  * `value instanceof ArrayBuffer` and different backends return different BLOB
271
271
  * shapes (workerd D1 `ArrayBuffer`, node:sqlite `Uint8Array`, pg/mysql2 `Buffer`).
272
- * - `object`/`array`/`record`: JSON string → parsed value.
272
+ * - `object`/`array`/`record`/`geoPoint`: JSON string → parsed value. `geoPoint`
273
+ * belongs here because {@link sqliteEncode} keys off the runtime JS type and
274
+ * stores the `{ lat, lng }` object as JSON in a TEXT column; without the case
275
+ * it fell through to `default:` and every client read back the raw JSON text.
273
276
  * - `union`/`any`/`from`: parsed back only when the stored string is a JSON
274
277
  * non-scalar (a scalar member round-trips through SQLite's native column type).
275
278
  * `from` belongs to THIS group, not to `object`/`array`/`record`: an external
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,runSqlAggregateMigrations as n,runSqlCdcMigration as s,runSqlGlobalTableMigrations as i,runSqlRankMigrations as d,sweepSqlCdcRetention as S}from"./packem_shared/createSqlCtxDb-BTZfO_3V.mjs";import{d as q,r as g}from"./packem_shared/ctx-db-search-CHdIaNJe.mjs";import{SEARCH_STATE_TABLE as f,migrateSearchState as b}from"./packem_shared/SEARCH_STATE_TABLE-CbcRI0sw.mjs";import{b as x,e as p,a as u,s as h,t as M}from"./packem_shared/value-codec-BvCc9FjU.mjs";import{decodeGlobalRow as A}from"./packem_shared/decodeGlobalRow-_JxajZP5.mjs";export{f as SEARCH_STATE_TABLE,q as backfillSqlSearchIndexes,a as createSqlCtxDb,x as decodeBigint,A as decodeGlobalRow,p as effectiveColumnKind,b as migrateSearchState,o as readSqlCdcChangedTables,t as readSqlCdcChanges,l as readSqlCdcFloor,n as runSqlAggregateMigrations,s as runSqlCdcMigration,i as runSqlGlobalTableMigrations,d as runSqlRankMigrations,g as runSqlSearchMigrations,u as sqliteDecode,h as sqliteEncode,S as sweepSqlCdcRetention,M as tryJsonParse};
1
+ import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,runSqlAggregateMigrations as n,runSqlCdcMigration as s,runSqlGlobalTableMigrations as i,runSqlRankMigrations as d,sweepSqlCdcRetention as S}from"./packem_shared/createSqlCtxDb-DAAHi-e-.mjs";import{d as q,r as g}from"./packem_shared/ctx-db-search-BiMTuJzw.mjs";import{SEARCH_STATE_TABLE as f,migrateSearchState as m}from"./packem_shared/SEARCH_STATE_TABLE-B5a5xBwB.mjs";import{c as b,e as p,a as u,s as h,t as M}from"./packem_shared/value-codec-CwTLrqfU.mjs";import{decodeGlobalRow as A}from"./packem_shared/decodeGlobalRow-C8O2hy0d.mjs";export{f as SEARCH_STATE_TABLE,q as backfillSqlSearchIndexes,a as createSqlCtxDb,b as decodeBigint,A as decodeGlobalRow,p as effectiveColumnKind,m as migrateSearchState,o as readSqlCdcChangedTables,t as readSqlCdcChanges,l as readSqlCdcFloor,n as runSqlAggregateMigrations,s as runSqlCdcMigration,i as runSqlGlobalTableMigrations,d as runSqlRankMigrations,g as runSqlSearchMigrations,u as sqliteDecode,h as sqliteEncode,S as sweepSqlCdcRetention,M as tryJsonParse};
@@ -1 +1 @@
1
- import{sql as i}from"drizzle-orm";import{queryRun as s,queryAll as E}from"./decodeGlobalRow-_JxajZP5.mjs";const f="__lunora_search_state",l=async(r,e)=>{const{integer:t,key:o}=e.companionTypes,n=async()=>{try{await s(r,e,i`ALTER TABLE ${i.identifier(f)} ADD COLUMN ${i.identifier("profile")} ${i.raw(o)}`)}catch{}};await s(r,e,i`CREATE TABLE IF NOT EXISTS ${i.identifier(f)} (${i.identifier("companion")} ${i.raw(o)} PRIMARY KEY, ${i.identifier("cursor")} ${i.raw(o)}, ${i.identifier("done")} ${i.raw(t)} NOT NULL DEFAULT 0, ${i.identifier("profile")} ${i.raw(o)})`),await n()},p=r=>r===1||r===!0||r==="1",S=async(r,e,t)=>{const n=(await E(r,e,i`SELECT ${i.identifier("cursor")}, ${i.identifier("done")}, ${i.identifier("profile")} FROM ${i.identifier(f)} WHERE ${i.identifier("companion")} = ${t}`))[0];if(!n)return{cursor:void 0,done:!1,profile:void 0};const{cursor:a,profile:$}=n;return{cursor:typeof a=="string"?a:void 0,done:p(n.done),profile:typeof $=="string"?$:void 0}},A=async(r,e,t,o,n,a)=>{const $=o??null,d=i`UPDATE ${i.identifier(f)} SET ${i.identifier("cursor")} = ${$}, ${i.identifier("done")} = ${n?1:0}, ${i.identifier("profile")} = ${a} WHERE ${i.identifier("companion")} = ${t}`;if((await E(r,e,i`SELECT ${i.identifier("companion")} FROM ${i.identifier(f)} WHERE ${i.identifier("companion")} = ${t}`)).length>0){await s(r,e,d);return}try{await s(r,e,i`INSERT INTO ${i.identifier(f)} (${i.identifier("companion")}, ${i.identifier("cursor")}, ${i.identifier("done")}, ${i.identifier("profile")}) VALUES (${t}, ${$}, ${n?1:0}, ${a})`)}catch(c){if(!e.isUniqueViolation(c))throw c;await s(r,e,d)}};export{f as SEARCH_STATE_TABLE,l as migrateSearchState,S as readSearchBackfillState,A as writeSearchBackfillState};
1
+ import{sql as i}from"drizzle-orm";import{queryRun as s,queryAll as E}from"./decodeGlobalRow-C8O2hy0d.mjs";const f="__lunora_search_state",l=async(r,e)=>{const{integer:t,key:o}=e.companionTypes,n=async()=>{try{await s(r,e,i`ALTER TABLE ${i.identifier(f)} ADD COLUMN ${i.identifier("profile")} ${i.raw(o)}`)}catch{}};await s(r,e,i`CREATE TABLE IF NOT EXISTS ${i.identifier(f)} (${i.identifier("companion")} ${i.raw(o)} PRIMARY KEY, ${i.identifier("cursor")} ${i.raw(o)}, ${i.identifier("done")} ${i.raw(t)} NOT NULL DEFAULT 0, ${i.identifier("profile")} ${i.raw(o)})`),await n()},p=r=>r===1||r===!0||r==="1",S=async(r,e,t)=>{const n=(await E(r,e,i`SELECT ${i.identifier("cursor")}, ${i.identifier("done")}, ${i.identifier("profile")} FROM ${i.identifier(f)} WHERE ${i.identifier("companion")} = ${t}`))[0];if(!n)return{cursor:void 0,done:!1,profile:void 0};const{cursor:a,profile:$}=n;return{cursor:typeof a=="string"?a:void 0,done:p(n.done),profile:typeof $=="string"?$:void 0}},A=async(r,e,t,o,n,a)=>{const $=o??null,d=i`UPDATE ${i.identifier(f)} SET ${i.identifier("cursor")} = ${$}, ${i.identifier("done")} = ${n?1:0}, ${i.identifier("profile")} = ${a} WHERE ${i.identifier("companion")} = ${t}`;if((await E(r,e,i`SELECT ${i.identifier("companion")} FROM ${i.identifier(f)} WHERE ${i.identifier("companion")} = ${t}`)).length>0){await s(r,e,d);return}try{await s(r,e,i`INSERT INTO ${i.identifier(f)} (${i.identifier("companion")}, ${i.identifier("cursor")}, ${i.identifier("done")}, ${i.identifier("profile")}) VALUES (${t}, ${$}, ${n?1:0}, ${a})`)}catch(c){if(!e.isUniqueViolation(c))throw c;await s(r,e,d)}};export{f as SEARCH_STATE_TABLE,l as migrateSearchState,S as readSearchBackfillState,A as writeSearchBackfillState};
@@ -0,0 +1 @@
1
+ import{d as S,c as s,a as i,r as l}from"./ctx-db-search-BiMTuJzw.mjs";import"./SEARCH_STATE_TABLE-B5a5xBwB.mjs";import"./decodeGlobalRow-C8O2hy0d.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
@@ -0,0 +1,7 @@
1
+ import{LunoraError as g}from"@lunora/errors";import{c as It,r as At,A as Lt,q as kt,C as Nt,R as Mt,a as Dt,T as qt,x as Ot,b as Ft}from"./ctx-db-search-BiMTuJzw.mjs";import{d as ii}from"./ctx-db-search-BiMTuJzw.mjs";import{literalInList as Bt,throwingScheduler as xt,CDC_LOG_TABLE as G,cursorBelowRetainedFloor as Wt,cdcTrimmedError as Ut,aggregateTableName as J,rankTableName as ne,assertNoExplicitUndefined as Ze,hasTrigger as Pt,runRowValidators as De,assertFlatPredicate as et,mergeWhere as O,sortColumnName as Q,resolveRankPartition as tt,encodePartitionKey as Ie,resolveRankSeekTuple as jt,RANK_TIEBREAK as Ee,CountRlsUnsupportedError as nt,normalizeIdStructurally as Kt,assertValidClientId as Ht,aggregateSqlFunction as we,softDeleteScope as _e,compileWhereSql as $e,normalizeOrderKeys as Gt,buildSeekWhere as Vt,decodeCursor as Yt,resolveRelationPredicates as it,resolveWith as ot,relationHooks as rt,applySelect as st,encodeCursor as Xt,NotFoundError as zt,applyOnDelete as Jt,ConflictError as he,normalizeCountArgument as Qt,selectIndexForCount as Zt,encodeAggregateKey as z,selectIndexForAggregate as en,readAggregateValue as qe,runTriggers as tn,matchesRankStaticWhere as at,CURSOR_PREFIX as nn,selectIndexForGroupBy as on,tiebreakDirectionFor as rn,fanOutScalarCounts as sn,matchesStaticWhere as Oe,foldAggregateTally as an,coerceAggregateNumber as Fe,CDC_LOG_TABLE_SEQ_INDEX as cn,NotUniqueError as dn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{d as _t,e as Le,n as ln,b as un}from"./value-codec-CwTLrqfU.mjs";import{migrateSearchState as fn}from"./SEARCH_STATE_TABLE-B5a5xBwB.mjs";import{queryAll as C,queryRun as A,createIndexIfNotExists as Ae,decodeRow as ie,serializeColumnValue as H,columnRefSql as F,decodeRows as wn,forEachRowPaged as ct,queryBatch as dt}from"./decodeGlobalRow-C8O2hy0d.mjs";import{decodeGlobalRow as ri}from"./decodeGlobalRow-C8O2hy0d.mjs";const _n=(s,u)=>{if(s.size<u)return;const l=s.keys().next().value;l!==void 0&&s.delete(l)},lt=50,$n=(s,u={})=>{const l=u.maxBatch??lt,i=Number.isInteger(l)&&l>0?l:lt,h=new Map;let d=!1;const c=async(R,b)=>{const v=[...b.keys()];for(let L=0;L<v.length;L+=i){const M=v.slice(L,L+i);try{const x=await s(R,M);for(const V of M){const Y=x.get(V);for(const X of b.get(V)??[])X.resolve(Y)}}catch(x){for(const V of M)for(const Y of b.get(V)??[])Y.reject(x)}}},m=()=>{d=!1;const R=[...h.entries()];h.clear();for(const[b,v]of R)c(b,v).catch(()=>{})};return{async load(R,b){return new Promise((v,L)=>{let M=h.get(R);M||(M=new Map,h.set(R,M));const x=M.get(b);x?x.push({reject:L,resolve:v}):M.set(b,[{reject:L,resolve:v}]),d||(d=!0,queueMicrotask(m))})}}},hn=new Set(["_id","id"]),We=(s,u,l)=>s==="postgres"?e`${u} IS NOT DISTINCT FROM ${l}`:s==="mysql"?e`${u} <=> ${l}`:e`${u} IS ${l}`,En=s=>{const u=s.map(l=>e`${F(l.field)} ${e.raw(l.direction==="desc"?"DESC":"ASC")}`);if(!s.some(l=>hn.has(l.field))){const l=rn(s);u.push(e`${F("id")} ${e.raw(l==="desc"?"DESC":"ASC")}`)}return e.join(u,e`, `)},ut=50,Ue=s=>{const u=[];for(const[l,i]of Object.entries(s.shape)){const h=i._meta?.column;h&&u.push([l,h])}return u},yn=(s,u,l)=>{const i={...u};for(const[h,d]of Ue(s)){if(d.serverDefault){i[h]=d.serverDefault({auth:l});continue}i[h]===void 0&&(d.defaultFn?i[h]=d.defaultFn():"defaultValue"in d&&(i[h]=d.defaultValue))}return i},ft=(s,u,l,i)=>{for(const[h,d]of Ue(s)){if(d.serverDefault){h in u&&(l[h]=d.serverDefault({auth:i}));continue}d.onUpdateFn&&!(h in u)&&(l[h]=d.onUpdateFn())}},pn=128,Rn=()=>{const s=new Map;return{delete:u=>{s.delete(u)},get:u=>{const l=s.get(u);if(l!==void 0)return s.delete(u),s.set(u,l),l},set:(u,l)=>{s.has(u)?s.delete(u):_n(s,pn),s.set(u,l)}}},Tn=async(s,u,l,i,h)=>{const d=h.get(i);if(d!==void 0)return d;const c=Object.entries(l.tables).filter(([,R])=>R.shardMode===void 0||R.shardMode.kind==="global").map(([R])=>R),m=await Promise.all(c.map(async R=>({found:(await C(s,u,e`SELECT 1 FROM ${e.identifier(R)} WHERE ${e.identifier("id")} = ${i} LIMIT 1`)).length>0,tableName:R})));for(const R of m)if(R.found)return h.set(i,R.tableName),R.tableName},oe=s=>s==null?null:Number(s),mn=(s,u)=>u.map(l=>{const i={};for(const h of s)i[h]=l[h]??null;return{key:i,value:oe(l.value)}}),Sn=(s,u,l)=>[...s.partitionBy??[],...s.sortBy.map(h=>h.field),...s.where?Object.keys(s.where):[]].every(h=>u[h]===l[h]),$t=s=>s.length===1?s[0]:e`(${e.join(s,e` AND `)})`,te=s=>e.join(s.map(u=>e`${e.identifier(u)}`),e`, `),re=s=>e.join(s.map(u=>e`${u}`),e`, `),gn=(s,u,l,i,h)=>{const d=[];for(let c=0;c<l.length+1;c+=1){const m=l.slice(0,c).map(v=>We(s,e`${e.identifier(v)}`,i[v])),R=l[c],b=u.sortBy[c];c<l.length&&R!==void 0&&b!==void 0?m.push(e`${e.identifier(R)} ${e.raw(b.direction==="desc"?">":"<")} ${i[R]}`):m.push(e`${e.identifier(Ee)} < ${h}`),d.push($t(m))}return d.length>0?e.join(d,e` OR `):void 0},vn=(s,u,l)=>{if(l.length!==u.length)return;const i=[];for(const[h,d]of u.entries()){const c=[];for(let m=0;m<h;m+=1){const R=u[m];R!==void 0&&c.push(We(s,e`${e.identifier(R.column)}`,l[m]))}c.push(e`${e.identifier(d.column)} ${e.raw(d.direction==="desc"?"<":">")} ${l[h]}`),i.push($t(c))}return e`(${e.join(i,e` OR `)})`},bn=(s,u)=>{if(s.sortBy.length===0)throw new g("INTERNAL",`rankIndex "${s.name}" requires at least one "sortBy" column for stable pagination`);const l=[{column:"__partition__",direction:"asc"}];for(const[i,h]of s.sortBy.entries())l.push({column:u[i]??Q(i),direction:h.direction});return l.push({column:Ee,direction:"asc"}),l},Cn=async(s,u,l,i,h)=>{const c=[];for(let v=0;v<h.length;v+=50)c.push(h.slice(v,v+50));const m=await Promise.all(c.map(async v=>C(s,u,e`SELECT * FROM ${e.identifier(i)} WHERE ${e.identifier("id")} IN (${re(v)})`))),R=new Map;for(const v of m)for(const L of v)R.set(L.id,L);const b=[];for(const v of h){const L=ie(l,R.get(v));L&&b.push(L)}return b},In=s=>{const u=JSON.stringify(s),l=new TextEncoder().encode(u);let i="";for(const h of l)i+=String.fromCodePoint(h);return nn+btoa(i)},An=(s,u)=>u.columnType(Le(s)),Ln=(s,u,l)=>{const i=[];for(const[c,m]of Object.entries(u.shape)){if(!m._meta?.column)continue;const R=m._meta.column.notNull&&m.kind!=="optional"?" NOT NULL":"";i.push(e`${e.identifier(c)} ${e.raw(`${An(m,l)}${R}`)}`)}const h=l.frameworkColumns().map(c=>e`${e.identifier(c.name)} ${e.raw(c.type)}`),d=h.length+i.length;if(l.maxTableColumns!==void 0&&d>l.maxTableColumns)throw new g("VALIDATION_ERROR",`@lunora/sql-store: global table "${s}" needs ${String(d)} columns, over this engine's ${String(l.maxTableColumns)}-column limit — split the table, or move the extra fields into one object field`);return e.join([...h,...i],e`, `)},kn=async(s,u,l,i)=>{const h=d=>{const c=F(d),m=l.shape[d],R=m&&i.indexKeyPrefix?i.indexKeyPrefix(Le(m)):void 0;return R===void 0?c:e`${c}(${e.raw(String(R))})`};for(const d of l.indexes){const c=e.join(d.fields.map(m=>h(m)),e`, `);await Ae(s,i,{columns:c,name:`${u}_${d.name}`,table:u,unique:d.unique??!1})}for(const[d,c]of Ue(l))c.unique&&await Ae(s,i,{columns:h(d),name:`${u}_unique_${d}`,table:u,unique:!0})},Nn=async(s,u,l)=>{for(const[i,h]of Object.entries(u.tables)){if(h.shardMode?.kind!=="global")continue;const d=Ln(i,h,l);await A(s,l,e`CREATE TABLE IF NOT EXISTS ${e.identifier(i)} (${d})`),await kn(s,i,h,l)}},Mn=async(s,u,l)=>{const{integer:i,key:h,real:d}=l.companionTypes;for(const[c,m]of Object.entries(u.tables)){const R=m.aggregateIndexes;if(!(!R||R.length===0))for(const b of R){const v=J(c,b.name);await A(s,l,e`CREATE TABLE IF NOT EXISTS ${e.identifier(v)} (${e.identifier("__key__")} ${e.raw(h)} PRIMARY KEY, ${e.identifier("__value__")} ${e.raw(d)}, ${e.identifier("__count__")} ${e.raw(i)} NOT NULL DEFAULT 0)`),l.name==="sqlite"&&((await C(s,l,e`PRAGMA table_info(${e.identifier(v)})`)).some(M=>M.name==="__count__")||await A(s,l,e`ALTER TABLE ${e.identifier(v)} ADD COLUMN ${e.identifier("__count__")} ${e.raw(i)} NOT NULL DEFAULT 0`))}}},Be=(s,u,l,i)=>{const h=s.name==="mysql"&&i?e`${e.identifier(u)}(191)`:e`${e.identifier(u)}`;return e`${h} ${e.raw(l)}`},Dn=(s,u,l)=>{const i=[Be(s,"__partition__","ASC",!0)];for(const[h,d]of u.sortBy.entries()){const c=l.shape[d.field],m=c!==void 0&&s.indexKeyPrefix?.(Le(c))!==void 0;i.push(Be(s,Q(h),d.direction==="desc"?"DESC":"ASC",m))}return i.push(Be(s,"__id__","ASC",!0)),i},qn=(s,u,l)=>u.sortBy.map((i,h)=>{const d=l.shape[i.field],c=s.columnType(d?Le(d):void 0);return e`${e.identifier(Q(h))} ${e.raw(c)}`}),On=async(s,u,l)=>{const{key:i}=l.companionTypes;for(const[h,d]of Object.entries(u.tables)){const c=d.rankIndexes;if(!(!c||c.length===0))for(const m of c){const R=ne(h,m.name),b=qn(l,m,d),v=b.length>0?e`, ${e.join(b,e`, `)}`:e``;await A(s,l,e`CREATE TABLE IF NOT EXISTS ${e.identifier(R)} (${e.identifier("__id__")} ${e.raw(i)} PRIMARY KEY, ${e.identifier("__partition__")} ${e.raw(i)} NOT NULL${v})`);const L=Dn(l,m,d),M=`${h}__rank_${m.name}__btree`;await Ae(s,l,{columns:e.join(L,e`, `),name:M,table:R,unique:!1})}}},xe="__cdc_sweep",ht="global",Fn=6e4,Bn=1e4,xn=3e4;let wt=0;const Wn=async(s,u)=>{const{autoincrementPrimaryKey:l,key:i,real:h,text:d}=u.companionTypes;await A(s,u,e`CREATE TABLE IF NOT EXISTS ${e.identifier(G)} (${e.identifier("seq")} ${e.raw(l)}, ${e.identifier("ts")} ${e.raw(h)} NOT NULL, ${e.identifier("table")} ${e.raw(i)} NOT NULL, ${e.identifier("id")} ${e.raw(i)} NOT NULL, ${e.identifier("op")} ${e.raw(i)} NOT NULL, ${e.identifier("doc")} ${e.raw(d)})`);const c=u.indexKeyPrefix?.("string");await Ae(s,u,{columns:e`${c===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(c))})`}, ${e.identifier("seq")}`,name:cn,table:G,unique:!1}),await A(s,u,e`CREATE TABLE IF NOT EXISTS ${e.identifier(xe)} (${e.identifier("id")} ${e.raw(i)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(h)} NOT NULL)`),await A(s,u,e`INSERT INTO ${e.identifier(xe)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${ht}, ${0}) ${u.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},Un=async(s,u,l)=>{const i=e`UPDATE ${e.identifier(xe)} SET ${e.identifier("lease_until")} = ${l+Fn} WHERE ${e.identifier("id")} = ${ht} AND ${e.identifier("lease_until")} <= ${l}`;if(u.supportsReturning)return(await C(s,u,e`${i} RETURNING ${e.identifier("id")}`)).length>0;const h=await A(s,u,i);return(u.affectedRows?u.affectedRows(h??{rowsAffected:0}):0)>0},Pn=async(s,u,l,i)=>{if(!await Un(s,u,i))return;const h=i-l;await A(s,u,e`
2
+ DELETE FROM ${e.identifier(G)} WHERE ${e.identifier("seq")} IN (
3
+ SELECT ${e.identifier("seq")} FROM (
4
+ SELECT ${e.identifier("seq")} FROM ${e.identifier(G)} WHERE ${e.identifier("ts")} <= ${h} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(Bn))}
5
+ ) AS ${e.identifier("expired")}
6
+ )
7
+ `)},Et=async(s,u)=>{const l=await C(s,u,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(G)}`),i=Number(l[0]?.seq??Number.NaN);return Number.isFinite(i)?i:void 0},jn=s=>JSON.stringify(ln(s)?un(s):s),Kn=async(s,u,l,i,h,d,c)=>{await A(s,c,e`INSERT INTO ${e.identifier(G)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${u}, ${l}, ${i}, ${h}, ${d===void 0?null:jn(d)})`)},Zn=async(s,u,l)=>{const i=u.sinceSeq??0,h=Math.max(1,Math.min(u.limit??1e3,1e4)),d=await Et(s,l);if(d!==void 0&&Wt(d,i))throw Ut(d,i,"global");const m=(await C(s,l,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(G)} WHERE seq > ${i} ORDER BY seq ASC LIMIT ${e.raw(String(h))}`)).map(R=>{const{doc:b}=R,v={id:String(R.id),op:String(R.op),seq:Number(R.seq),table:String(R.table),ts:Number(R.ts)};return typeof b=="string"?{...v,doc:_t(JSON.parse(b))}:v});return{changes:m,cursor:m.at(-1)?.seq??i}},Hn=async(s,u,l,i={})=>{if(i.cursorOnly){const R=await C(s,l,e`SELECT MAX(seq) AS seq FROM ${e.identifier(G)}`),b=Number(R[0]?.seq??u);return{cursor:Number.isFinite(b)?b:u,tables:[]}}const h=await C(s,l,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(G)} WHERE seq > ${u} GROUP BY ${e.identifier("table")}`);let d=u;const c=[];for(const R of h){const b=Number(R.seq);Number.isFinite(b)&&b>d&&(d=b),c.push(String(R.table))}const m=i.retained===!0?await Et(s,l):void 0;return{cursor:d,tables:c,...m===void 0?{}:{floor:m}}},ei=s=>{const{crossShardCounter:u,crossShardReader:l,exec:i,maxRelationKeys:h,schema:d}=s,{dialect:c}=s,{isUniqueViolation:m}=c,R={fieldRef:F,serialize:H,...c.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...c.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...c.name==="sqlite"?{}:{inList:Bt}},b=(t,n)=>We(c.name,t,n),v=t=>{const n=te(t.columns),o=re(t.values),r=f=>c.name==="mysql"?e`VALUES(${e.identifier(f)})`:e`excluded.${e.identifier(f)}`,a=f=>c.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(f)}`:e`${e.identifier(f)}`,_=e.join(Object.entries(t.set(r,a)).map(([f,y])=>e`${e.identifier(f)} = ${y}`),e`, `),E=c.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${_}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${_}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${o}) ${E}`},L=s.clock??(()=>Date.now()),M=s.idGenerator??(()=>crypto.randomUUID()),x=s.cdc??!1,V=typeof s.cdcRetentionMs=="number"&&Number.isFinite(s.cdcRetentionMs)&&s.cdcRetentionMs>0?s.cdcRetentionMs:void 0,Y=s.auth??{identity:null,userId:null},X=async(t,n,o,r)=>{if(!x||(await Kn(i,L(),t,n,o,r,c),V===void 0))return;const a=L();if(!(a-wt<xn)){wt=a;try{await Pn(i,c,V,a)}catch{}}},yt=s.scheduler??xt,ke=Rn();let ye=0,Ne;const W=async()=>(Ne??=(async()=>{await Nn(i,d,c),await Mn(i,d,c),await On(i,d,c),await fn(i,c),await At(i,d,c),x&&await Wn(i,c)})().catch(t=>{throw Ne=void 0,t}),Ne),se=async(t,n)=>{await W();const o=await Tn(i,c,d,t,ke);if(!(n!==void 0&&o!==n))return o},ae=new Map,Pe=async(t,n)=>{const o=J(t,n);return(await C(i,c,c.tableExists(o))).length>0},pe=async(t,n)=>{const o=`${t}::${n.name}`,r=ae.get(o);if(r!==void 0)return r;if(!await Pe(t,n.name))return ae.set(o,!1),!1;const _=d.tables[t];if(!_)return ae.set(o,!1),!1;const E=n.by??[],f=new Map;await ct(i,c,_,t,$=>{if(n.where&&!Oe($,n.where))return;const p=z(E,$);an(f,p,n,$)});const y=J(t,n.name);await A(i,c,e`DELETE FROM ${e.identifier(y)}`);const w=[];for(const[$,p]of f)w.push(e`INSERT INTO ${e.identifier(y)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${$}, ${p.value}, ${p.count})`);return await dt(i,c,w),ae.set(o,!0),!0},pt=async(t,n,o)=>{const r=we(n.op),a=n.field??"",_=[];for(const y of n.by??[]){const w=H(o[y]??null);_.push(w===null?e`${F(y)} IS NULL`:e`${F(y)} = ${w}`)}for(const[y,w]of Object.entries(n.where??{})){const $=w!==null&&typeof w=="object"&&!Array.isArray(w)?w.eq:w,p=H($);_.push(p===null?e`${F(y)} IS NULL`:e`${F(y)} = ${p}`)}const E=e`SELECT ${e.raw(r)}(${F(a)}) AS value FROM ${e.identifier(t)}`,f=await C(i,c,_.length>0?e`${E} WHERE ${e.join(_,e` AND `)}`:E);return oe(f[0]?.value)},Rt=async(t,n)=>{await A(i,c,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},Tt=async(t,n,o,r)=>{const a=J(t,n.name),{op:_}=n,E=n.field??"",f=o&&(!n.where||Oe(o,n.where))?o:void 0,y=r&&(!n.where||Oe(r,n.where))?r:void 0;if(!(!f&&!y)){if(_==="count"||_==="sum"||_==="avg"){const w=new Set;for(const[$,p]of[[f,-1],[y,1]]){if(!$)continue;const S=_==="count"?1:Fe($[E]);if(S===void 0)continue;const T=z(n.by??[],$);w.add(T),await A(i,c,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(I,k)=>({__count__:e`${k("__count__")} + ${I("__count__")}`,__value__:_==="count"?e`${k("__value__")} + ${I("__value__")}`:e`COALESCE(${k("__value__")}, 0) + ${I("__value__")}`}),table:a,values:[T,p*S,p]}))}for(const $ of w)await Rt(a,$);return}if(f){const w=z(n.by??[],f),$=Fe(f[E]),S=(await C(i,c,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(a)} WHERE ${e.identifier("__key__")} = ${w}`))[0],T=oe(S?.value),I=(S?.count??0)-1;if(I<=0)await A(i,c,e`DELETE FROM ${e.identifier(a)} WHERE ${e.identifier("__key__")} = ${w}`);else if(S&&$!==void 0&&T!==null&&$===T){const k=await pt(t,n,f);await A(i,c,e`UPDATE ${e.identifier(a)} SET ${e.identifier("__value__")} = ${k}, ${e.identifier("__count__")} = ${I} WHERE ${e.identifier("__key__")} = ${w}`)}else await A(i,c,e`UPDATE ${e.identifier(a)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${w}`)}if(y){const w=z(n.by??[],y),$=Fe(y[E]);if($===void 0)await A(i,c,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(p,S)=>({__count__:e`${S("__count__")} + 1`}),table:a,values:[w,null,1]}));else{const p=_==="min"?"MIN":"MAX";await A(i,c,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(S,T)=>({__count__:e`${T("__count__")} + 1`,__value__:e`${e.raw(p)}(COALESCE(${T("__value__")}, ${S("__value__")}), ${S("__value__")})`}),table:a,values:[w,$,1]}))}}}},Re=async t=>{const n=d.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const o of n)await pe(t,o)},ce=async(t,n,o)=>{const r=d.tables[t]?.aggregateIndexes;if(!(!r||r.length===0))for(const a of r){const _=`${t}::${a.name}`;(ae.get(_)??await Pe(t,a.name))&&await Tt(t,a,n,o)}},de=new Map,je=async(t,n)=>{const o=ne(t,n);return(await C(i,c,c.tableExists(o))).length>0},Me=async(t,n)=>{const o=`${t}::rank::${n.name}`,r=de.get(o);if(r!==void 0)return r;if(!await je(t,n.name))return de.set(o,!1),!1;const _=d.tables[t];if(!_)return de.set(o,!1),!1;const E=ne(t,n.name);await A(i,c,e`DELETE FROM ${e.identifier(E)}`);const f=n.sortBy.map((p,S)=>Q(S)),y=te(["__id__","__partition__",...f]),w=[];await ct(i,c,_,t,p=>{if(n.where&&!at(p,n.where))return;const S=Ie(n.partitionBy??[],p),T=n.sortBy.map(I=>H(p[I.field]??null));w.push([p._id,S,...T])});const $=w.map(p=>e`INSERT INTO ${e.identifier(E)} (${y}) VALUES (${re(p)})`);return await dt(i,c,$),de.set(o,!0),!0},Te=async t=>{const n=d.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const o of n)await Me(t,o)},Z=async(t,n,o,r)=>{const a=d.tables[t],_=a?.rankIndexes;if(!_||_.length===0)return;const E=a?.softDeleteMode?.field,f=E===void 0||r===void 0?void 0:r[E],y=f!=null;for(const w of _){if(o!==void 0&&r!==void 0&&Sn(w,o,r))continue;const $=`${t}::rank::${w.name}`;if(!(de.get($)??await je(t,w.name)))continue;const T=ne(t,w.name);if(o&&await A(i,c,e`DELETE FROM ${e.identifier(T)} WHERE ${e.identifier("__id__")} = ${n}`),r&&!y){if(w.where&&!at(r,w.where))continue;const I=w.sortBy.map((D,K)=>Q(K)),k=te(["__id__","__partition__",...I]),B=Ie(w.partitionBy??[],r),N=w.sortBy.map(D=>H(r[D.field]??null));await A(i,c,e`INSERT INTO ${e.identifier(T)} (${k}) VALUES (${re([n,B,...N])})`)}}},le=It({dialect:c,exec:i,schema:d}),Ke=new Set;for(const[t,n]of Object.entries(d.tables))for(const o of Object.values(n.triggerMap??{}))Ke.add(`${t} ${o.timing} ${o.op}`);const P=(t,n,o)=>Ke.has(`${t} ${n} ${o}`);let He;const j=async(t,n,o)=>{if(ye+=1,ye>ut)throw ye-=1,new he(`trigger recursion exceeded ${String(ut)} levels on "${o.table}" — check for a self-triggering write`,"trigger");try{await tn({ctx:He,event:o,op:n,schema:d,tableName:o.table,timing:t})}finally{ye-=1}},mt=async(t,n)=>{try{await A(i,c,n)}catch(o){throw m(o)?new he(`unique constraint violation on "${t}"`,"unique"):o}},me=async(t,n)=>(await C(i,c,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],Se=async(t,n,o,r)=>{if(r===void 0)return;const a=e.join(Object.keys(r).map(f=>b(e`${e.identifier(f)}`,r[f])),e` AND `),_=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${o} WHERE ${a}`:e`DELETE FROM ${e.identifier(t)} WHERE ${a}`,E=()=>{throw new he(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(c.supportsReturning)(await C(i,c,e`${_} RETURNING ${e.identifier("id")}`)).length===0&&E();else{const f=await A(i,c,_);(c.affectedRows?c.affectedRows(f??{rowsAffected:0}):0)===0&&E()}}catch(f){throw m(f)?new he(`unique constraint violation on "${t}"`,"unique"):f}},St=(t,n,o,r)=>{const a=Object.keys(t.shape);return{columns:["id","_creationTime",...a],values:[n,o,...a.map(_=>H(r[_]??null))]}},gt=async(t,n,o,r)=>{const a=on(n,o.op,o.field,r.by,r.where);if(!a||!await pe(t,a.index))return;const E=J(t,a.index.name),f=Object.keys(a.partial);if(f.length===(a.index.by??[]).length&&f.length>0){const w=z(a.index.by??[],a.partial),$=await C(i,c,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(E)} WHERE ${e.identifier("__key__")} = ${w}`);if($.length===0)return[];const p=$[0];return[{key:{...a.partial},value:qe(o.op,{count:p.count,value:oe(p.value)})}]}return f.length>0?void 0:(await C(i,c,e`SELECT ${e.identifier("__key__")} AS key, ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(E)}`)).map(w=>{const $=w;return{key:_t(JSON.parse($.key)),value:qe(o.op,{count:$.count,value:oe($.value)})}})},Ge=t=>{const n=d.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},Ve=t=>{throw new g("INTERNAL",`cross-backend relation: a global table cannot load the shard-local relation '${t}' (it spans every shard) — wire a cross-shard reader to support it`)},vt=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new g("MASK_UNSUPPORTED",`masking cannot follow a nested \`with\` across the cross-shard relation hop to "${t}" — the nested rows are hydrated on the serving shard, where the mask policy does not exist. Read the nested relation at its own (masked) call site instead.`);const o={};if(n?.relationBaseWhere)for(const r of Object.keys(d.tables)){const a=n.relationBaseWhere(r);a!==void 0&&(o[r]=a)}return{orderBy:n?.orderBy,relationPolicies:o,where:O(n?.baseWhere,n?.where),with:n?.with}},Ye=(t,n)=>Ge(t)?l?l(t,vt(t,n)):Ve(t):U.findMany(t,n),ge=(t,n,o)=>it(t,{fetcher:Ye,maxRelationKeys:h,relationBaseWhere:o,schema:d,tableName:n}),bt=$n(async(t,n)=>{const o=await C(i,c,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${re(n)})`),r=new Map;for(const a of o){const{id:_}=a;typeof _=="string"&&r.set(_,a)}return r}),U={async cdcChangedTables(t,n){if(x)try{return await W(),await Hn(i,t,c,{...n,retained:V!==void 0})}catch{return}},async aggregate(t,n){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);if(await W(),we(n.op),n.op==="count")return U.count(t,{baseWhere:n.baseWhere,relationBaseWhere:n.relationBaseWhere,restrictsCounts:n.restrictsCounts,where:n.where});if(!n.field)throw new g("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const r=_e(o.softDeleteMode,void 0),a=O(O(n.baseWhere,n.where),r),_=await ge(a,t,n.relationBaseWhere),E=_!==a;if(o.aggregateIndexes&&!n.baseWhere&&!E&&!r){const S=en(o.aggregateIndexes,n.op,n.field,n.where);if(S&&await pe(t,S.index)){const I=z(S.index.by??[],S.key),k=J(t,S.index.name),N=(await C(i,c,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(k)} WHERE ${e.identifier("__key__")} = ${I}`))[0];return qe(n.op,N===void 0?void 0:{count:N.count,value:oe(N.value)})}}const f=$e(_,R),y=e.raw(we(n.op)),w=e`SELECT ${y}(${F(n.field)}) AS value FROM ${e.identifier(t)}`,p=(await C(i,c,f?e`${w} WHERE ${f}`:w))[0]?.value;return p==null?null:Number(p)},async count(t,n){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);await W();const r=Qt(n);if(r.restrictsCounts)throw new nt(t);const a=_e(o.softDeleteMode,void 0),_=O(O(r.baseWhere,r.where),a),E=await ge(_,t,r.relationBaseWhere),f=E!==_;if(o.aggregateIndexes&&!r.baseWhere&&!f&&!a){const p=Zt(o.aggregateIndexes,r.where);if(p&&await pe(t,p.index)){const T=z(p.index.by??[],p.key),I=J(t,p.index.name),k=await C(i,c,e`SELECT ${e.identifier("__value__")} AS value FROM ${e.identifier(I)} WHERE ${e.identifier("__key__")} = ${T}`);return Number(k[0]?.value??0)}}const y=$e(E,R),w=e`SELECT COUNT(*) AS count FROM ${e.identifier(t)}`,$=await C(i,c,y?e`${w} WHERE ${y}`:w);return Number($[0]?.count??0)},async delete(t,n,o){const r=await se(t,n);if(!r)return;const a=d.tables[r];if(!a)return;const _=await me(r,t),E=ie(a,_),f=o?.hard===!0,y=!f&&a.softDeleteMode?a.softDeleteMode.field:void 0;if(!(y&&(!E||E[y]!==null&&E[y]!==void 0))){if(P(r,"before","delete")&&await j("before","delete",{id:t,op:"delete",previous:E??void 0,table:r}),await Jt({deletedId:t,deletedReference:w=>E?.[w],findHolders:async(w,$,p)=>{if(d.tables[w]?.shardMode?.kind==="shardBy")throw new g("INTERNAL",`cross-backend cascade from global '${r}' into shardBy '${w}' is not supported — would require Query Coordinator fan-out across shards`);return(await U.findMany(w,{includeDeleted:f,where:{[$]:p}})).page},onCascade:(w,$)=>U.delete($,void 0,o),onRestrict:w=>{throw new he(w,"restrict")},onSetNull:(w,$,p)=>U.patch($,{[p]:null}),schema:d,tableName:r}),await Re(r),await Te(r),y&&E){const w={...E,[y]:L()},$=e.join(Object.keys(a.shape).map(p=>e`${e.identifier(p)} = ${H(w[p]??null)}`),e`, `);await Se(r,"UPDATE",$,_),await ce(r,E,w),await Z(r,t,E,void 0),await le(r,t,w,E),await X(r,t,"update",w),P(r,"after","delete")&&await j("after","delete",{id:t,op:"delete",previous:E,table:r});return}await Se(r,"DELETE",void 0,_),ke.delete(t),await ce(r,E??void 0,void 0),await Z(r,t,E??void 0,void 0),await le(r,t,void 0),await X(r,t,"delete"),P(r,"after","delete")&&await j("after","delete",{id:t,op:"delete",previous:E??void 0,table:r})}},async findFirst(t,n={}){return(await U.findMany(t,{...n,limit:1})).page[0]??null},async findFirstOrThrow(t,n={}){const o=await U.findFirst(t,n);if(o===null)throw new zt(`findFirstOrThrow: no "${t}" document matched`);return o},async findMany(t,n={}){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);await W();const r=Gt(n.orderBy),a=n.cursor?Vt(r,Yt(n.cursor)):void 0,_=Ye,E=async(N,D,K,ve)=>{if(Ge(N))return u?sn(u,N,D,K,ve):Ve(N);const be=d.tables[N];if(!be)throw new g("INTERNAL",`unknown table: ${N}`);const Ce=_e(be.softDeleteMode,void 0),ee={[D]:{in:K}},q=O(O(ee,ve),Ce),ue=await ge(q,N,void 0),Xe=$e(ue,R),ze=F(D);let fe=e`SELECT ${ze} AS __fk__, COUNT(*) AS count FROM ${e.identifier(N)}`;Xe&&(fe=e`${fe} WHERE ${Xe}`),fe=e`${fe} GROUP BY ${ze}`;const Ct=await C(i,c,fe),Je=new Map;for(const Qe of Ct)Je.set(Qe.__fk__,Number(Qe.count??0));return Je};let f=O(n.baseWhere,n.where);f=O(f,_e(o.softDeleteMode,n.includeDeleted)),f=await it(f,{fetcher:_,maxRelationKeys:h,relationBaseWhere:n.relationBaseWhere,schema:d,tableName:t}),a&&(f=f?{AND:[f,a]}:a);const y=$e(f,R),w=En(r);let $=e`SELECT * FROM ${e.identifier(t)}`;y&&($=e`${$} WHERE ${y}`),$=e`${$} ORDER BY ${w}`;const p=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;p!==void 0&&($=e`${$} LIMIT ${e.raw(String(p+1))}`);const S=await C(i,c,$),T=wn(o,S);if(p===void 0)return n.with&&await ot({fetcher:_,groupedCounter:E,parents:T,...rt(n),schema:d,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:st(T,n.select,n.with)};const I=T.length>p,k=I?T.slice(0,p):T,B=k.at(-1);return n.with&&await ot({fetcher:_,groupedCounter:E,parents:k,...rt(n),schema:d,tableName:t,with:n.with}),{continueCursor:I&&B?Xt(B,r):null,isDone:!I,page:st(k,n.select,n.with)}},async get(t,n){const o=await se(t,n);if(!o)return null;const r=d.tables[o];return r?ie(r,await bt.load(o,t)):null},async groupBy(t,n){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);await W();const r=n.agg??{op:"count"};if(we(r.op),r.op!=="count"&&!r.field)throw new g("INTERNAL",`groupBy(${t}, { agg: { op: "${r.op}" } }): "field" is required for non-count reducers`);const a=_e(o.softDeleteMode,void 0),_=O(O(n.baseWhere,n.where),a),E=await ge(_,t,n.relationBaseWhere),f=E!==_;if(o.aggregateIndexes&&!n.baseWhere&&!f&&!a){const T=await gt(t,o.aggregateIndexes,r,n);if(T!==void 0)return T}const y=$e(E,R),w=n.by.map(T=>e`${F(T)} AS ${e.identifier(T)}`);if(r.op==="count")w.push(e`COUNT(*) AS value`);else{if(!r.field)throw new g("INTERNAL",`groupBy(${t}, { agg: { op: "${r.op}" } }): "field" is required for non-count reducers`);w.push(e`${e.raw(we(r.op))}(${F(r.field)}) AS value`)}const $=e.join(n.by.map(T=>F(T)),e`, `);let p=e`SELECT ${e.join(w,e`, `)} FROM ${e.identifier(t)}`;y&&(p=e`${p} WHERE ${y}`),p=e`${p} GROUP BY ${$}`;const S=await C(i,c,p);return mn(n.by,S)},async insert(t,n,o){const r=d.tables[t];if(!r)throw new g("INTERNAL",`unknown table: ${t}`);await W();const a=yn(r,n,Y);De(r,a);let _,E=!0;o?.clientId!==void 0?(Ht(o.clientId),_=o.clientId):o?.allowExplicitId&&typeof a._id=="string"?_=a._id:(_=M(),E=!1);const f=o?.allowExplicitId&&typeof a._creationTime=="number"?a._creationTime:L(),y={...a,_creationTime:f,_id:_};P(t,"before","insert")&&await j("before","insert",{doc:{...y},id:_,op:"insert",table:t}),await Re(t),await Te(t);const{columns:w,values:$}=St(r,_,f,a);return await mt(t,e`INSERT INTO ${e.identifier(t)} (${te(w)}) VALUES (${re($)})`),E&&ke.set(_,t),await ce(t,void 0,y),await Z(t,_,void 0,y),await le(t,_,y),await X(t,_,"insert",y),P(t,"after","insert")&&await j("after","insert",{doc:y,id:_,op:"insert",table:t}),_},normalizeId(t,n){return Kt(d,t,n)},async patch(t,n,o){Ze("patch",n);const r=await se(t,o);if(!r)throw new g("INTERNAL",`document not found: ${t}`);const a=d.tables[r];if(!a)throw new g("INTERNAL",`document not found: ${t}`);const _=await me(r,t),E=ie(a,_);if(!E)throw new g("INTERNAL",`document not found: ${t}`);const f={...E,...n,_id:t};ft(a,n,f,Y),De(a,f,!0),P(r,"before","update")&&await j("before","update",{doc:{...f},id:t,op:"update",previous:E,table:r}),await Re(r),await Te(r);const y=Object.keys(a.shape),w=e.join(y.map($=>e`${e.identifier($)} = ${H(f[$]??null)}`),e`, `);await Se(r,"UPDATE",w,_),await ce(r,E,f),await Z(r,t,E,f),await le(r,t,f,E),await X(r,t,"update",f),P(r,"after","update")&&await j("after","update",{doc:f,id:t,op:"update",previous:E,table:r})},async restore(t,n){const o=await se(t,n);if(!o)throw new g("INTERNAL",`document not found: ${t}`);const r=d.tables[o],a=r?.softDeleteMode?.field;if(!r||!a)throw new g("INTERNAL",`ctx.db.restore: table "${o}" is not a .softDelete() table`);const _=await me(o,t),E=_?.[a]!==null&&_?.[a]!==void 0;if(await U.patch(t,{[a]:null},n),E){const f=ie(r,_);f!==null&&await Z(o,t,void 0,{...f,[a]:null})}},query(t){const n=d.tables[t];if(!n)throw new g("INTERNAL",`unknown table: ${t}`);const o="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",r=[],a=f=>r.every(y=>y(f)),_=async(f,y)=>{await W();const w=r.length>0,$=await Dt(i,c,n,t,f,qt(w?void 0:y));if(!w)return y===void 0&&Ot($),$;const p=$.filter(S=>a(S));return y===void 0?p:p.slice(0,y)},E=f=>{const y={async*[Symbol.asyncIterator](){if(!f)throw new g("INTERNAL",o);yield*await _(f,void 0)},async collect(){if(!f)throw new g("INTERNAL",o);return _(f,void 0)},async collectWithScores(){throw new g("GLOBAL_SEARCH_SCORES_UNSUPPORTED",`collectWithScores() is not supported on \`.global()\` tables (table "${t}") — relevance scores are not yet surfaced on this backend; use .collect() instead`)},filter(w){return r.push(w),y},async first(){if(!f)throw new g("INTERNAL",o);return(await _(f,1))[0]??null},order(){return y},async paginate(w){if(!f)throw new g("INTERNAL",o);const $=Nt(w);return Mt(await _(f,Ft($)),$)},async take(w){if(!f)throw new g("INTERNAL",o);return _(f,w)},async unique(){if(!f)throw new g("INTERNAL",o);const w=await _(f,2);if(w.length>1)throw new dn(`unique() on table "${t}" matched ${String(w.length)} documents; expected at most one`);return w[0]??null},withGeoIndex(){throw new g("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new g("INTERNAL",o)},withSearchIndex(w,$){const p=(n.searchIndexes??[]).find(T=>T.name===w);if(!p)throw new g("INTERNAL",`unknown search index "${w}" on table "${t}"`);const S={definition:p,field:p.field,filters:[],hasQuery:!1,indexName:w,query:""};if($(Lt(S,t,kt(p.language))),!S.hasQuery)throw new g("INTERNAL",`search index "${w}" on table "${t}" requires a .search(field, query) call`);return E(S)}};return y};return E(void 0)},async rank(t,n,o){const r=d.tables[t];if(!r)throw new g("INTERNAL",`unknown table: ${t}`);const a=r.rankIndexes?.find(D=>D.name===n);if(!a)throw new g("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(o.restrictsCounts)throw new nt(t);if(await W(),!await Me(t,a))return null;const E=typeof o.row=="string"?o.row:o.row._id;if(!E)return null;const f=ne(t,a.name),y=a.sortBy.map((D,K)=>Q(K)),w=te(["__partition__",...y]),p=(await C(i,c,e`SELECT ${w} FROM ${e.identifier(f)} WHERE ${e.identifier("__id__")} = ${E}`))[0];if(!p)return null;const S=p.__partition__,T=O(o.baseWhere,o.where);et(T,d,t,"rank");const I=tt(a,T);if(I&&Ie(a.partitionBy??[],I)!==S)return null;const k=gn(c.name,a,y,p,E),B=await C(i,c,e`SELECT COUNT(*) AS c FROM ${e.identifier(f)} WHERE ${e.identifier("__partition__")} = ${S}${k?e` AND (${k})`:e``}`),N=await C(i,c,e`SELECT COUNT(*) AS c FROM ${e.identifier(f)} WHERE ${e.identifier("__partition__")} = ${S}`);return{position:Number(B[0]?.c??0)+1,total:Number(N[0]?.c??0)}},async rankPage(t,n,o={}){et(O(o.baseWhere,o.where),d,t,"rankPage");const r=d.tables[t];if(!r)throw new g("INTERNAL",`unknown table: ${t}`);const a=r.rankIndexes?.find(q=>q.name===n);if(!a)throw new g("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await W(),!await Me(t,a))return{continueCursor:null,isDone:!0,page:[]};const E=ne(t,a.name),f=a.sortBy.map((q,ue)=>Q(ue)),y=Math.max(1,Math.min(1e3,Math.floor(o.take??100))),w=O(o.baseWhere,o.where),$=tt(a,w),p=bn(a,f),S=e.join(p.map(q=>e`${e.identifier(q.column)} ${e.raw(q.direction==="desc"?"DESC":"ASC")}`),e`, `),T=[];typeof o.partitionKey=="string"?T.push(e`${e.identifier("__partition__")} = ${o.partitionKey}`):$&&T.push(e`${e.identifier("__partition__")} = ${Ie(a.partitionBy??[],$)}`);const I=jt(o);if(I!==void 0){const q=vn(c.name,p,I);q!==void 0&&T.push(q)}const k=te([Ee,"__partition__",...f]);let B=e`SELECT ${k} FROM ${e.identifier(E)}`;T.length>0&&(B=e`${B} WHERE ${e.join(T,e` AND `)}`),B=e`${B} ORDER BY ${S} LIMIT ${e.raw(String(y+1))}`;const N=await C(i,c,B),D=N.length>y,K=D?N.slice(0,y):N,ve=K.map(q=>q[Ee]),be=await Cn(i,c,r,t,ve);let Ce=null;const ee=K.at(-1);if(D&&ee!==void 0){const q=[ee.__partition__,...f.map(ue=>ee[ue]),ee[Ee]];Ce=In(q)}return{continueCursor:Ce,isDone:!D,page:be}},async replace(t,n,o,r){Ze("replace",n);const a=await se(t,o);if(!a)throw new g("INTERNAL",`document not found: ${t}`);const _=d.tables[a];if(!_)throw new g("INTERNAL",`document not found: ${t}`);const E=await me(a,t);if(E===void 0)throw new g("INTERNAL",`document not found: ${t}`);const y=Pt(d,a,"update")||(_.aggregateIndexes??[]).length>0||(_.rankIndexes??[]).length>0?ie(_,E)??void 0:void 0,w=r?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:L(),$={...n,_creationTime:w,_id:t};ft(_,n,$,Y),De(_,$),P(a,"before","update")&&await j("before","update",{doc:{...$},id:t,op:"update",previous:y,table:a}),await Re(a),await Te(a);const p=Object.keys(_.shape),S=e.join([e`${e.identifier("_creationTime")} = ${w}`,...p.map(T=>e`${e.identifier(T)} = ${H($[T]??null)}`)],e`, `);await Se(a,"UPDATE",S,E),await ce(a,y,$),await Z(a,t,y,$),await le(a,t,$,y),await X(a,t,"update",$),P(a,"after","update")&&await j("after","update",{doc:$,id:t,op:"update",previous:y,table:a})}};return He={db:U,scheduler:yt},U};export{ii as backfillSqlSearchIndexes,ei as createSqlCtxDb,ri as decodeGlobalRow,Hn as readSqlCdcChangedTables,Zn as readSqlCdcChanges,Et as readSqlCdcFloor,Mn as runSqlAggregateMigrations,Wn as runSqlCdcMigration,Nn as runSqlGlobalTableMigrations,On as runSqlRankMigrations,At as runSqlSearchMigrations,Pn as sweepSqlCdcRetention};
@@ -1 +1 @@
1
- import{sql as t}from"drizzle-orm";import{migrateSearchState as Z,readSearchBackfillState as P,writeSearchBackfillState as I}from"./SEARCH_STATE_TABLE-CbcRI0sw.mjs";import{LunoraError as h}from"@lunora/errors";import{unionAll as ee}from"@lunora/shard-engine";import{queryRun as S,decodeRows as z,queryAll as D,queryBatch as ne,createIndexIfNotExists as U,columnRefSql as F,serializeColumnValue as te,forEachRowPaged as ie}from"./decodeGlobalRow-_JxajZP5.mjs";const oe=["de","en","es","fr","it","nl","none","pt"],re=e=>oe.includes(e),se="a an and are as at be but by for if in into is it no not of on or such that the their then there these they this to was will with",ae="aber als am an auch auf aus bei bin bis bist da dass der den des dem die das denn dir du ein eine für hat ich im in ist mit nicht noch nur oder sich sie sind über und von vor war wie wir zu zum zur",ce="a al como con de del el en es la las lo los mas no o para pero por que se su sus un una uno y ya",ue="au aux avec ce ces dans de des du elle en et eux il je la le les leur lui ma mais me même mes moi mon ne nos notre nous on ou par pas pour qu que qui sa se ses son sur ta te tes toi ton tu un une vos votre vous y",fe="a ai al alla anche che chi ci coi col come con da dal degli dei del della di do e ed gli ha hai hanno i il in la le lo ma mi ne nei nel non o per più quale quanto se si sono su sul tra un una uno vi",de="aan al als bij dan dat de der deze die dit door een en er het hij ij in is je kan me men met mij na naar niet nog nu of om ons ook op over te tot uit van voor was wat we wij zij zijn zo",le="a ao aos as até com como da das de do dos e em entre era essa esse esta este eu foi há isso já mais mas me mesmo meu na nas no nos num numa o os ou para pela pelo por qual que quem se sem seu só sua também te tem um uma você",me=/[\u0300-\u036F]/gu,$e=/[\u0080-\u{10FFFF}]/u,he=/[\p{L}\p{N}]+/gu,W=e=>$e.test(e)?e.normalize("NFD").replaceAll(me,"").normalize("NFC").toLowerCase():e.toLowerCase(),g=e=>new Set(W(e).split(" ")),we={de:g(ae),en:g(se),es:g(ce),fr:g(ue),it:g(fe),nl:g(de),none:new Set,pt:g(le)},Se=2,pe=256,M=new Map,y=e=>{const n=e!==void 0&&re(e)?e:"none",i=M.get(n);if(i)return i;const o=we[n],r=a=>{const c=(W(a).match(he)??[]).filter(u=>u.length<=pe);return o.size===0?c:c.filter(u=>!o.has(u))},s={document:r,profile:`${n}-v${String(Se)}`,query:a=>{const c=r(a);return c.filter((u,f)=>c.lastIndexOf(u)===f)}};return M.set(n,s),s},Ee=(e,n)=>e.profile!==n?{cursor:void 0,finished:!1,wipe:e.cursor!==void 0||e.done}:{cursor:e.cursor,finished:e.done,wipe:!1},ge=e=>{const n=atob(e),i=Uint8Array.from(n,o=>o.codePointAt(0)??0);return new TextDecoder().decode(i)},_e=()=>new h("BAD_REQUEST","invalid cursor"),j=16,B=8,w=1024,v=(e,n)=>n.query(e),ye=(e,n)=>{if(!n)return{exact:!0,lower:e,upper:e};const i=[...e].at(-1)??"",o=(i.codePointAt(0)??0)+1;if(o>=55296&&o<=57343||o>1114111)return{exact:!0,lower:e,upper:e};const r=e.slice(0,e.length-i.length);return{exact:!1,lower:e,upper:r+String.fromCodePoint(o)}},ze=(e,n,i)=>{const o={eq:(r,s)=>{if(!e.definition.filterFields?.includes(r))throw new h("INTERNAL",`field "${r}" is not a filter field of search index "${e.indexName}" on table "${n}"`);if(e.filters.length>=B)throw new h("BAD_REQUEST",`search index "${e.indexName}" on table "${n}": at most ${String(B)} .eq() filters are supported per search query`);return e.filters.push({field:r,value:s}),o},search:(r,s)=>{const a=e;if(r!==a.definition.field)throw new h("INTERNAL",`search index "${a.indexName}" on table "${n}" indexes "${a.definition.field}", not "${r}"`);const c=v(s,i).length;if(c>j)throw new h("BAD_REQUEST",`search index "${a.indexName}" on table "${n}": at most ${String(j)} search terms are supported (got ${String(c)})`);return a.field=r,a.query=s,a.hasQuery=!0,o}};return o},We=e=>{if(e.length>w)throw new h("BAD_REQUEST",`more than ${String(w)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},Qe=e=>Math.min(e.offset+e.numItems+1,w),Te=e=>btoa(`search:${String(e)}`),Ne=e=>{let n;try{n=ge(e)}catch{return}if(!n.startsWith("search:"))return;const i=Number(n.slice(7));return Number.isInteger(i)&&i>=0?i:void 0},Ge=e=>{if(typeof e.endCursor=="string")throw new h("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(e.numItems))throw new h("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(e.numItems)}`);const n=Math.max(0,Math.floor(e.numItems)),i=e.cursor?Ne(e.cursor):0;if(i===void 0)throw _e();if(i+n>=w)throw new h("BAD_REQUEST",`search pagination reaches the ${String(w)}-document limit (offset ${String(i)} + ${String(n)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,w-i-1))} or fewer, or narrow the query or the filters instead`);return{numItems:n,offset:i}},Ve=(e,n)=>{const i=n.offset+n.numItems,o=n.numItems>0&&e.length>i;return{continueCursor:o?Te(i):null,isDone:!o,page:e.slice(n.offset,i)}},Je=e=>{if(e===void 0)return w+1;if(!Number.isFinite(e))return w;const n=Math.max(0,Math.floor(e));if(n>w)throw new h("BAD_REQUEST",`search returns at most ${String(w)} documents (asked for ${String(n)}) — narrow the query or paginate instead`);return n},Ie=(e,n)=>{if(!n.includes("."))return e[n];let i=e;for(const o of n.split(".")){if(i===null||typeof i!="object"||Array.isArray(i))return;i=i[o]}return i},R=(e,n)=>`${e}__fts_${n}`,ve="__text__",l="__id__",T="__token__",L="__n__",Re=1e3,Q=(e,n)=>n.document(e),C=(e,n)=>Ie(e,n),Ae=e=>typeof e=="string"?e:e==null?"":typeof e=="number"||typeof e=="bigint"||typeof e=="boolean"?String(e):JSON.stringify(e)??"",be=(e,n,i)=>e!==void 0&&n!==void 0&&C(e,i.field)===C(n,i.field),Le=(e,n)=>Q(Ae(C(e,n.field)),y(n.language)).slice(0,Re),O=(e,n)=>Le(e,n).join(" "),Ce=(e,n)=>{const i=new Map;for(const o of Q(e,n))i.set(o,(i.get(o)??0)+1);return i},A=async(e,n,i,o)=>{await S(e,n,t`DELETE FROM ${t.identifier(i)} WHERE ${t.identifier(l)} = ${o}`)},b=(e,n)=>e.name==="mysql"?t`${t.identifier(n)}(191)`:e.textPatternOperatorClass===void 0?t`${t.identifier(n)}`:t`${t.identifier(n)} ${t.raw(e.textPatternOperatorClass)}`,k=50,De=(e,n)=>n?t`${t.identifier(T)} LIKE ${`${e}%`}`:t`${t.identifier(T)} = ${e}`,G=(e,n)=>{const i=n.filters.map(o=>t`m.${F(o.field)} = ${te(o.value)}`);return e.softDeleteMode&&i.push(t`m.${F(e.softDeleteMode.field)} IS NULL`),i},V=async(e,n,i,o,r,s,a)=>{const c=G(i,r);let u=t`SELECT m.* FROM (${a}) s JOIN ${t.identifier(o)} m ON m.${t.identifier("id")} = s.${t.identifier(l)}`;return c.length>0&&(u=t`${u} WHERE ${t.join(c,t` AND `)}`),u=t`${u} ORDER BY s.${t.identifier("__score__")} DESC, m.${t.identifier("_creationTime")} DESC, m.${t.identifier("id")} ASC LIMIT ${t.raw(String(s))}`,z(i,await D(e,n,u))},Oe=async(e,n,i,o,r,s)=>{const a=v(r.query,y(r.definition.language));if(a.length===0)return[];const c=R(o,r.indexName),u=a.length-1,f=a.map((d,_)=>De(d,_===u)),m=t.join(f,t` OR `),$=f.map(d=>t`SUM(CASE WHEN ${d} THEN ${t.identifier(L)} ELSE 0 END)`),E=t.join($.map(d=>t`${d} > 0`),t` AND `),p=t`SELECT ${t.identifier(l)}, ${t.join($,t` + `)} AS ${t.identifier("__score__")} FROM ${t.identifier(c)} WHERE ${m} GROUP BY ${t.identifier(l)} HAVING ${E}`;return V(e,n,i,o,r,s,p)},qe=async(e,n,i,o,r,s)=>{const a=v(r.query,y(r.definition.language));if(a.length===0)return[];const c=R(o,r.indexName),u=`${c}__vocab`,f=a.length-1,m=a.map((p,d)=>{const _=ye(p,d===f),K=_.exact?t`${t.identifier("term")} = ${_.lower}`:t`${t.identifier("term")} >= ${_.lower} AND ${t.identifier("term")} < ${_.upper}`;return t`SELECT ${t.identifier("doc")}, ${t.raw(String(d))} AS ${t.identifier("__term__")}, COUNT(*) AS ${t.identifier("__n__")} FROM ${t.identifier(u)} WHERE ${K} GROUP BY ${t.identifier("doc")}`}),$=a.map((p,d)=>t`SUM(CASE WHEN u.${t.identifier("__term__")} = ${t.raw(String(d))} THEN u.${t.identifier("__n__")} ELSE 0 END)`),E=t`SELECT f.${t.identifier(l)} AS ${t.identifier(l)}, ${t.join($,t` + `)} AS ${t.identifier("__score__")} FROM (${ee(m)}) u JOIN ${t.identifier(c)} f ON f.rowid = u.${t.identifier("doc")} GROUP BY f.${t.identifier(l)} HAVING ${t.join($.map(p=>t`${p} > 0`),t` AND `)}`;return V(e,n,i,o,r,s,E)},xe=async(e,n,i,o,r,s)=>{const a=n.nativeTextSearch,c=v(r.query,y(r.definition.language));if(!a||c.length===0)return[];const u=R(o,r.indexName),f=[a.matches(u,c),...G(i,r)],m=t`SELECT m.* FROM ${t.identifier(u)} JOIN ${t.identifier(o)} m ON m.${t.identifier("id")} = ${t.identifier(u)}.${t.identifier(l)} WHERE ${t.join(f,t` AND `)} ORDER BY ${a.rank(u,c)} DESC, m.${t.identifier("_creationTime")} DESC, m.${t.identifier("id")} ASC LIMIT ${t.raw(String(s))}`;return z(i,await D(e,n,m))},Ue={ensureCompanion:async(e,n,i)=>{const{integer:o,key:r}=n.companionTypes;await S(e,n,t`CREATE TABLE IF NOT EXISTS ${t.identifier(i)} (${t.identifier(T)} ${t.raw(r)} NOT NULL, ${t.identifier(l)} ${t.raw(r)} NOT NULL, ${t.identifier(L)} ${t.raw(o)} NOT NULL)`),await U(e,n,{columns:t`${b(n,T)}, ${b(n,l)}`,name:`${i}__btree`,table:i,unique:!1}),await U(e,n,{columns:b(n,l),name:`${i}__by_id`,table:i,unique:!1})},indexDocument:async(e,n,i,o,r,s)=>{await A(e,n,i,o);const a=[...Ce(O(r,s),y(s.language))],c=t.join([T,l,L].map(f=>t.identifier(f)),t`, `),u=[];for(let f=0;f<a.length;f+=k){const m=t.join(a.slice(f,f+k).map(([$,E])=>t`(${$}, ${o}, ${E})`),t`, `);u.push(t`INSERT INTO ${t.identifier(i)} (${c}) VALUES ${m}`)}await ne(e,n,u)},name:"inverted",runSearch:Oe},Fe={ensureCompanion:async(e,n,i)=>{await S(e,n,t`CREATE VIRTUAL TABLE IF NOT EXISTS ${t.identifier(i)} USING fts5(${t.identifier(ve)}, ${t.identifier(l)} UNINDEXED)`),await S(e,n,t`CREATE VIRTUAL TABLE IF NOT EXISTS ${t.identifier(`${i}__vocab`)} USING fts5vocab(${t.identifier(i)}, ${t.raw("instance")})`)},indexDocument:async(e,n,i,o,r,s)=>{await A(e,n,i,o),await S(e,n,t`INSERT INTO ${t.identifier(i)} (${t.identifier("__text__")}, ${t.identifier(l)}) VALUES (${O(r,s)}, ${o})`)},name:"fts5",runSearch:qe},Me={ensureCompanion:async(e,n,i)=>{const o=n.nativeTextSearch;if(o){await S(e,n,o.createCompanion(i,n.companionTypes.key));for(const r of o.createIndexes(i))await S(e,n,r)}},indexDocument:async(e,n,i,o,r,s)=>{const a=n.nativeTextSearch;a&&(await A(e,n,i,o),await S(e,n,a.indexDocument(i,o,O(r,s))))},name:"native",runSearch:xe},N=(e,n)=>e.strategy==="native"&&n.nativeTextSearch!==void 0?Me:n.supportsFts5?Fe:Ue,J=(e,n)=>`${y(e.language).profile}/${N(e,n).name}`,q=function*(e){for(const[n,i]of Object.entries(e.tables)){const o=i.searchIndexes;if(!(i.shardMode!==void 0&&i.shardMode.kind!=="global"||!o))for(const r of o)yield[n,i,r]}},x=(e,n)=>R(e,n.name),Xe=async(e,n,i,o,r,s)=>N(r.definition,n).runSearch(e,n,i,o,r,s),H=200,X=async(e,n,i,o,r)=>{const s=x(o,r),a=N(r,n),c=J(r,n),u=Ee(await P(e,n,s),c);if(u.finished)return!0;if(u.wipe&&(await S(e,n,t`DELETE FROM ${t.identifier(s)}`),await I(e,n,s,void 0,!1,c)),(await D(e,n,n.tableExists(o))).length===0)return await I(e,n,s,void 0,!0,c),!0;let m=0,$=u.cursor;await ie(e,n,i,o,async p=>{m+=1;const d=p._id;typeof d=="string"&&($=d,await a.indexDocument(e,n,s,d,p,r))},{after:u.cursor,limit:H});const E=m<H;return await I(e,n,s,$,E,c),E},Y=async(e,n,i)=>{await Z(e,i);for(const[o,,r]of q(n)){const s=x(o,r),a=J(r,i),c=await P(e,i,s);c.profile!==void 0&&c.profile!==a&&(await S(e,i,t`DROP TABLE IF EXISTS ${t.identifier(s)}`),await I(e,i,s,void 0,!1,a)),await N(r,i).ensureCompanion(e,i,s)}},Ye=async(e,n,i)=>{await Y(e,n,i);for(const[o,r,s]of q(n))s.staged||await X(e,i,r,o,s)},Ke=async(e,n,i)=>{await Y(e,n,i);for(const[o,r,s]of q(n)){let a=!1;for(;!a;)a=await X(e,i,r,o,s)}},Ze=e=>{const{dialect:n,exec:i,schema:o}=e;return async(r,s,a,c)=>{const u=o.tables[r]?.searchIndexes;if(!(!u||u.length===0))for(const f of u){if(be(c,a,f))continue;const m=x(r,f);if(a){await N(f,n).indexDocument(i,n,m,s,a,f);continue}await A(i,n,m,s)}}};export{ze as A,Ge as C,Ve as R,Je as T,Xe as a,Qe as b,Ze as c,Ke as d,y as q,Ye as r,We as x};
1
+ import{sql as t}from"drizzle-orm";import{migrateSearchState as Z,readSearchBackfillState as P,writeSearchBackfillState as I}from"./SEARCH_STATE_TABLE-B5a5xBwB.mjs";import{LunoraError as h}from"@lunora/errors";import{unionAll as ee}from"@lunora/shard-engine";import{queryRun as S,decodeRows as z,queryAll as D,queryBatch as ne,createIndexIfNotExists as U,columnRefSql as F,serializeColumnValue as te,forEachRowPaged as ie}from"./decodeGlobalRow-C8O2hy0d.mjs";const oe=["de","en","es","fr","it","nl","none","pt"],re=e=>oe.includes(e),se="a an and are as at be but by for if in into is it no not of on or such that the their then there these they this to was will with",ae="aber als am an auch auf aus bei bin bis bist da dass der den des dem die das denn dir du ein eine für hat ich im in ist mit nicht noch nur oder sich sie sind über und von vor war wie wir zu zum zur",ce="a al como con de del el en es la las lo los mas no o para pero por que se su sus un una uno y ya",ue="au aux avec ce ces dans de des du elle en et eux il je la le les leur lui ma mais me même mes moi mon ne nos notre nous on ou par pas pour qu que qui sa se ses son sur ta te tes toi ton tu un une vos votre vous y",fe="a ai al alla anche che chi ci coi col come con da dal degli dei del della di do e ed gli ha hai hanno i il in la le lo ma mi ne nei nel non o per più quale quanto se si sono su sul tra un una uno vi",de="aan al als bij dan dat de der deze die dit door een en er het hij ij in is je kan me men met mij na naar niet nog nu of om ons ook op over te tot uit van voor was wat we wij zij zijn zo",le="a ao aos as até com como da das de do dos e em entre era essa esse esta este eu foi há isso já mais mas me mesmo meu na nas no nos num numa o os ou para pela pelo por qual que quem se sem seu só sua também te tem um uma você",me=/[\u0300-\u036F]/gu,$e=/[\u0080-\u{10FFFF}]/u,he=/[\p{L}\p{N}]+/gu,W=e=>$e.test(e)?e.normalize("NFD").replaceAll(me,"").normalize("NFC").toLowerCase():e.toLowerCase(),g=e=>new Set(W(e).split(" ")),we={de:g(ae),en:g(se),es:g(ce),fr:g(ue),it:g(fe),nl:g(de),none:new Set,pt:g(le)},Se=2,pe=256,M=new Map,y=e=>{const n=e!==void 0&&re(e)?e:"none",i=M.get(n);if(i)return i;const o=we[n],r=a=>{const c=(W(a).match(he)??[]).filter(u=>u.length<=pe);return o.size===0?c:c.filter(u=>!o.has(u))},s={document:r,profile:`${n}-v${String(Se)}`,query:a=>{const c=r(a);return c.filter((u,f)=>c.lastIndexOf(u)===f)}};return M.set(n,s),s},Ee=(e,n)=>e.profile!==n?{cursor:void 0,finished:!1,wipe:e.cursor!==void 0||e.done}:{cursor:e.cursor,finished:e.done,wipe:!1},ge=e=>{const n=atob(e),i=Uint8Array.from(n,o=>o.codePointAt(0)??0);return new TextDecoder().decode(i)},_e=()=>new h("BAD_REQUEST","invalid cursor"),j=16,B=8,w=1024,v=(e,n)=>n.query(e),ye=(e,n)=>{if(!n)return{exact:!0,lower:e,upper:e};const i=[...e].at(-1)??"",o=(i.codePointAt(0)??0)+1;if(o>=55296&&o<=57343||o>1114111)return{exact:!0,lower:e,upper:e};const r=e.slice(0,e.length-i.length);return{exact:!1,lower:e,upper:r+String.fromCodePoint(o)}},ze=(e,n,i)=>{const o={eq:(r,s)=>{if(!e.definition.filterFields?.includes(r))throw new h("INTERNAL",`field "${r}" is not a filter field of search index "${e.indexName}" on table "${n}"`);if(e.filters.length>=B)throw new h("BAD_REQUEST",`search index "${e.indexName}" on table "${n}": at most ${String(B)} .eq() filters are supported per search query`);return e.filters.push({field:r,value:s}),o},search:(r,s)=>{const a=e;if(r!==a.definition.field)throw new h("INTERNAL",`search index "${a.indexName}" on table "${n}" indexes "${a.definition.field}", not "${r}"`);const c=v(s,i).length;if(c>j)throw new h("BAD_REQUEST",`search index "${a.indexName}" on table "${n}": at most ${String(j)} search terms are supported (got ${String(c)})`);return a.field=r,a.query=s,a.hasQuery=!0,o}};return o},We=e=>{if(e.length>w)throw new h("BAD_REQUEST",`more than ${String(w)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},Qe=e=>Math.min(e.offset+e.numItems+1,w),Te=e=>btoa(`search:${String(e)}`),Ne=e=>{let n;try{n=ge(e)}catch{return}if(!n.startsWith("search:"))return;const i=Number(n.slice(7));return Number.isInteger(i)&&i>=0?i:void 0},Ge=e=>{if(typeof e.endCursor=="string")throw new h("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(e.numItems))throw new h("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(e.numItems)}`);const n=Math.max(0,Math.floor(e.numItems)),i=e.cursor?Ne(e.cursor):0;if(i===void 0)throw _e();if(i+n>=w)throw new h("BAD_REQUEST",`search pagination reaches the ${String(w)}-document limit (offset ${String(i)} + ${String(n)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,w-i-1))} or fewer, or narrow the query or the filters instead`);return{numItems:n,offset:i}},Ve=(e,n)=>{const i=n.offset+n.numItems,o=n.numItems>0&&e.length>i;return{continueCursor:o?Te(i):null,isDone:!o,page:e.slice(n.offset,i)}},Je=e=>{if(e===void 0)return w+1;if(!Number.isFinite(e))return w;const n=Math.max(0,Math.floor(e));if(n>w)throw new h("BAD_REQUEST",`search returns at most ${String(w)} documents (asked for ${String(n)}) — narrow the query or paginate instead`);return n},Ie=(e,n)=>{if(!n.includes("."))return e[n];let i=e;for(const o of n.split(".")){if(i===null||typeof i!="object"||Array.isArray(i))return;i=i[o]}return i},R=(e,n)=>`${e}__fts_${n}`,ve="__text__",l="__id__",T="__token__",L="__n__",Re=1e3,Q=(e,n)=>n.document(e),C=(e,n)=>Ie(e,n),Ae=e=>typeof e=="string"?e:e==null?"":typeof e=="number"||typeof e=="bigint"||typeof e=="boolean"?String(e):JSON.stringify(e)??"",be=(e,n,i)=>e!==void 0&&n!==void 0&&C(e,i.field)===C(n,i.field),Le=(e,n)=>Q(Ae(C(e,n.field)),y(n.language)).slice(0,Re),O=(e,n)=>Le(e,n).join(" "),Ce=(e,n)=>{const i=new Map;for(const o of Q(e,n))i.set(o,(i.get(o)??0)+1);return i},A=async(e,n,i,o)=>{await S(e,n,t`DELETE FROM ${t.identifier(i)} WHERE ${t.identifier(l)} = ${o}`)},b=(e,n)=>e.name==="mysql"?t`${t.identifier(n)}(191)`:e.textPatternOperatorClass===void 0?t`${t.identifier(n)}`:t`${t.identifier(n)} ${t.raw(e.textPatternOperatorClass)}`,k=50,De=(e,n)=>n?t`${t.identifier(T)} LIKE ${`${e}%`}`:t`${t.identifier(T)} = ${e}`,G=(e,n)=>{const i=n.filters.map(o=>t`m.${F(o.field)} = ${te(o.value)}`);return e.softDeleteMode&&i.push(t`m.${F(e.softDeleteMode.field)} IS NULL`),i},V=async(e,n,i,o,r,s,a)=>{const c=G(i,r);let u=t`SELECT m.* FROM (${a}) s JOIN ${t.identifier(o)} m ON m.${t.identifier("id")} = s.${t.identifier(l)}`;return c.length>0&&(u=t`${u} WHERE ${t.join(c,t` AND `)}`),u=t`${u} ORDER BY s.${t.identifier("__score__")} DESC, m.${t.identifier("_creationTime")} DESC, m.${t.identifier("id")} ASC LIMIT ${t.raw(String(s))}`,z(i,await D(e,n,u))},Oe=async(e,n,i,o,r,s)=>{const a=v(r.query,y(r.definition.language));if(a.length===0)return[];const c=R(o,r.indexName),u=a.length-1,f=a.map((d,_)=>De(d,_===u)),m=t.join(f,t` OR `),$=f.map(d=>t`SUM(CASE WHEN ${d} THEN ${t.identifier(L)} ELSE 0 END)`),E=t.join($.map(d=>t`${d} > 0`),t` AND `),p=t`SELECT ${t.identifier(l)}, ${t.join($,t` + `)} AS ${t.identifier("__score__")} FROM ${t.identifier(c)} WHERE ${m} GROUP BY ${t.identifier(l)} HAVING ${E}`;return V(e,n,i,o,r,s,p)},qe=async(e,n,i,o,r,s)=>{const a=v(r.query,y(r.definition.language));if(a.length===0)return[];const c=R(o,r.indexName),u=`${c}__vocab`,f=a.length-1,m=a.map((p,d)=>{const _=ye(p,d===f),K=_.exact?t`${t.identifier("term")} = ${_.lower}`:t`${t.identifier("term")} >= ${_.lower} AND ${t.identifier("term")} < ${_.upper}`;return t`SELECT ${t.identifier("doc")}, ${t.raw(String(d))} AS ${t.identifier("__term__")}, COUNT(*) AS ${t.identifier("__n__")} FROM ${t.identifier(u)} WHERE ${K} GROUP BY ${t.identifier("doc")}`}),$=a.map((p,d)=>t`SUM(CASE WHEN u.${t.identifier("__term__")} = ${t.raw(String(d))} THEN u.${t.identifier("__n__")} ELSE 0 END)`),E=t`SELECT f.${t.identifier(l)} AS ${t.identifier(l)}, ${t.join($,t` + `)} AS ${t.identifier("__score__")} FROM (${ee(m)}) u JOIN ${t.identifier(c)} f ON f.rowid = u.${t.identifier("doc")} GROUP BY f.${t.identifier(l)} HAVING ${t.join($.map(p=>t`${p} > 0`),t` AND `)}`;return V(e,n,i,o,r,s,E)},xe=async(e,n,i,o,r,s)=>{const a=n.nativeTextSearch,c=v(r.query,y(r.definition.language));if(!a||c.length===0)return[];const u=R(o,r.indexName),f=[a.matches(u,c),...G(i,r)],m=t`SELECT m.* FROM ${t.identifier(u)} JOIN ${t.identifier(o)} m ON m.${t.identifier("id")} = ${t.identifier(u)}.${t.identifier(l)} WHERE ${t.join(f,t` AND `)} ORDER BY ${a.rank(u,c)} DESC, m.${t.identifier("_creationTime")} DESC, m.${t.identifier("id")} ASC LIMIT ${t.raw(String(s))}`;return z(i,await D(e,n,m))},Ue={ensureCompanion:async(e,n,i)=>{const{integer:o,key:r}=n.companionTypes;await S(e,n,t`CREATE TABLE IF NOT EXISTS ${t.identifier(i)} (${t.identifier(T)} ${t.raw(r)} NOT NULL, ${t.identifier(l)} ${t.raw(r)} NOT NULL, ${t.identifier(L)} ${t.raw(o)} NOT NULL)`),await U(e,n,{columns:t`${b(n,T)}, ${b(n,l)}`,name:`${i}__btree`,table:i,unique:!1}),await U(e,n,{columns:b(n,l),name:`${i}__by_id`,table:i,unique:!1})},indexDocument:async(e,n,i,o,r,s)=>{await A(e,n,i,o);const a=[...Ce(O(r,s),y(s.language))],c=t.join([T,l,L].map(f=>t.identifier(f)),t`, `),u=[];for(let f=0;f<a.length;f+=k){const m=t.join(a.slice(f,f+k).map(([$,E])=>t`(${$}, ${o}, ${E})`),t`, `);u.push(t`INSERT INTO ${t.identifier(i)} (${c}) VALUES ${m}`)}await ne(e,n,u)},name:"inverted",runSearch:Oe},Fe={ensureCompanion:async(e,n,i)=>{await S(e,n,t`CREATE VIRTUAL TABLE IF NOT EXISTS ${t.identifier(i)} USING fts5(${t.identifier(ve)}, ${t.identifier(l)} UNINDEXED)`),await S(e,n,t`CREATE VIRTUAL TABLE IF NOT EXISTS ${t.identifier(`${i}__vocab`)} USING fts5vocab(${t.identifier(i)}, ${t.raw("instance")})`)},indexDocument:async(e,n,i,o,r,s)=>{await A(e,n,i,o),await S(e,n,t`INSERT INTO ${t.identifier(i)} (${t.identifier("__text__")}, ${t.identifier(l)}) VALUES (${O(r,s)}, ${o})`)},name:"fts5",runSearch:qe},Me={ensureCompanion:async(e,n,i)=>{const o=n.nativeTextSearch;if(o){await S(e,n,o.createCompanion(i,n.companionTypes.key));for(const r of o.createIndexes(i))await S(e,n,r)}},indexDocument:async(e,n,i,o,r,s)=>{const a=n.nativeTextSearch;a&&(await A(e,n,i,o),await S(e,n,a.indexDocument(i,o,O(r,s))))},name:"native",runSearch:xe},N=(e,n)=>e.strategy==="native"&&n.nativeTextSearch!==void 0?Me:n.supportsFts5?Fe:Ue,J=(e,n)=>`${y(e.language).profile}/${N(e,n).name}`,q=function*(e){for(const[n,i]of Object.entries(e.tables)){const o=i.searchIndexes;if(!(i.shardMode!==void 0&&i.shardMode.kind!=="global"||!o))for(const r of o)yield[n,i,r]}},x=(e,n)=>R(e,n.name),Xe=async(e,n,i,o,r,s)=>N(r.definition,n).runSearch(e,n,i,o,r,s),H=200,X=async(e,n,i,o,r)=>{const s=x(o,r),a=N(r,n),c=J(r,n),u=Ee(await P(e,n,s),c);if(u.finished)return!0;if(u.wipe&&(await S(e,n,t`DELETE FROM ${t.identifier(s)}`),await I(e,n,s,void 0,!1,c)),(await D(e,n,n.tableExists(o))).length===0)return await I(e,n,s,void 0,!0,c),!0;let m=0,$=u.cursor;await ie(e,n,i,o,async p=>{m+=1;const d=p._id;typeof d=="string"&&($=d,await a.indexDocument(e,n,s,d,p,r))},{after:u.cursor,limit:H});const E=m<H;return await I(e,n,s,$,E,c),E},Y=async(e,n,i)=>{await Z(e,i);for(const[o,,r]of q(n)){const s=x(o,r),a=J(r,i),c=await P(e,i,s);c.profile!==void 0&&c.profile!==a&&(await S(e,i,t`DROP TABLE IF EXISTS ${t.identifier(s)}`),await I(e,i,s,void 0,!1,a)),await N(r,i).ensureCompanion(e,i,s)}},Ye=async(e,n,i)=>{await Y(e,n,i);for(const[o,r,s]of q(n))s.staged||await X(e,i,r,o,s)},Ke=async(e,n,i)=>{await Y(e,n,i);for(const[o,r,s]of q(n)){let a=!1;for(;!a;)a=await X(e,i,r,o,s)}},Ze=e=>{const{dialect:n,exec:i,schema:o}=e;return async(r,s,a,c)=>{const u=o.tables[r]?.searchIndexes;if(!(!u||u.length===0))for(const f of u){if(be(c,a,f))continue;const m=x(r,f);if(a){await N(f,n).indexDocument(i,n,m,s,a,f);continue}await A(i,n,m,s)}}};export{ze as A,Ge as C,Ve as R,Je as T,Xe as a,Qe as b,Ze as c,Ke as d,y as q,Ye as r,We as x};
@@ -0,0 +1 @@
1
+ import{c as a,e as o,a as t,s as i,t as c}from"./value-codec-CwTLrqfU.mjs";export{a as decodeBigint,o as effectiveColumnKind,t as sqliteDecode,i as sqliteEncode,c as tryJsonParse};
@@ -1 +1 @@
1
- import{renderSql as u}from"@lunora/shard-engine";import{sql as i}from"drizzle-orm";import{s as I,a as y,e as C}from"./value-codec-BvCc9FjU.mjs";const g=t=>t==="_id"||t==="id"?"id":t,A=t=>i`${i.identifier(g(t))}`,S=(t,n,e)=>{const{params:o,sql:r}=u(n.name,e);return t.all(r,o)},l=(t,n,e)=>{const{params:o,sql:r}=u(n.name,e);return t.run(r,o)},b=async(t,n,e)=>{if(e.length!==0){if(!t.batch){for(const o of e)await l(t,n,o);return}await t.batch(e.map(o=>u(n.name,o)))}},M=async(t,n,e)=>{const o=e.unique?i`UNIQUE `:i``;if(n.name==="mysql"){try{await l(t,n,i`CREATE ${o}INDEX ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)}catch(r){const a=r;if(a.errno!==1061&&a.code!=="ER_DUP_KEYNAME"&&a.code!==1061)throw r}return}await l(t,n,i`CREATE ${o}INDEX IF NOT EXISTS ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)},O=I,h=new WeakMap,T=t=>{let n=h.get(t);return n===void 0&&(n=Object.entries(t.shape).map(([e,o])=>[e,C(o)]),h.set(t,n)),n},p=(t,n)=>{const e={};for(const[o,r]of T(t)){const a=n[o];a!==void 0&&(e[o]=y(a,r))}return e._id=n.id,e._creationTime=n._creationTime,e},$=(t,n)=>n?p(t,n):null,D=(t,n)=>{const e=[];for(const o of n){const r=$(t,o);r&&e.push(r)}return e},w=500,K=async(t,n,e,o,r,a={})=>{let d=a.after,s=a.limit,f=!0;for(;f&&(s===void 0||s>0);){const m=s===void 0?w:Math.min(w,s),R=d===void 0?i``:i` WHERE ${i.identifier("id")} > ${d}`,c=await S(t,n,i`SELECT * FROM ${i.identifier(o)}${R} ORDER BY ${i.identifier("id")} ASC LIMIT ${i.raw(String(m))}`);for(const q of c){const E=$(e,q);E&&await r(E)}d=c.at(-1)?.id,f=c.length===m,s=s===void 0?void 0:s-c.length}};export{w as BACKFILL_BATCH_SIZE,A as columnRefSql,M as createIndexIfNotExists,p as decodeGlobalRow,$ as decodeRow,D as decodeRows,K as forEachRowPaged,g as physicalColumn,S as queryAll,b as queryBatch,l as queryRun,O as serializeColumnValue};
1
+ import{renderSql as u}from"@lunora/shard-engine";import{sql as i}from"drizzle-orm";import{s as I,a as y,e as C}from"./value-codec-CwTLrqfU.mjs";const g=t=>t==="_id"||t==="id"?"id":t,A=t=>i`${i.identifier(g(t))}`,S=(t,n,e)=>{const{params:o,sql:r}=u(n.name,e);return t.all(r,o)},l=(t,n,e)=>{const{params:o,sql:r}=u(n.name,e);return t.run(r,o)},b=async(t,n,e)=>{if(e.length!==0){if(!t.batch){for(const o of e)await l(t,n,o);return}await t.batch(e.map(o=>u(n.name,o)))}},M=async(t,n,e)=>{const o=e.unique?i`UNIQUE `:i``;if(n.name==="mysql"){try{await l(t,n,i`CREATE ${o}INDEX ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)}catch(r){const a=r;if(a.errno!==1061&&a.code!=="ER_DUP_KEYNAME"&&a.code!==1061)throw r}return}await l(t,n,i`CREATE ${o}INDEX IF NOT EXISTS ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)},O=I,h=new WeakMap,T=t=>{let n=h.get(t);return n===void 0&&(n=Object.entries(t.shape).map(([e,o])=>[e,C(o)]),h.set(t,n)),n},p=(t,n)=>{const e={};for(const[o,r]of T(t)){const a=n[o];a!==void 0&&(e[o]=y(a,r))}return e._id=n.id,e._creationTime=n._creationTime,e},$=(t,n)=>n?p(t,n):null,D=(t,n)=>{const e=[];for(const o of n){const r=$(t,o);r&&e.push(r)}return e},w=500,K=async(t,n,e,o,r,a={})=>{let d=a.after,s=a.limit,f=!0;for(;f&&(s===void 0||s>0);){const m=s===void 0?w:Math.min(w,s),R=d===void 0?i``:i` WHERE ${i.identifier("id")} > ${d}`,c=await S(t,n,i`SELECT * FROM ${i.identifier(o)}${R} ORDER BY ${i.identifier("id")} ASC LIMIT ${i.raw(String(m))}`);for(const q of c){const E=$(e,q);E&&await r(E)}d=c.at(-1)?.id,f=c.length===m,s=s===void 0?void 0:s-c.length}};export{w as BACKFILL_BATCH_SIZE,A as columnRefSql,M as createIndexIfNotExists,p as decodeGlobalRow,$ as decodeRow,D as decodeRows,K as forEachRowPaged,g as physicalColumn,S as queryAll,b as queryBatch,l as queryRun,O as serializeColumnValue};
@@ -0,0 +1 @@
1
+ import{LunoraError as B}from"@lunora/errors";const R=r=>{if(r.kind!=="optional")return r.kind;const t=r._meta?.inner;return t?R(t):r.kind},p=r=>{let t="";for(let o=0;o<r.length;o+=32768)t+=String.fromCharCode(...r.subarray(o,o+32768));return btoa(t)},I=r=>{const t=atob(r),s=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)s[o]=t.codePointAt(o)??0;return s},i="$lunora.wire$",g=64,O=1024,d="__proto__",h={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},j={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},U=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},E=(r,t=0)=>{if(t>g)return!0;if(r===null)return!1;const s=typeof r;if(s==="string"||s==="boolean")return!1;if(s==="number")return!Number.isFinite(r);if(s!=="object")return!0;if(Array.isArray(r))return r.length>0&&r[0]===i?!0:r.some(o=>o===void 0||E(o,t+1));if(!U(r)||Object.hasOwn(r,d))return!0;for(const o of Object.keys(r)){const c=r[o];if(c!==void 0&&E(c,t+1))return!0}return!1},a=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===void 0)return[i,"undefined"];if(r===null)return null;const s=typeof r;if(s==="bigint")return[i,"bigint",r.toString()];if(s==="number"){const e=r;return Number.isNaN(e)?[i,"nan"]:e===1/0?[i,"inf"]:e===-1/0?[i,"-inf"]:e}if(s!=="object")return r;if(r instanceof Date)return[i,"date",a(r.getTime(),t+1)];if(r instanceof Error){const e=r,n={};for(const u of Object.keys(e))e[u]!==void 0&&(n[u]=a(e[u],t+1));const f=[i,"error",e.name,e.message,n];return e.cause!==void 0&&f.push(a(e.cause,t+1)),f}if(r instanceof URL)return[i,"url",r.href];if(r instanceof Map)return[i,"map",[...r.entries()].map(([e,n])=>[a(e,t+1),a(n,t+1)])];if(r instanceof Set)return[i,"set",[...r].map(e=>a(e,t+1))];if(r instanceof ArrayBuffer)return[i,"bytes",p(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,n=e.constructor.name,f=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return n==="Uint8Array"?[i,"bytes",p(f)]:[i,"bytes",p(f),n]}if(Array.isArray(r)){const e=r.map(n=>a(n,t+1));return e.length>0&&e[0]===i?[i,"arr",e]:e}if(!U(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const o=r,c={};for(const e of Object.keys(o)){const n=o[e];if(n===void 0)continue;const f=a(n,t+1);e===d?Object.defineProperty(c,e,{configurable:!0,enumerable:!0,value:f,writable:!0}):c[e]=f}return c},y=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===i)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(e=>y(e,t+1));case"bigint":{const e=r[2];if(typeof e!="string"||e.length>O||!/^-?\d+$/.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${O} digits)`);return BigInt(e)}case"date":return new Date(y(r[2],t+1));case"map":{const e=r[2];return new Map(e.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[y(n[0],t+1),y(n[1],t+1)]}))}case"set":return new Set(r[2].map(e=>y(e,t+1)));case"url":return new URL(r[2]);case"error":{const e=r[2],n=r[3],f=(Object.hasOwn(j,e)?j[e]:void 0)??Error,u=new f(n);u.name!==e&&Object.defineProperty(u,"name",{configurable:!0,value:e,writable:!0});const A=y(r[4],t+1);for(const b of Object.keys(A))b===d?Object.defineProperty(u,b,{configurable:!0,enumerable:!0,value:A[b],writable:!0}):u[b]=A[b];return r.length>5&&Object.defineProperty(u,"cause",{configurable:!0,value:y(r[5],t+1),writable:!0}),u}case"bytes":{const e=I(r[2]),n=r[3]??"Uint8Array";if(n==="ArrayBuffer")return e.buffer.byteLength===e.byteLength?e.buffer:e.slice().buffer;const f=Object.hasOwn(h,n)?h[n]:void 0;return f?new f(e.slice().buffer):e}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(e=>y(e,t+1))}return r.map(c=>y(c,t+1))}const s=r,o={};for(const c of Object.keys(s)){const e=y(s[c],t+1);c===d?Object.defineProperty(o,c,{configurable:!0,enumerable:!0,value:e,writable:!0}):o[c]=e}return o},m=i,l=(r,t)=>r.startsWith(m)?y(t(r.slice(m.length))):t(r),N=r=>{if(typeof r=="boolean")return r?1:0;if(r===null||typeof r=="string"||typeof r=="number")return r;if(typeof r=="bigint")return r.toString();if(r instanceof Uint8Array)return r;if(r instanceof ArrayBuffer)return new Uint8Array(r);try{return E(r)?m+JSON.stringify(a(r)):JSON.stringify(r)}catch(t){throw new B("BAD_REQUEST",`this value cannot be stored: ${t instanceof Error?t.message:String(t)}`)}},k=r=>{try{return JSON.parse(r)}catch{return r}},S=r=>{if(typeof r!="string")return r;try{return BigInt(r)}catch{return r}},_=r=>R(r),P=(r,t)=>{if(r===null)return r;switch(t){case"any":case"from":case"union":return typeof r=="string"&&(r.startsWith("{")||r.startsWith("[")||r.startsWith(m))?l(r,k):r;case"array":case"geoPoint":case"object":case"record":return typeof r=="string"?l(r,k):r;case"bigint":return S(r);case"boolean":return r===0||r===1?r===1:r;case"bytes":return r instanceof ArrayBuffer?r:ArrayBuffer.isView(r)?new Uint8Array(r.buffer,r.byteOffset,r.byteLength).slice().buffer:r;default:return r}};export{P as a,a as b,S as c,y as d,_ as e,E as n,N as s,k as t};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/sql-store",
3
- "version": "1.0.0-alpha.100",
3
+ "version": "1.0.0-alpha.102",
4
4
  "description": "Internal dialect-parameterized SQL store core for Lunora .global() backends (D1, PlanetScale)",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -50,8 +50,8 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
- "@lunora/errors": "1.0.0-alpha.26",
54
- "@lunora/shard-engine": "1.0.0-alpha.47",
53
+ "@lunora/errors": "1.0.0-alpha.27",
54
+ "@lunora/shard-engine": "1.0.0-alpha.49",
55
55
  "drizzle-orm": "^0.45.2"
56
56
  },
57
57
  "engines": {
@@ -1 +0,0 @@
1
- import{d as S,c as s,a as i,r as l}from"./ctx-db-search-CHdIaNJe.mjs";import"./SEARCH_STATE_TABLE-CbcRI0sw.mjs";import"./decodeGlobalRow-_JxajZP5.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
@@ -1,7 +0,0 @@
1
- import{LunoraError as g}from"@lunora/errors";import{c as It,r as Ct,A as At,q as Lt,C as kt,R as Nt,a as Mt,T as Dt,x as qt,b as Ot}from"./ctx-db-search-CHdIaNJe.mjs";import{d as ei}from"./ctx-db-search-CHdIaNJe.mjs";import{literalInList as Ft,throwingScheduler as Bt,CDC_LOG_TABLE as G,cursorBelowRetainedFloor as xt,cdcTrimmedError as Wt,aggregateTableName as Q,rankTableName as ne,assertNoExplicitUndefined as Ze,hasTrigger as Ut,runRowValidators as De,assertFlatPredicate as et,mergeWhere as O,sortColumnName as J,resolveRankPartition as tt,encodePartitionKey as Ce,resolveRankSeekTuple as Pt,RANK_TIEBREAK as Ee,CountRlsUnsupportedError as nt,normalizeIdStructurally as jt,assertValidClientId as Kt,aggregateSqlFunction as we,softDeleteScope as _e,compileWhereSql as $e,normalizeOrderKeys as Ht,buildSeekWhere as Gt,decodeCursor as Vt,resolveRelationPredicates as it,resolveWith as ot,relationHooks as rt,applySelect as st,encodeCursor as Yt,NotFoundError as Xt,applyOnDelete as zt,ConflictError as he,normalizeCountArgument as Qt,selectIndexForCount as Jt,encodeAggregateKey as z,selectIndexForAggregate as Zt,readAggregateValue as qe,runTriggers as en,matchesRankStaticWhere as at,CURSOR_PREFIX as tn,selectIndexForGroupBy as nn,tiebreakDirectionFor as on,fanOutScalarCounts as rn,matchesStaticWhere as Oe,foldAggregateTally as sn,coerceAggregateNumber as Fe,CDC_LOG_TABLE_SEQ_INDEX as an,NotUniqueError as cn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{e as Le,d as dn}from"./value-codec-BvCc9FjU.mjs";import{migrateSearchState as ln}from"./SEARCH_STATE_TABLE-CbcRI0sw.mjs";import{queryAll as I,queryRun as A,createIndexIfNotExists as Ae,decodeRow as ie,serializeColumnValue as H,columnRefSql as F,decodeRows as un,forEachRowPaged as ct,queryBatch as dt}from"./decodeGlobalRow-_JxajZP5.mjs";import{decodeGlobalRow as ni}from"./decodeGlobalRow-_JxajZP5.mjs";const fn=(s,u)=>{if(s.size<u)return;const l=s.keys().next().value;l!==void 0&&s.delete(l)},lt=50,wn=(s,u={})=>{const l=u.maxBatch??lt,i=Number.isInteger(l)&&l>0?l:lt,h=new Map;let d=!1;const c=async(R,b)=>{const v=[...b.keys()];for(let L=0;L<v.length;L+=i){const M=v.slice(L,L+i);try{const x=await s(R,M);for(const V of M){const Y=x.get(V);for(const X of b.get(V)??[])X.resolve(Y)}}catch(x){for(const V of M)for(const Y of b.get(V)??[])Y.reject(x)}}},m=()=>{d=!1;const R=[...h.entries()];h.clear();for(const[b,v]of R)c(b,v).catch(()=>{})};return{async load(R,b){return new Promise((v,L)=>{let M=h.get(R);M||(M=new Map,h.set(R,M));const x=M.get(b);x?x.push({reject:L,resolve:v}):M.set(b,[{reject:L,resolve:v}]),d||(d=!0,queueMicrotask(m))})}}},_n=new Set(["_id","id"]),We=(s,u,l)=>s==="postgres"?e`${u} IS NOT DISTINCT FROM ${l}`:s==="mysql"?e`${u} <=> ${l}`:e`${u} IS ${l}`,$n=s=>{const u=s.map(l=>e`${F(l.field)} ${e.raw(l.direction==="desc"?"DESC":"ASC")}`);if(!s.some(l=>_n.has(l.field))){const l=on(s);u.push(e`${F("id")} ${e.raw(l==="desc"?"DESC":"ASC")}`)}return e.join(u,e`, `)},ut=50,Ue=s=>{const u=[];for(const[l,i]of Object.entries(s.shape)){const h=i._meta?.column;h&&u.push([l,h])}return u},hn=(s,u,l)=>{const i={...u};for(const[h,d]of Ue(s)){if(d.serverDefault){i[h]=d.serverDefault({auth:l});continue}i[h]===void 0&&(d.defaultFn?i[h]=d.defaultFn():"defaultValue"in d&&(i[h]=d.defaultValue))}return i},ft=(s,u,l,i)=>{for(const[h,d]of Ue(s)){if(d.serverDefault){h in u&&(l[h]=d.serverDefault({auth:i}));continue}d.onUpdateFn&&!(h in u)&&(l[h]=d.onUpdateFn())}},En=128,yn=()=>{const s=new Map;return{delete:u=>{s.delete(u)},get:u=>{const l=s.get(u);if(l!==void 0)return s.delete(u),s.set(u,l),l},set:(u,l)=>{s.has(u)?s.delete(u):fn(s,En),s.set(u,l)}}},pn=async(s,u,l,i,h)=>{const d=h.get(i);if(d!==void 0)return d;const c=Object.entries(l.tables).filter(([,R])=>R.shardMode===void 0||R.shardMode.kind==="global").map(([R])=>R),m=await Promise.all(c.map(async R=>({found:(await I(s,u,e`SELECT 1 FROM ${e.identifier(R)} WHERE ${e.identifier("id")} = ${i} LIMIT 1`)).length>0,tableName:R})));for(const R of m)if(R.found)return h.set(i,R.tableName),R.tableName},oe=s=>s==null?null:Number(s),Rn=(s,u)=>u.map(l=>{const i={};for(const h of s)i[h]=l[h]??null;return{key:i,value:oe(l.value)}}),Tn=(s,u,l)=>[...s.partitionBy??[],...s.sortBy.map(h=>h.field),...s.where?Object.keys(s.where):[]].every(h=>u[h]===l[h]),_t=s=>s.length===1?s[0]:e`(${e.join(s,e` AND `)})`,te=s=>e.join(s.map(u=>e`${e.identifier(u)}`),e`, `),re=s=>e.join(s.map(u=>e`${u}`),e`, `),mn=(s,u,l,i,h)=>{const d=[];for(let c=0;c<l.length+1;c+=1){const m=l.slice(0,c).map(v=>We(s,e`${e.identifier(v)}`,i[v])),R=l[c],b=u.sortBy[c];c<l.length&&R!==void 0&&b!==void 0?m.push(e`${e.identifier(R)} ${e.raw(b.direction==="desc"?">":"<")} ${i[R]}`):m.push(e`${e.identifier(Ee)} < ${h}`),d.push(_t(m))}return d.length>0?e.join(d,e` OR `):void 0},Sn=(s,u,l)=>{if(l.length!==u.length)return;const i=[];for(const[h,d]of u.entries()){const c=[];for(let m=0;m<h;m+=1){const R=u[m];R!==void 0&&c.push(We(s,e`${e.identifier(R.column)}`,l[m]))}c.push(e`${e.identifier(d.column)} ${e.raw(d.direction==="desc"?"<":">")} ${l[h]}`),i.push(_t(c))}return e`(${e.join(i,e` OR `)})`},gn=(s,u)=>{if(s.sortBy.length===0)throw new g("INTERNAL",`rankIndex "${s.name}" requires at least one "sortBy" column for stable pagination`);const l=[{column:"__partition__",direction:"asc"}];for(const[i,h]of s.sortBy.entries())l.push({column:u[i]??J(i),direction:h.direction});return l.push({column:Ee,direction:"asc"}),l},vn=async(s,u,l,i,h)=>{const c=[];for(let v=0;v<h.length;v+=50)c.push(h.slice(v,v+50));const m=await Promise.all(c.map(async v=>I(s,u,e`SELECT * FROM ${e.identifier(i)} WHERE ${e.identifier("id")} IN (${re(v)})`))),R=new Map;for(const v of m)for(const L of v)R.set(L.id,L);const b=[];for(const v of h){const L=ie(l,R.get(v));L&&b.push(L)}return b},bn=s=>{const u=JSON.stringify(s),l=new TextEncoder().encode(u);let i="";for(const h of l)i+=String.fromCodePoint(h);return tn+btoa(i)},In=(s,u)=>u.columnType(Le(s)),Cn=(s,u,l)=>{const i=[];for(const[c,m]of Object.entries(u.shape)){if(!m._meta?.column)continue;const R=m._meta.column.notNull&&m.kind!=="optional"?" NOT NULL":"";i.push(e`${e.identifier(c)} ${e.raw(`${In(m,l)}${R}`)}`)}const h=l.frameworkColumns().map(c=>e`${e.identifier(c.name)} ${e.raw(c.type)}`),d=h.length+i.length;if(l.maxTableColumns!==void 0&&d>l.maxTableColumns)throw new g("VALIDATION_ERROR",`@lunora/sql-store: global table "${s}" needs ${String(d)} columns, over this engine's ${String(l.maxTableColumns)}-column limit — split the table, or move the extra fields into one object field`);return e.join([...h,...i],e`, `)},An=async(s,u,l,i)=>{const h=d=>{const c=F(d),m=l.shape[d],R=m&&i.indexKeyPrefix?i.indexKeyPrefix(Le(m)):void 0;return R===void 0?c:e`${c}(${e.raw(String(R))})`};for(const d of l.indexes){const c=e.join(d.fields.map(m=>h(m)),e`, `);await Ae(s,i,{columns:c,name:`${u}_${d.name}`,table:u,unique:d.unique??!1})}for(const[d,c]of Ue(l))c.unique&&await Ae(s,i,{columns:h(d),name:`${u}_unique_${d}`,table:u,unique:!0})},Ln=async(s,u,l)=>{for(const[i,h]of Object.entries(u.tables)){if(h.shardMode?.kind!=="global")continue;const d=Cn(i,h,l);await A(s,l,e`CREATE TABLE IF NOT EXISTS ${e.identifier(i)} (${d})`),await An(s,i,h,l)}},kn=async(s,u,l)=>{const{integer:i,key:h,real:d}=l.companionTypes;for(const[c,m]of Object.entries(u.tables)){const R=m.aggregateIndexes;if(!(!R||R.length===0))for(const b of R){const v=Q(c,b.name);await A(s,l,e`CREATE TABLE IF NOT EXISTS ${e.identifier(v)} (${e.identifier("__key__")} ${e.raw(h)} PRIMARY KEY, ${e.identifier("__value__")} ${e.raw(d)}, ${e.identifier("__count__")} ${e.raw(i)} NOT NULL DEFAULT 0)`),l.name==="sqlite"&&((await I(s,l,e`PRAGMA table_info(${e.identifier(v)})`)).some(M=>M.name==="__count__")||await A(s,l,e`ALTER TABLE ${e.identifier(v)} ADD COLUMN ${e.identifier("__count__")} ${e.raw(i)} NOT NULL DEFAULT 0`))}}},Be=(s,u,l,i)=>{const h=s.name==="mysql"&&i?e`${e.identifier(u)}(191)`:e`${e.identifier(u)}`;return e`${h} ${e.raw(l)}`},Nn=(s,u,l)=>{const i=[Be(s,"__partition__","ASC",!0)];for(const[h,d]of u.sortBy.entries()){const c=l.shape[d.field],m=c!==void 0&&s.indexKeyPrefix?.(Le(c))!==void 0;i.push(Be(s,J(h),d.direction==="desc"?"DESC":"ASC",m))}return i.push(Be(s,"__id__","ASC",!0)),i},Mn=(s,u,l)=>u.sortBy.map((i,h)=>{const d=l.shape[i.field],c=s.columnType(d?Le(d):void 0);return e`${e.identifier(J(h))} ${e.raw(c)}`}),Dn=async(s,u,l)=>{const{key:i}=l.companionTypes;for(const[h,d]of Object.entries(u.tables)){const c=d.rankIndexes;if(!(!c||c.length===0))for(const m of c){const R=ne(h,m.name),b=Mn(l,m,d),v=b.length>0?e`, ${e.join(b,e`, `)}`:e``;await A(s,l,e`CREATE TABLE IF NOT EXISTS ${e.identifier(R)} (${e.identifier("__id__")} ${e.raw(i)} PRIMARY KEY, ${e.identifier("__partition__")} ${e.raw(i)} NOT NULL${v})`);const L=Nn(l,m,d),M=`${h}__rank_${m.name}__btree`;await Ae(s,l,{columns:e.join(L,e`, `),name:M,table:R,unique:!1})}}},xe="__cdc_sweep",$t="global",qn=6e4,On=1e4,Fn=3e4;let wt=0;const Bn=async(s,u)=>{const{autoincrementPrimaryKey:l,key:i,real:h,text:d}=u.companionTypes;await A(s,u,e`CREATE TABLE IF NOT EXISTS ${e.identifier(G)} (${e.identifier("seq")} ${e.raw(l)}, ${e.identifier("ts")} ${e.raw(h)} NOT NULL, ${e.identifier("table")} ${e.raw(i)} NOT NULL, ${e.identifier("id")} ${e.raw(i)} NOT NULL, ${e.identifier("op")} ${e.raw(i)} NOT NULL, ${e.identifier("doc")} ${e.raw(d)})`);const c=u.indexKeyPrefix?.("string");await Ae(s,u,{columns:e`${c===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(c))})`}, ${e.identifier("seq")}`,name:an,table:G,unique:!1}),await A(s,u,e`CREATE TABLE IF NOT EXISTS ${e.identifier(xe)} (${e.identifier("id")} ${e.raw(i)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(h)} NOT NULL)`),await A(s,u,e`INSERT INTO ${e.identifier(xe)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${$t}, ${0}) ${u.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},xn=async(s,u,l)=>{const i=e`UPDATE ${e.identifier(xe)} SET ${e.identifier("lease_until")} = ${l+qn} WHERE ${e.identifier("id")} = ${$t} AND ${e.identifier("lease_until")} <= ${l}`;if(u.supportsReturning)return(await I(s,u,e`${i} RETURNING ${e.identifier("id")}`)).length>0;const h=await A(s,u,i);return(u.affectedRows?u.affectedRows(h??{rowsAffected:0}):0)>0},Wn=async(s,u,l,i)=>{if(!await xn(s,u,i))return;const h=i-l;await A(s,u,e`
2
- DELETE FROM ${e.identifier(G)} WHERE ${e.identifier("seq")} IN (
3
- SELECT ${e.identifier("seq")} FROM (
4
- SELECT ${e.identifier("seq")} FROM ${e.identifier(G)} WHERE ${e.identifier("ts")} <= ${h} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(On))}
5
- ) AS ${e.identifier("expired")}
6
- )
7
- `)},ht=async(s,u)=>{const l=await I(s,u,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(G)}`),i=Number(l[0]?.seq??Number.NaN);return Number.isFinite(i)?i:void 0},Un=async(s,u,l,i,h,d,c)=>{await A(s,c,e`INSERT INTO ${e.identifier(G)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${u}, ${l}, ${i}, ${h}, ${d===void 0?null:JSON.stringify(d)})`)},zn=async(s,u,l)=>{const i=u.sinceSeq??0,h=Math.max(1,Math.min(u.limit??1e3,1e4)),d=await ht(s,l);if(d!==void 0&&xt(d,i))throw Wt(d,i,"global");const m=(await I(s,l,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(G)} WHERE seq > ${i} ORDER BY seq ASC LIMIT ${e.raw(String(h))}`)).map(R=>{const{doc:b}=R,v={id:String(R.id),op:String(R.op),seq:Number(R.seq),table:String(R.table),ts:Number(R.ts)};return typeof b=="string"?{...v,doc:JSON.parse(b)}:v});return{changes:m,cursor:m.at(-1)?.seq??i}},Pn=async(s,u,l,i={})=>{if(i.cursorOnly){const R=await I(s,l,e`SELECT MAX(seq) AS seq FROM ${e.identifier(G)}`),b=Number(R[0]?.seq??u);return{cursor:Number.isFinite(b)?b:u,tables:[]}}const h=await I(s,l,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(G)} WHERE seq > ${u} GROUP BY ${e.identifier("table")}`);let d=u;const c=[];for(const R of h){const b=Number(R.seq);Number.isFinite(b)&&b>d&&(d=b),c.push(String(R.table))}const m=i.retained===!0?await ht(s,l):void 0;return{cursor:d,tables:c,...m===void 0?{}:{floor:m}}},Qn=s=>{const{crossShardCounter:u,crossShardReader:l,exec:i,maxRelationKeys:h,schema:d}=s,{dialect:c}=s,{isUniqueViolation:m}=c,R={fieldRef:F,serialize:H,...c.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...c.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...c.name==="sqlite"?{}:{inList:Ft}},b=(t,n)=>We(c.name,t,n),v=t=>{const n=te(t.columns),o=re(t.values),r=f=>c.name==="mysql"?e`VALUES(${e.identifier(f)})`:e`excluded.${e.identifier(f)}`,a=f=>c.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(f)}`:e`${e.identifier(f)}`,_=e.join(Object.entries(t.set(r,a)).map(([f,y])=>e`${e.identifier(f)} = ${y}`),e`, `),E=c.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${_}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${_}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${o}) ${E}`},L=s.clock??(()=>Date.now()),M=s.idGenerator??(()=>crypto.randomUUID()),x=s.cdc??!1,V=typeof s.cdcRetentionMs=="number"&&Number.isFinite(s.cdcRetentionMs)&&s.cdcRetentionMs>0?s.cdcRetentionMs:void 0,Y=s.auth??{identity:null,userId:null},X=async(t,n,o,r)=>{if(!x||(await Un(i,L(),t,n,o,r,c),V===void 0))return;const a=L();if(!(a-wt<Fn)){wt=a;try{await Wn(i,c,V,a)}catch{}}},Et=s.scheduler??Bt,ke=yn();let ye=0,Ne;const W=async()=>(Ne??=(async()=>{await Ln(i,d,c),await kn(i,d,c),await Dn(i,d,c),await ln(i,c),await Ct(i,d,c),x&&await Bn(i,c)})().catch(t=>{throw Ne=void 0,t}),Ne),se=async(t,n)=>{await W();const o=await pn(i,c,d,t,ke);if(!(n!==void 0&&o!==n))return o},ae=new Map,Pe=async(t,n)=>{const o=Q(t,n);return(await I(i,c,c.tableExists(o))).length>0},pe=async(t,n)=>{const o=`${t}::${n.name}`,r=ae.get(o);if(r!==void 0)return r;if(!await Pe(t,n.name))return ae.set(o,!1),!1;const _=d.tables[t];if(!_)return ae.set(o,!1),!1;const E=n.by??[],f=new Map;await ct(i,c,_,t,$=>{if(n.where&&!Oe($,n.where))return;const p=z(E,$);sn(f,p,n,$)});const y=Q(t,n.name);await A(i,c,e`DELETE FROM ${e.identifier(y)}`);const w=[];for(const[$,p]of f)w.push(e`INSERT INTO ${e.identifier(y)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${$}, ${p.value}, ${p.count})`);return await dt(i,c,w),ae.set(o,!0),!0},yt=async(t,n,o)=>{const r=we(n.op),a=n.field??"",_=[];for(const y of n.by??[]){const w=H(o[y]??null);_.push(w===null?e`${F(y)} IS NULL`:e`${F(y)} = ${w}`)}for(const[y,w]of Object.entries(n.where??{})){const $=w!==null&&typeof w=="object"&&!Array.isArray(w)?w.eq:w,p=H($);_.push(p===null?e`${F(y)} IS NULL`:e`${F(y)} = ${p}`)}const E=e`SELECT ${e.raw(r)}(${F(a)}) AS value FROM ${e.identifier(t)}`,f=await I(i,c,_.length>0?e`${E} WHERE ${e.join(_,e` AND `)}`:E);return oe(f[0]?.value)},pt=async(t,n)=>{await A(i,c,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},Rt=async(t,n,o,r)=>{const a=Q(t,n.name),{op:_}=n,E=n.field??"",f=o&&(!n.where||Oe(o,n.where))?o:void 0,y=r&&(!n.where||Oe(r,n.where))?r:void 0;if(!(!f&&!y)){if(_==="count"||_==="sum"||_==="avg"){const w=new Set;for(const[$,p]of[[f,-1],[y,1]]){if(!$)continue;const S=_==="count"?1:Fe($[E]);if(S===void 0)continue;const T=z(n.by??[],$);w.add(T),await A(i,c,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(C,k)=>({__count__:e`${k("__count__")} + ${C("__count__")}`,__value__:_==="count"?e`${k("__value__")} + ${C("__value__")}`:e`COALESCE(${k("__value__")}, 0) + ${C("__value__")}`}),table:a,values:[T,p*S,p]}))}for(const $ of w)await pt(a,$);return}if(f){const w=z(n.by??[],f),$=Fe(f[E]),S=(await I(i,c,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(a)} WHERE ${e.identifier("__key__")} = ${w}`))[0],T=oe(S?.value),C=(S?.count??0)-1;if(C<=0)await A(i,c,e`DELETE FROM ${e.identifier(a)} WHERE ${e.identifier("__key__")} = ${w}`);else if(S&&$!==void 0&&T!==null&&$===T){const k=await yt(t,n,f);await A(i,c,e`UPDATE ${e.identifier(a)} SET ${e.identifier("__value__")} = ${k}, ${e.identifier("__count__")} = ${C} WHERE ${e.identifier("__key__")} = ${w}`)}else await A(i,c,e`UPDATE ${e.identifier(a)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${w}`)}if(y){const w=z(n.by??[],y),$=Fe(y[E]);if($===void 0)await A(i,c,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(p,S)=>({__count__:e`${S("__count__")} + 1`}),table:a,values:[w,null,1]}));else{const p=_==="min"?"MIN":"MAX";await A(i,c,v({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(S,T)=>({__count__:e`${T("__count__")} + 1`,__value__:e`${e.raw(p)}(COALESCE(${T("__value__")}, ${S("__value__")}), ${S("__value__")})`}),table:a,values:[w,$,1]}))}}}},Re=async t=>{const n=d.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const o of n)await pe(t,o)},ce=async(t,n,o)=>{const r=d.tables[t]?.aggregateIndexes;if(!(!r||r.length===0))for(const a of r){const _=`${t}::${a.name}`;(ae.get(_)??await Pe(t,a.name))&&await Rt(t,a,n,o)}},de=new Map,je=async(t,n)=>{const o=ne(t,n);return(await I(i,c,c.tableExists(o))).length>0},Me=async(t,n)=>{const o=`${t}::rank::${n.name}`,r=de.get(o);if(r!==void 0)return r;if(!await je(t,n.name))return de.set(o,!1),!1;const _=d.tables[t];if(!_)return de.set(o,!1),!1;const E=ne(t,n.name);await A(i,c,e`DELETE FROM ${e.identifier(E)}`);const f=n.sortBy.map((p,S)=>J(S)),y=te(["__id__","__partition__",...f]),w=[];await ct(i,c,_,t,p=>{if(n.where&&!at(p,n.where))return;const S=Ce(n.partitionBy??[],p),T=n.sortBy.map(C=>H(p[C.field]??null));w.push([p._id,S,...T])});const $=w.map(p=>e`INSERT INTO ${e.identifier(E)} (${y}) VALUES (${re(p)})`);return await dt(i,c,$),de.set(o,!0),!0},Te=async t=>{const n=d.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const o of n)await Me(t,o)},Z=async(t,n,o,r)=>{const a=d.tables[t],_=a?.rankIndexes;if(!_||_.length===0)return;const E=a?.softDeleteMode?.field,f=E===void 0||r===void 0?void 0:r[E],y=f!=null;for(const w of _){if(o!==void 0&&r!==void 0&&Tn(w,o,r))continue;const $=`${t}::rank::${w.name}`;if(!(de.get($)??await je(t,w.name)))continue;const T=ne(t,w.name);if(o&&await A(i,c,e`DELETE FROM ${e.identifier(T)} WHERE ${e.identifier("__id__")} = ${n}`),r&&!y){if(w.where&&!at(r,w.where))continue;const C=w.sortBy.map((D,K)=>J(K)),k=te(["__id__","__partition__",...C]),B=Ce(w.partitionBy??[],r),N=w.sortBy.map(D=>H(r[D.field]??null));await A(i,c,e`INSERT INTO ${e.identifier(T)} (${k}) VALUES (${re([n,B,...N])})`)}}},le=It({dialect:c,exec:i,schema:d}),Ke=new Set;for(const[t,n]of Object.entries(d.tables))for(const o of Object.values(n.triggerMap??{}))Ke.add(`${t} ${o.timing} ${o.op}`);const P=(t,n,o)=>Ke.has(`${t} ${n} ${o}`);let He;const j=async(t,n,o)=>{if(ye+=1,ye>ut)throw ye-=1,new he(`trigger recursion exceeded ${String(ut)} levels on "${o.table}" — check for a self-triggering write`,"trigger");try{await en({ctx:He,event:o,op:n,schema:d,tableName:o.table,timing:t})}finally{ye-=1}},Tt=async(t,n)=>{try{await A(i,c,n)}catch(o){throw m(o)?new he(`unique constraint violation on "${t}"`,"unique"):o}},me=async(t,n)=>(await I(i,c,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],Se=async(t,n,o,r)=>{if(r===void 0)return;const a=e.join(Object.keys(r).map(f=>b(e`${e.identifier(f)}`,r[f])),e` AND `),_=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${o} WHERE ${a}`:e`DELETE FROM ${e.identifier(t)} WHERE ${a}`,E=()=>{throw new he(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(c.supportsReturning)(await I(i,c,e`${_} RETURNING ${e.identifier("id")}`)).length===0&&E();else{const f=await A(i,c,_);(c.affectedRows?c.affectedRows(f??{rowsAffected:0}):0)===0&&E()}}catch(f){throw m(f)?new he(`unique constraint violation on "${t}"`,"unique"):f}},mt=(t,n,o,r)=>{const a=Object.keys(t.shape);return{columns:["id","_creationTime",...a],values:[n,o,...a.map(_=>H(r[_]??null))]}},St=async(t,n,o,r)=>{const a=nn(n,o.op,o.field,r.by,r.where);if(!a||!await pe(t,a.index))return;const E=Q(t,a.index.name),f=Object.keys(a.partial);if(f.length===(a.index.by??[]).length&&f.length>0){const w=z(a.index.by??[],a.partial),$=await I(i,c,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(E)} WHERE ${e.identifier("__key__")} = ${w}`);if($.length===0)return[];const p=$[0];return[{key:{...a.partial},value:qe(o.op,{count:p.count,value:oe(p.value)})}]}return f.length>0?void 0:(await I(i,c,e`SELECT ${e.identifier("__key__")} AS key, ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(E)}`)).map(w=>{const $=w;return{key:dn(JSON.parse($.key)),value:qe(o.op,{count:$.count,value:oe($.value)})}})},Ge=t=>{const n=d.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},Ve=t=>{throw new g("INTERNAL",`cross-backend relation: a global table cannot load the shard-local relation '${t}' (it spans every shard) — wire a cross-shard reader to support it`)},gt=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new g("MASK_UNSUPPORTED",`masking cannot follow a nested \`with\` across the cross-shard relation hop to "${t}" — the nested rows are hydrated on the serving shard, where the mask policy does not exist. Read the nested relation at its own (masked) call site instead.`);const o={};if(n?.relationBaseWhere)for(const r of Object.keys(d.tables)){const a=n.relationBaseWhere(r);a!==void 0&&(o[r]=a)}return{orderBy:n?.orderBy,relationPolicies:o,where:O(n?.baseWhere,n?.where),with:n?.with}},Ye=(t,n)=>Ge(t)?l?l(t,gt(t,n)):Ve(t):U.findMany(t,n),ge=(t,n,o)=>it(t,{fetcher:Ye,maxRelationKeys:h,relationBaseWhere:o,schema:d,tableName:n}),vt=wn(async(t,n)=>{const o=await I(i,c,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${re(n)})`),r=new Map;for(const a of o){const{id:_}=a;typeof _=="string"&&r.set(_,a)}return r}),U={async cdcChangedTables(t,n){if(x)try{return await W(),await Pn(i,t,c,{...n,retained:V!==void 0})}catch{return}},async aggregate(t,n){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);if(await W(),we(n.op),n.op==="count")return U.count(t,{baseWhere:n.baseWhere,relationBaseWhere:n.relationBaseWhere,restrictsCounts:n.restrictsCounts,where:n.where});if(!n.field)throw new g("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const r=_e(o.softDeleteMode,void 0),a=O(O(n.baseWhere,n.where),r),_=await ge(a,t,n.relationBaseWhere),E=_!==a;if(o.aggregateIndexes&&!n.baseWhere&&!E&&!r){const S=Zt(o.aggregateIndexes,n.op,n.field,n.where);if(S&&await pe(t,S.index)){const C=z(S.index.by??[],S.key),k=Q(t,S.index.name),N=(await I(i,c,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(k)} WHERE ${e.identifier("__key__")} = ${C}`))[0];return qe(n.op,N===void 0?void 0:{count:N.count,value:oe(N.value)})}}const f=$e(_,R),y=e.raw(we(n.op)),w=e`SELECT ${y}(${F(n.field)}) AS value FROM ${e.identifier(t)}`,p=(await I(i,c,f?e`${w} WHERE ${f}`:w))[0]?.value;return p==null?null:Number(p)},async count(t,n){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);await W();const r=Qt(n);if(r.restrictsCounts)throw new nt(t);const a=_e(o.softDeleteMode,void 0),_=O(O(r.baseWhere,r.where),a),E=await ge(_,t,r.relationBaseWhere),f=E!==_;if(o.aggregateIndexes&&!r.baseWhere&&!f&&!a){const p=Jt(o.aggregateIndexes,r.where);if(p&&await pe(t,p.index)){const T=z(p.index.by??[],p.key),C=Q(t,p.index.name),k=await I(i,c,e`SELECT ${e.identifier("__value__")} AS value FROM ${e.identifier(C)} WHERE ${e.identifier("__key__")} = ${T}`);return Number(k[0]?.value??0)}}const y=$e(E,R),w=e`SELECT COUNT(*) AS count FROM ${e.identifier(t)}`,$=await I(i,c,y?e`${w} WHERE ${y}`:w);return Number($[0]?.count??0)},async delete(t,n,o){const r=await se(t,n);if(!r)return;const a=d.tables[r];if(!a)return;const _=await me(r,t),E=ie(a,_),f=o?.hard===!0,y=!f&&a.softDeleteMode?a.softDeleteMode.field:void 0;if(!(y&&(!E||E[y]!==null&&E[y]!==void 0))){if(P(r,"before","delete")&&await j("before","delete",{id:t,op:"delete",previous:E??void 0,table:r}),await zt({deletedId:t,deletedReference:w=>E?.[w],findHolders:async(w,$,p)=>{if(d.tables[w]?.shardMode?.kind==="shardBy")throw new g("INTERNAL",`cross-backend cascade from global '${r}' into shardBy '${w}' is not supported — would require Query Coordinator fan-out across shards`);return(await U.findMany(w,{includeDeleted:f,where:{[$]:p}})).page},onCascade:(w,$)=>U.delete($,void 0,o),onRestrict:w=>{throw new he(w,"restrict")},onSetNull:(w,$,p)=>U.patch($,{[p]:null}),schema:d,tableName:r}),await Re(r),await Te(r),y&&E){const w={...E,[y]:L()},$=e.join(Object.keys(a.shape).map(p=>e`${e.identifier(p)} = ${H(w[p]??null)}`),e`, `);await Se(r,"UPDATE",$,_),await ce(r,E,w),await Z(r,t,E,void 0),await le(r,t,w,E),await X(r,t,"update",w),P(r,"after","delete")&&await j("after","delete",{id:t,op:"delete",previous:E,table:r});return}await Se(r,"DELETE",void 0,_),ke.delete(t),await ce(r,E??void 0,void 0),await Z(r,t,E??void 0,void 0),await le(r,t,void 0),await X(r,t,"delete"),P(r,"after","delete")&&await j("after","delete",{id:t,op:"delete",previous:E??void 0,table:r})}},async findFirst(t,n={}){return(await U.findMany(t,{...n,limit:1})).page[0]??null},async findFirstOrThrow(t,n={}){const o=await U.findFirst(t,n);if(o===null)throw new Xt(`findFirstOrThrow: no "${t}" document matched`);return o},async findMany(t,n={}){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);await W();const r=Ht(n.orderBy),a=n.cursor?Gt(r,Vt(n.cursor)):void 0,_=Ye,E=async(N,D,K,ve)=>{if(Ge(N))return u?rn(u,N,D,K,ve):Ve(N);const be=d.tables[N];if(!be)throw new g("INTERNAL",`unknown table: ${N}`);const Ie=_e(be.softDeleteMode,void 0),ee={[D]:{in:K}},q=O(O(ee,ve),Ie),ue=await ge(q,N,void 0),Xe=$e(ue,R),ze=F(D);let fe=e`SELECT ${ze} AS __fk__, COUNT(*) AS count FROM ${e.identifier(N)}`;Xe&&(fe=e`${fe} WHERE ${Xe}`),fe=e`${fe} GROUP BY ${ze}`;const bt=await I(i,c,fe),Qe=new Map;for(const Je of bt)Qe.set(Je.__fk__,Number(Je.count??0));return Qe};let f=O(n.baseWhere,n.where);f=O(f,_e(o.softDeleteMode,n.includeDeleted)),f=await it(f,{fetcher:_,maxRelationKeys:h,relationBaseWhere:n.relationBaseWhere,schema:d,tableName:t}),a&&(f=f?{AND:[f,a]}:a);const y=$e(f,R),w=$n(r);let $=e`SELECT * FROM ${e.identifier(t)}`;y&&($=e`${$} WHERE ${y}`),$=e`${$} ORDER BY ${w}`;const p=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;p!==void 0&&($=e`${$} LIMIT ${e.raw(String(p+1))}`);const S=await I(i,c,$),T=un(o,S);if(p===void 0)return n.with&&await ot({fetcher:_,groupedCounter:E,parents:T,...rt(n),schema:d,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:st(T,n.select,n.with)};const C=T.length>p,k=C?T.slice(0,p):T,B=k.at(-1);return n.with&&await ot({fetcher:_,groupedCounter:E,parents:k,...rt(n),schema:d,tableName:t,with:n.with}),{continueCursor:C&&B?Yt(B,r):null,isDone:!C,page:st(k,n.select,n.with)}},async get(t,n){const o=await se(t,n);if(!o)return null;const r=d.tables[o];return r?ie(r,await vt.load(o,t)):null},async groupBy(t,n){const o=d.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);await W();const r=n.agg??{op:"count"};if(we(r.op),r.op!=="count"&&!r.field)throw new g("INTERNAL",`groupBy(${t}, { agg: { op: "${r.op}" } }): "field" is required for non-count reducers`);const a=_e(o.softDeleteMode,void 0),_=O(O(n.baseWhere,n.where),a),E=await ge(_,t,n.relationBaseWhere),f=E!==_;if(o.aggregateIndexes&&!n.baseWhere&&!f&&!a){const T=await St(t,o.aggregateIndexes,r,n);if(T!==void 0)return T}const y=$e(E,R),w=n.by.map(T=>e`${F(T)} AS ${e.identifier(T)}`);if(r.op==="count")w.push(e`COUNT(*) AS value`);else{if(!r.field)throw new g("INTERNAL",`groupBy(${t}, { agg: { op: "${r.op}" } }): "field" is required for non-count reducers`);w.push(e`${e.raw(we(r.op))}(${F(r.field)}) AS value`)}const $=e.join(n.by.map(T=>F(T)),e`, `);let p=e`SELECT ${e.join(w,e`, `)} FROM ${e.identifier(t)}`;y&&(p=e`${p} WHERE ${y}`),p=e`${p} GROUP BY ${$}`;const S=await I(i,c,p);return Rn(n.by,S)},async insert(t,n,o){const r=d.tables[t];if(!r)throw new g("INTERNAL",`unknown table: ${t}`);await W();const a=hn(r,n,Y);De(r,a);let _,E=!0;o?.clientId!==void 0?(Kt(o.clientId),_=o.clientId):o?.allowExplicitId&&typeof a._id=="string"?_=a._id:(_=M(),E=!1);const f=o?.allowExplicitId&&typeof a._creationTime=="number"?a._creationTime:L(),y={...a,_creationTime:f,_id:_};P(t,"before","insert")&&await j("before","insert",{doc:{...y},id:_,op:"insert",table:t}),await Re(t),await Te(t);const{columns:w,values:$}=mt(r,_,f,a);return await Tt(t,e`INSERT INTO ${e.identifier(t)} (${te(w)}) VALUES (${re($)})`),E&&ke.set(_,t),await ce(t,void 0,y),await Z(t,_,void 0,y),await le(t,_,y),await X(t,_,"insert",y),P(t,"after","insert")&&await j("after","insert",{doc:y,id:_,op:"insert",table:t}),_},normalizeId(t,n){return jt(d,t,n)},async patch(t,n,o){Ze("patch",n);const r=await se(t,o);if(!r)throw new g("INTERNAL",`document not found: ${t}`);const a=d.tables[r];if(!a)throw new g("INTERNAL",`document not found: ${t}`);const _=await me(r,t),E=ie(a,_);if(!E)throw new g("INTERNAL",`document not found: ${t}`);const f={...E,...n,_id:t};ft(a,n,f,Y),De(a,f,!0),P(r,"before","update")&&await j("before","update",{doc:{...f},id:t,op:"update",previous:E,table:r}),await Re(r),await Te(r);const y=Object.keys(a.shape),w=e.join(y.map($=>e`${e.identifier($)} = ${H(f[$]??null)}`),e`, `);await Se(r,"UPDATE",w,_),await ce(r,E,f),await Z(r,t,E,f),await le(r,t,f,E),await X(r,t,"update",f),P(r,"after","update")&&await j("after","update",{doc:f,id:t,op:"update",previous:E,table:r})},async restore(t,n){const o=await se(t,n);if(!o)throw new g("INTERNAL",`document not found: ${t}`);const r=d.tables[o],a=r?.softDeleteMode?.field;if(!r||!a)throw new g("INTERNAL",`ctx.db.restore: table "${o}" is not a .softDelete() table`);const _=await me(o,t),E=_?.[a]!==null&&_?.[a]!==void 0;if(await U.patch(t,{[a]:null},n),E){const f=ie(r,_);f!==null&&await Z(o,t,void 0,{...f,[a]:null})}},query(t){const n=d.tables[t];if(!n)throw new g("INTERNAL",`unknown table: ${t}`);const o="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",r=[],a=f=>r.every(y=>y(f)),_=async(f,y)=>{await W();const w=r.length>0,$=await Mt(i,c,n,t,f,Dt(w?void 0:y));if(!w)return y===void 0&&qt($),$;const p=$.filter(S=>a(S));return y===void 0?p:p.slice(0,y)},E=f=>{const y={async*[Symbol.asyncIterator](){if(!f)throw new g("INTERNAL",o);yield*await _(f,void 0)},async collect(){if(!f)throw new g("INTERNAL",o);return _(f,void 0)},async collectWithScores(){throw new g("GLOBAL_SEARCH_SCORES_UNSUPPORTED",`collectWithScores() is not supported on \`.global()\` tables (table "${t}") — relevance scores are not yet surfaced on this backend; use .collect() instead`)},filter(w){return r.push(w),y},async first(){if(!f)throw new g("INTERNAL",o);return(await _(f,1))[0]??null},order(){return y},async paginate(w){if(!f)throw new g("INTERNAL",o);const $=kt(w);return Nt(await _(f,Ot($)),$)},async take(w){if(!f)throw new g("INTERNAL",o);return _(f,w)},async unique(){if(!f)throw new g("INTERNAL",o);const w=await _(f,2);if(w.length>1)throw new cn(`unique() on table "${t}" matched ${String(w.length)} documents; expected at most one`);return w[0]??null},withGeoIndex(){throw new g("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new g("INTERNAL",o)},withSearchIndex(w,$){const p=(n.searchIndexes??[]).find(T=>T.name===w);if(!p)throw new g("INTERNAL",`unknown search index "${w}" on table "${t}"`);const S={definition:p,field:p.field,filters:[],hasQuery:!1,indexName:w,query:""};if($(At(S,t,Lt(p.language))),!S.hasQuery)throw new g("INTERNAL",`search index "${w}" on table "${t}" requires a .search(field, query) call`);return E(S)}};return y};return E(void 0)},async rank(t,n,o){const r=d.tables[t];if(!r)throw new g("INTERNAL",`unknown table: ${t}`);const a=r.rankIndexes?.find(D=>D.name===n);if(!a)throw new g("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(o.restrictsCounts)throw new nt(t);if(await W(),!await Me(t,a))return null;const E=typeof o.row=="string"?o.row:o.row._id;if(!E)return null;const f=ne(t,a.name),y=a.sortBy.map((D,K)=>J(K)),w=te(["__partition__",...y]),p=(await I(i,c,e`SELECT ${w} FROM ${e.identifier(f)} WHERE ${e.identifier("__id__")} = ${E}`))[0];if(!p)return null;const S=p.__partition__,T=O(o.baseWhere,o.where);et(T,d,t,"rank");const C=tt(a,T);if(C&&Ce(a.partitionBy??[],C)!==S)return null;const k=mn(c.name,a,y,p,E),B=await I(i,c,e`SELECT COUNT(*) AS c FROM ${e.identifier(f)} WHERE ${e.identifier("__partition__")} = ${S}${k?e` AND (${k})`:e``}`),N=await I(i,c,e`SELECT COUNT(*) AS c FROM ${e.identifier(f)} WHERE ${e.identifier("__partition__")} = ${S}`);return{position:Number(B[0]?.c??0)+1,total:Number(N[0]?.c??0)}},async rankPage(t,n,o={}){et(O(o.baseWhere,o.where),d,t,"rankPage");const r=d.tables[t];if(!r)throw new g("INTERNAL",`unknown table: ${t}`);const a=r.rankIndexes?.find(q=>q.name===n);if(!a)throw new g("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await W(),!await Me(t,a))return{continueCursor:null,isDone:!0,page:[]};const E=ne(t,a.name),f=a.sortBy.map((q,ue)=>J(ue)),y=Math.max(1,Math.min(1e3,Math.floor(o.take??100))),w=O(o.baseWhere,o.where),$=tt(a,w),p=gn(a,f),S=e.join(p.map(q=>e`${e.identifier(q.column)} ${e.raw(q.direction==="desc"?"DESC":"ASC")}`),e`, `),T=[];typeof o.partitionKey=="string"?T.push(e`${e.identifier("__partition__")} = ${o.partitionKey}`):$&&T.push(e`${e.identifier("__partition__")} = ${Ce(a.partitionBy??[],$)}`);const C=Pt(o);if(C!==void 0){const q=Sn(c.name,p,C);q!==void 0&&T.push(q)}const k=te([Ee,"__partition__",...f]);let B=e`SELECT ${k} FROM ${e.identifier(E)}`;T.length>0&&(B=e`${B} WHERE ${e.join(T,e` AND `)}`),B=e`${B} ORDER BY ${S} LIMIT ${e.raw(String(y+1))}`;const N=await I(i,c,B),D=N.length>y,K=D?N.slice(0,y):N,ve=K.map(q=>q[Ee]),be=await vn(i,c,r,t,ve);let Ie=null;const ee=K.at(-1);if(D&&ee!==void 0){const q=[ee.__partition__,...f.map(ue=>ee[ue]),ee[Ee]];Ie=bn(q)}return{continueCursor:Ie,isDone:!D,page:be}},async replace(t,n,o,r){Ze("replace",n);const a=await se(t,o);if(!a)throw new g("INTERNAL",`document not found: ${t}`);const _=d.tables[a];if(!_)throw new g("INTERNAL",`document not found: ${t}`);const E=await me(a,t);if(E===void 0)throw new g("INTERNAL",`document not found: ${t}`);const y=Ut(d,a,"update")||(_.aggregateIndexes??[]).length>0||(_.rankIndexes??[]).length>0?ie(_,E)??void 0:void 0,w=r?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:L(),$={...n,_creationTime:w,_id:t};ft(_,n,$,Y),De(_,$),P(a,"before","update")&&await j("before","update",{doc:{...$},id:t,op:"update",previous:y,table:a}),await Re(a),await Te(a);const p=Object.keys(_.shape),S=e.join([e`${e.identifier("_creationTime")} = ${w}`,...p.map(T=>e`${e.identifier(T)} = ${H($[T]??null)}`)],e`, `);await Se(a,"UPDATE",S,E),await ce(a,y,$),await Z(a,t,y,$),await le(a,t,$,y),await X(a,t,"update",$),P(a,"after","update")&&await j("after","update",{doc:$,id:t,op:"update",previous:y,table:a})}};return He={db:U,scheduler:Et},U};export{ei as backfillSqlSearchIndexes,Qn as createSqlCtxDb,ni as decodeGlobalRow,Pn as readSqlCdcChangedTables,zn as readSqlCdcChanges,ht as readSqlCdcFloor,kn as runSqlAggregateMigrations,Bn as runSqlCdcMigration,Ln as runSqlGlobalTableMigrations,Dn as runSqlRankMigrations,Ct as runSqlSearchMigrations,Wn as sweepSqlCdcRetention};
@@ -1 +0,0 @@
1
- import{b as a,e as o,a as t,s as i,t as d}from"./value-codec-BvCc9FjU.mjs";export{a as decodeBigint,o as effectiveColumnKind,t as sqliteDecode,i as sqliteEncode,d as tryJsonParse};
@@ -1 +0,0 @@
1
- import{LunoraError as B}from"@lunora/errors";const U=r=>{if(r.kind!=="optional")return r.kind;const t=r._meta?.inner;return t?U(t):r.kind},p=r=>{let t="";for(let n=0;n<r.length;n+=32768)t+=String.fromCharCode(...r.subarray(n,n+32768));return btoa(t)},I=r=>{const t=atob(r),s=new Uint8Array(t.length);for(let n=0;n<t.length;n+=1)s[n]=t.codePointAt(n)??0;return s},i="$lunora.wire$",g=64,O=1024,d="__proto__",j={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},h={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},k=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},E=(r,t=0)=>{if(t>g)return!0;if(r===null)return!1;const s=typeof r;if(s==="string"||s==="boolean")return!1;if(s==="number")return!Number.isFinite(r);if(s!=="object")return!0;if(Array.isArray(r))return r.length>0&&r[0]===i?!0:r.some(n=>n===void 0||E(n,t+1));if(!k(r)||Object.hasOwn(r,d))return!0;for(const n of Object.keys(r)){const c=r[n];if(c!==void 0&&E(c,t+1))return!0}return!1},a=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===void 0)return[i,"undefined"];if(r===null)return null;const s=typeof r;if(s==="bigint")return[i,"bigint",r.toString()];if(s==="number"){const e=r;return Number.isNaN(e)?[i,"nan"]:e===1/0?[i,"inf"]:e===-1/0?[i,"-inf"]:e}if(s!=="object")return r;if(r instanceof Date)return[i,"date",a(r.getTime(),t+1)];if(r instanceof Error){const e=r,o={};for(const u of Object.keys(e))e[u]!==void 0&&(o[u]=a(e[u],t+1));const f=[i,"error",e.name,e.message,o];return e.cause!==void 0&&f.push(a(e.cause,t+1)),f}if(r instanceof URL)return[i,"url",r.href];if(r instanceof Map)return[i,"map",[...r.entries()].map(([e,o])=>[a(e,t+1),a(o,t+1)])];if(r instanceof Set)return[i,"set",[...r].map(e=>a(e,t+1))];if(r instanceof ArrayBuffer)return[i,"bytes",p(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,o=e.constructor.name,f=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return o==="Uint8Array"?[i,"bytes",p(f)]:[i,"bytes",p(f),o]}if(Array.isArray(r)){const e=r.map(o=>a(o,t+1));return e.length>0&&e[0]===i?[i,"arr",e]:e}if(!k(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const n=r,c={};for(const e of Object.keys(n)){const o=n[e];if(o===void 0)continue;const f=a(o,t+1);e===d?Object.defineProperty(c,e,{configurable:!0,enumerable:!0,value:f,writable:!0}):c[e]=f}return c},y=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===i)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(e=>y(e,t+1));case"bigint":{const e=r[2];if(typeof e!="string"||e.length>O||!/^-?\d+$/.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${O} digits)`);return BigInt(e)}case"date":return new Date(y(r[2],t+1));case"map":return new Map(r[2].map(([e,o])=>[y(e,t+1),y(o,t+1)]));case"set":return new Set(r[2].map(e=>y(e,t+1)));case"url":return new URL(r[2]);case"error":{const e=r[2],o=r[3],f=(Object.hasOwn(h,e)?h[e]:void 0)??Error,u=new f(o);u.name!==e&&Object.defineProperty(u,"name",{configurable:!0,value:e,writable:!0});const A=y(r[4],t+1);for(const b of Object.keys(A))b===d?Object.defineProperty(u,b,{configurable:!0,enumerable:!0,value:A[b],writable:!0}):u[b]=A[b];return r.length>5&&Object.defineProperty(u,"cause",{configurable:!0,value:y(r[5],t+1),writable:!0}),u}case"bytes":{const e=I(r[2]),o=r[3]??"Uint8Array";if(o==="ArrayBuffer")return e.buffer.byteLength===e.byteLength?e.buffer:e.slice().buffer;const f=Object.hasOwn(j,o)?j[o]:void 0;return f?new f(e.slice().buffer):e}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(e=>y(e,t+1))}return r.map(c=>y(c,t+1))}const s=r,n={};for(const c of Object.keys(s)){const e=y(s[c],t+1);c===d?Object.defineProperty(n,c,{configurable:!0,enumerable:!0,value:e,writable:!0}):n[c]=e}return n},m=i,l=(r,t)=>r.startsWith(m)?y(t(r.slice(m.length))):t(r),_=r=>{if(typeof r=="boolean")return r?1:0;if(r===null||typeof r=="string"||typeof r=="number")return r;if(typeof r=="bigint")return r.toString();if(r instanceof Uint8Array)return r;if(r instanceof ArrayBuffer)return new Uint8Array(r);try{return E(r)?m+JSON.stringify(a(r)):JSON.stringify(r)}catch(t){throw new B("BAD_REQUEST",`this value cannot be stored: ${t instanceof Error?t.message:String(t)}`)}},R=r=>{try{return JSON.parse(r)}catch{return r}},S=r=>{if(typeof r!="string")return r;try{return BigInt(r)}catch{return r}},w=r=>U(r),P=(r,t)=>{if(r===null)return r;switch(t){case"any":case"from":case"union":return typeof r=="string"&&(r.startsWith("{")||r.startsWith("[")||r.startsWith(m))?l(r,R):r;case"array":case"object":case"record":return typeof r=="string"?l(r,R):r;case"bigint":return S(r);case"boolean":return r===0||r===1?r===1:r;case"bytes":return r instanceof ArrayBuffer?r:ArrayBuffer.isView(r)?new Uint8Array(r.buffer,r.byteOffset,r.byteLength).slice().buffer:r;default:return r}};export{P as a,S as b,y as d,w as e,_ as s,R as t};