@lunora/sql-store 1.0.0-alpha.134 → 1.0.0-alpha.136

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/dist/index.d.mts CHANGED
@@ -28,6 +28,17 @@ interface SqlCtxExec {
28
28
  * correct on SQLite, Postgres and MySQL.
29
29
  */
30
30
  declare const decodeGlobalRow: (definition: TableDefinitionLike, row: Record<string, unknown>) => Record<string, unknown>;
31
+ /** What {@link backfillSqlSearchIndexes} could not finish. */
32
+ interface SqlSearchBackfillResult {
33
+ /**
34
+ * Inverted companions that still lack their unique `(token, id)` key. Writes
35
+ * keep working without it, but two backfills racing over one row can index
36
+ * it twice; the warning logged for each says why the key was refused.
37
+ */
38
+ uniqueKeyMissing: string[];
39
+ /** A previous build's rows left unmigrated because every attempt at them lost to a concurrent write. */
40
+ unmappedSkipped: number;
41
+ }
31
42
  /**
32
43
  * Provision the search companions, then index one bounded page of the rows that
33
44
  * predate each index — unless it is declared `staged: true`, which leaves the
@@ -37,11 +48,6 @@ declare const decodeGlobalRow: (definition: TableDefinitionLike, row: Record<str
37
48
  * from recorded progress).
38
49
  */
39
50
  declare const runSqlSearchMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
40
- /** What {@link backfillSqlSearchIndexes} could not finish. */
41
- interface SqlSearchBackfillResult {
42
- /** A previous build's rows left unmigrated because every attempt at them lost to a concurrent write. */
43
- unmappedSkipped: number;
44
- }
45
51
  /**
46
52
  * Run every declared search index — including the `staged: true` ones the
47
53
  * migration pass skips — through to completion. The entry point a host calls
package/dist/index.d.ts CHANGED
@@ -28,6 +28,17 @@ interface SqlCtxExec {
28
28
  * correct on SQLite, Postgres and MySQL.
29
29
  */
30
30
  declare const decodeGlobalRow: (definition: TableDefinitionLike, row: Record<string, unknown>) => Record<string, unknown>;
31
+ /** What {@link backfillSqlSearchIndexes} could not finish. */
32
+ interface SqlSearchBackfillResult {
33
+ /**
34
+ * Inverted companions that still lack their unique `(token, id)` key. Writes
35
+ * keep working without it, but two backfills racing over one row can index
36
+ * it twice; the warning logged for each says why the key was refused.
37
+ */
38
+ uniqueKeyMissing: string[];
39
+ /** A previous build's rows left unmigrated because every attempt at them lost to a concurrent write. */
40
+ unmappedSkipped: number;
41
+ }
31
42
  /**
32
43
  * Provision the search companions, then index one bounded page of the rows that
33
44
  * predate each index — unless it is declared `staged: true`, which leaves the
@@ -37,11 +48,6 @@ declare const decodeGlobalRow: (definition: TableDefinitionLike, row: Record<str
37
48
  * from recorded progress).
38
49
  */
39
50
  declare const runSqlSearchMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
40
- /** What {@link backfillSqlSearchIndexes} could not finish. */
41
- interface SqlSearchBackfillResult {
42
- /** A previous build's rows left unmigrated because every attempt at them lost to a concurrent write. */
43
- unmappedSkipped: number;
44
- }
45
51
  /**
46
52
  * Run every declared search index — including the `staged: true` ones the
47
53
  * migration pass skips — through to completion. The entry point a host calls
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,runSqlCdcMigration as s,sweepSqlCdcRetention as n}from"./packem_shared/createSqlCtxDb-D07PHR9y.mjs";import{runSqlAggregateMigrations as d,runSqlGlobalTableMigrations as S,runSqlRankMigrations as c}from"./packem_shared/runSqlAggregateMigrations-B9-Aq3_d.mjs";import{d as g,r as f}from"./packem_shared/ctx-db-search-BU0YOW8P.mjs";import{S as m,m as x}from"./packem_shared/ctx-db-search-state-DaAD01za.mjs";import{f as p,e as u,b as h,s as M,t as T}from"./packem_shared/value-codec-DC_dHxUY.mjs";import{decodeGlobalRow as E}from"./packem_shared/decodeGlobalRow-C5EqHgwt.mjs";export{m as SEARCH_STATE_TABLE,g as backfillSqlSearchIndexes,a as createSqlCtxDb,p as decodeBigint,E as decodeGlobalRow,u as effectiveColumnKind,x as migrateSearchState,o as readSqlCdcChangedTables,t as readSqlCdcChanges,l as readSqlCdcFloor,d as runSqlAggregateMigrations,s as runSqlCdcMigration,S as runSqlGlobalTableMigrations,c as runSqlRankMigrations,f as runSqlSearchMigrations,h as sqliteDecode,M as sqliteEncode,n as sweepSqlCdcRetention,T as tryJsonParse};
1
+ import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,runSqlCdcMigration as s,sweepSqlCdcRetention as n}from"./packem_shared/createSqlCtxDb-B8367Cr7.mjs";import{runSqlAggregateMigrations as d,runSqlGlobalTableMigrations as S,runSqlRankMigrations as c}from"./packem_shared/runSqlAggregateMigrations-CmsPHIJb.mjs";import{d as g,r as f}from"./packem_shared/ctx-db-search-CvZzVlOl.mjs";import{S as m,m as x}from"./packem_shared/ctx-db-search-state-DGbsWTp6.mjs";import{f as p,e as u,b as h,s as M,t as T}from"./packem_shared/value-codec-DC_dHxUY.mjs";import{decodeGlobalRow as E}from"./packem_shared/decodeGlobalRow-VOl_TIbk.mjs";export{m as SEARCH_STATE_TABLE,g as backfillSqlSearchIndexes,a as createSqlCtxDb,p as decodeBigint,E as decodeGlobalRow,u as effectiveColumnKind,x as migrateSearchState,o as readSqlCdcChangedTables,t as readSqlCdcChanges,l as readSqlCdcFloor,d as runSqlAggregateMigrations,s as runSqlCdcMigration,S as runSqlGlobalTableMigrations,c as runSqlRankMigrations,f as runSqlSearchMigrations,h as sqliteDecode,M as sqliteEncode,n as sweepSqlCdcRetention,T as tryJsonParse};
@@ -1 +1 @@
1
- import{S as t,a as S,m as c,r as l,b as i,w as s}from"./ctx-db-search-state-DaAD01za.mjs";import"./decodeGlobalRow-C5EqHgwt.mjs";export{t as SEARCH_STATE_TABLE,S as clearSearchBackfillState,c as migrateSearchState,l as readSearchBackfillState,i as readSearchIndexCoverage,s as writeSearchBackfillState};
1
+ import{S as t,a as S,m as c,r as l,b as i,w as s}from"./ctx-db-search-state-DGbsWTp6.mjs";import"./decodeGlobalRow-VOl_TIbk.mjs";export{t as SEARCH_STATE_TABLE,S as clearSearchBackfillState,c as migrateSearchState,l as readSearchBackfillState,i as readSearchIndexCoverage,s as writeSearchBackfillState};
@@ -0,0 +1 @@
1
+ import"./ctx-db-search-state-DGbsWTp6.mjs";import{d as S,c as s,a as i,r as l}from"./ctx-db-search-CvZzVlOl.mjs";import"./decodeGlobalRow-VOl_TIbk.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
@@ -0,0 +1,7 @@
1
+ import{LunoraError as v}from"@lunora/errors";import{m as xt,D as Pt}from"./ctx-db-search-state-DGbsWTp6.mjs";import{c as Ht,r as Kt,A as jt,C as Gt,R as Vt,a as Yt,T as Xt,x as zt,b as Qt}from"./ctx-db-search-CvZzVlOl.mjs";import{d as gi}from"./ctx-db-search-CvZzVlOl.mjs";import{literalInList as Jt,throwingScheduler as Zt,CDC_LOG_TABLE as P,cdcForkedError as en,cursorBelowRetainedFloor as tn,cdcTrimmedError as nn,assertNoExplicitUndefined as nt,hasTrigger as on,runRowValidators as De,assertFlatPredicate as it,mergeWhere as B,rankTableName as we,sortColumnName as ye,resolveRankPartition as ot,encodePartitionKey as Ae,resolveRankSeekTuple as rn,RANK_TIEBREAK as pe,CountRlsUnsupportedError as rt,stripReservedPatchFields as sn,normalizeIdStructurally as an,assertValidClientId as cn,aggregateSqlFunction as $e,softDeleteScope as _e,compileWhereSql as he,normalizeOrderKeys as dn,uniqueIndexFields as ln,equalityPinnedFields as un,buildSeekWhere as fn,decodeCursor as wn,resolveRelationPredicates as st,resolveWith as at,relationHooks as ct,applySelect as dt,encodeCursor as $n,NotFoundError as _n,applyOnDelete as hn,ConflictError as Le,normalizeCountArgument as En,selectIndexForCount as yn,encodeAggregateKey as Y,aggregateTableName as Q,selectIndexForAggregate as pn,readAggregateValue as Be,runTriggers as Rn,matchesRankStaticWhere as lt,rankPivotConditionSql as St,CURSOR_PREFIX as Sn,selectIndexForGroupBy as gn,tiebreakDirectionFor as vn,fanOutScalarCounts as Tn,matchesStaticWhere as Fe,foldAggregateTally as ut,coerceAggregateNumber as Oe,CDC_LOG_TABLE_SEQ_INDEX as mn,NotUniqueError as bn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{d as gt,b as In,e as vt,n as Cn,c as An}from"./value-codec-DC_dHxUY.mjs";import{runSqlGlobalTableMigrations as Ln,runSqlAggregateMigrations as kn,runSqlRankMigrations as Mn}from"./runSqlAggregateMigrations-CmsPHIJb.mjs";import{queryAll as m,queryRun as M,createIndexIfNotExists as Nn,decodeRow as ee,serializeDocumentColumn as J,OCC_VERSION_COLUMN as Ee,columnRefSql as F,decodeRows as ft,tableColumns as Tt,nextRowVersion as wt,serializeColumnValue as We,forEachRowPaged as $t,BACKFILL_BATCH_SIZE as Ue,nullSafeEqualsSql as Ke,queryBatch as _t}from"./decodeGlobalRow-VOl_TIbk.mjs";import{decodeGlobalRow as Ti}from"./decodeGlobalRow-VOl_TIbk.mjs";const qn=(a,c)=>{if(a.size<c)return;const E=a.keys().next().value;E!==void 0&&a.delete(E)},ht=50,Dn=(a,c={})=>{const E=c.maxBatch??ht,r=Number.isInteger(E)&&E>0?E:ht,p=new Map;let w=!1;const d=async(g,T)=>{const b=[...T.keys()];for(let C=0;C<b.length;C+=r){const N=b.slice(C,C+r);try{const W=await a(g,N);for(const G of N){const V=W.get(G);for(const ie of T.get(G)??[])ie.resolve(V)}}catch(W){for(const G of N)for(const V of T.get(G)??[])V.reject(W)}}},L=()=>{w=!1;const g=[...p.entries()];p.clear();for(const[T,b]of g)d(T,b).catch(()=>{})};return{async load(g,T){return new Promise((b,C)=>{let N=p.get(g);N||(N=new Map,p.set(g,N));const W=N.get(T);W?W.push({reject:C,resolve:b}):N.set(T,[{reject:C,resolve:b}]),w||(w=!0,queueMicrotask(L))})}}},Bn=new Set(["_id","id"]),mt=(a,c)=>a.name!=="postgres"||c.nullable!==!0?"":c.direction==="desc"?" NULLS LAST":" NULLS FIRST",Fn=(a,c)=>{const E=a.map(r=>e`${F(r.field)} ${e.raw(`${r.direction==="desc"?"DESC":"ASC"}${mt(c,r)}`)}`);if(!a.some(r=>Bn.has(r.field))){const r=vn(a);E.push(e`${F("id")} ${e.raw(r==="desc"?"DESC":"ASC")}`)}return e.join(E,e`, `)},Et=50,On=(a,c,E)=>{const r={...c};for(const[p,w]of Tt(a)){if(w.serverDefault){r[p]=w.serverDefault({auth:E});continue}r[p]===void 0&&(w.defaultFn?r[p]=w.defaultFn():"defaultValue"in w&&(r[p]=w.defaultValue))}return r},yt=(a,c,E,r)=>{for(const[p,w]of Tt(a)){if(w.serverDefault){p in c&&(E[p]=w.serverDefault({auth:r}));continue}w.onUpdateFn&&!(p in c)&&(E[p]=w.onUpdateFn())}},Wn=128,Un=()=>{const a=new Map;return{delete:c=>{a.delete(c)},get:c=>{const E=a.get(c);if(E!==void 0)return a.delete(c),a.set(c,E),E},set:(c,E)=>{a.has(c)?a.delete(c):qn(a,Wn),a.set(c,E)}}},xn=async(a,c,E,r,p)=>{const w=p.get(r);if(w!==void 0)return w;const d=Object.entries(E.tables).filter(([,g])=>g.shardMode===void 0||g.shardMode.kind==="global").map(([g])=>g),L=await Promise.all(d.map(async g=>({found:(await m(a,c,e`SELECT 1 FROM ${e.identifier(g)} WHERE ${e.identifier("id")} = ${r} LIMIT 1`)).length>0,tableName:g})));for(const g of L)if(g.found)return p.set(r,g.tableName),g.tableName},te=a=>a==null?null:Number(a),Pn=(a,c,E)=>E.map(r=>{const p={};for(const w of c){const d=a.shape[w];p[w]=In(r[w]??null,d&&vt(d))}return{key:p,value:te(r.value)}}),Hn=(a,c,E)=>[...a.partitionBy??[],...a.sortBy.map(p=>p.field),...a.where?Object.keys(a.where):[]].every(p=>c[p]===E[p]),bt=a=>a.length===1?a[0]:e`(${e.join(a,e` AND `)})`,Z=a=>e.join(a.map(c=>e`${e.identifier(c)}`),e`, `),ne=a=>e.join(a.map(c=>e`${c}`),e`, `),Kn=(a,c,E,r,p)=>{const w=[];for(let d=0;d<E.length+1;d+=1){const L=E[d],g=c.sortBy[d],T=d<E.length&&L!==void 0&&g!==void 0,b=g?.direction==="desc"?"desc":"asc",C=T?St(L,r[L],b,!1):e`${e.identifier(pe)} < ${p}`;if(C===void 0)continue;const N=E.slice(0,d).map(W=>Ke(a,e`${e.identifier(W)}`,r[W]));N.push(C),w.push(bt(N))}return w.length>0?e.join(w,e` OR `):e`1 = 0`},jn=(a,c,E)=>{if(E.length!==c.length)return;const r=[];for(const[p,w]of c.entries()){const d=St(w.column,E[p],w.direction,!0);if(d===void 0)continue;const L=[];for(let g=0;g<p;g+=1){const T=c[g];T!==void 0&&L.push(Ke(a,e`${e.identifier(T.column)}`,E[g]))}L.push(d),r.push(bt(L))}return r.length===0?e`(1 = 0)`:e`(${e.join(r,e` OR `)})`},Gn=(a,c)=>{if(a.sortBy.length===0)throw new v("INTERNAL",`rankIndex "${a.name}" requires at least one "sortBy" column for stable pagination`);const E=[{column:"__partition__",direction:"asc",nullable:!1}];for(const[r,p]of a.sortBy.entries())E.push({column:c[r]??ye(r),direction:p.direction,nullable:!0});return E.push({column:pe,direction:"asc",nullable:!1}),E},Vn=async(a,c,E,r,p)=>{const d=[];for(let b=0;b<p.length;b+=50)d.push(p.slice(b,b+50));const L=await Promise.all(d.map(async b=>m(a,c,e`SELECT * FROM ${e.identifier(r)} WHERE ${e.identifier("id")} IN (${ne(b)})`))),g=new Map;for(const b of L)for(const C of b)g.set(C.id,C);const T=[];for(const b of p){const C=ee(E,g.get(b));C&&T.push(C)}return T},Yn=a=>{const c=JSON.stringify(a),E=new TextEncoder().encode(c);let r="";for(const p of E)r+=String.fromCodePoint(p);return Sn+btoa(r)},It=a=>{if(a===void 0)return!1;const c=vt(a);return c==="any"||c==="bigint"||c==="from"||c==="union"},Pe=(a,c,E)=>{if(It(a.shape[c]))throw new v("BAD_REQUEST",`${E}: "${c}" may hold an order-preserving key rather than a value SQL can reduce or group — declare an aggregateIndex covering this (by, field, op) so the maintained companion answers it instead (its running total is a REAL, so it stays exact only while the total is inside 2^53)`)},Xn=(a,c,E,r)=>{for(const p of E)Pe(a,p,`groupBy(${c}, { by: [..."${p}"] })`);r.field!==void 0&&Pe(a,r.field,`groupBy(${c}, { agg: { op: "${r.op}", field: "${r.field}" } })`)},He="__cdc_sweep",Ct="global",zn=6e4,Qn=1e4,Jn=3e4;let pt=0;const Zn=async(a,c)=>{const{autoincrementPrimaryKey:E,key:r,real:p,text:w}=c.companionTypes;await M(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(P)} (${e.identifier("seq")} ${e.raw(E)}, ${e.identifier("ts")} ${e.raw(p)} NOT NULL, ${e.identifier("table")} ${e.raw(r)} NOT NULL, ${e.identifier("id")} ${e.raw(r)} NOT NULL, ${e.identifier("op")} ${e.raw(r)} NOT NULL, ${e.identifier("doc")} ${e.raw(w)})`);const d=c.indexKeyPrefix?.("string");await Nn(a,c,{columns:e`${d===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(d))})`}, ${e.identifier("seq")}`,name:mn,table:P,unique:!1}),await M(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(He)} (${e.identifier("id")} ${e.raw(r)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(p)} NOT NULL)`),await M(a,c,e`INSERT INTO ${e.identifier(He)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${Ct}, ${0}) ${c.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},ei=async(a,c,E)=>{const r=e`UPDATE ${e.identifier(He)} SET ${e.identifier("lease_until")} = ${E+zn} WHERE ${e.identifier("id")} = ${Ct} AND ${e.identifier("lease_until")} <= ${E}`;if(c.supportsReturning)return(await m(a,c,e`${r} RETURNING ${e.identifier("id")}`)).length>0;const p=await M(a,c,r);return(c.affectedRows?c.affectedRows(p??{rowsAffected:0}):0)>0},ti=async(a,c,E,r)=>{if(!await ei(a,c,r))return;const p=r-E;await M(a,c,e`
2
+ DELETE FROM ${e.identifier(P)} WHERE ${e.identifier("seq")} IN (
3
+ SELECT ${e.identifier("seq")} FROM (
4
+ SELECT ${e.identifier("seq")} FROM ${e.identifier(P)} WHERE ${e.identifier("ts")} <= ${p} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(Qn))}
5
+ ) AS ${e.identifier("expired")}
6
+ )
7
+ `)},At=async(a,c)=>{const E=await m(a,c,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(P)}`),r=Number(E[0]?.seq??Number.NaN);return Number.isFinite(r)?r:void 0},ni=async(a,c)=>{if(c.name!=="sqlite")return;const E=await m(a,c,e`SELECT ${e.identifier("seq")} AS ${e.identifier("seq")} FROM ${e.identifier("sqlite_sequence")} WHERE ${e.identifier("name")} = ${P}`),r=Number(E[0]?.seq??Number.NaN);return Number.isFinite(r)?r:0},ii=a=>JSON.stringify(Cn(a)?An(a):a),oi=async(a,c,E,r,p,w,d)=>{await M(a,d,e`INSERT INTO ${e.identifier(P)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${c}, ${E}, ${r}, ${p}, ${w===void 0?null:ii(w)})`)},yi=async(a,c,E)=>{const r=c.sinceSeq??0,p=Math.max(1,Math.min(c.limit??1e3,1e4)),w=await At(a,E),d=await ni(a,E);if(d!==void 0&&r>d)throw en(d,r,"global");if(w!==void 0&&tn(w,r))throw nn(w,r,"global");const g=(await m(a,E,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(P)} WHERE seq > ${r} ORDER BY seq ASC LIMIT ${e.raw(String(p))}`)).map(T=>{const{doc:b}=T,C={id:String(T.id),op:String(T.op),seq:Number(T.seq),table:String(T.table),ts:Number(T.ts)};return typeof b=="string"?{...C,doc:gt(JSON.parse(b))}:C});return{changes:g,cursor:g.at(-1)?.seq??r}},ri=async(a,c,E,r={})=>{if(r.cursorOnly){const g=await m(a,E,e`SELECT MAX(seq) AS seq FROM ${e.identifier(P)}`),T=Number(g[0]?.seq??c);return{cursor:Number.isFinite(T)?T:c,tables:[]}}const p=await m(a,E,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(P)} WHERE seq > ${c} GROUP BY ${e.identifier("table")}`);let w=c;const d=[];for(const g of p){const T=Number(g.seq);Number.isFinite(T)&&T>w&&(w=T),d.push(String(g.table))}const L=r.retained===!0?await At(a,E):void 0;return{cursor:w,tables:d,...L===void 0?{}:{floor:L}}},si=/string or blob too big/iu,ai=/row is too big/iu,ci=(a,c)=>{const{code:E,errno:r}=c,p=c instanceof Error?c.message:"";switch(a.name){case"mysql":return r===1118||E==="ER_TOO_BIG_ROWSIZE"?"InnoDB's per-row ceiling — roughly 8 KB, half a 16 KB page, for the part of the row stored inline":void 0;case"postgres":return ai.test(p)?"the 8 KB heap page a tuple must fit once its wide columns have been TOASTed out":void 0;default:return si.test(p)?"the storage engine's per-row ceiling (2 MB on D1)":void 0}},di=(a,c,E)=>{const r=ci(a,c);if(r!==void 0)throw new v("PAYLOAD_TOO_LARGE",`document is too large to store in "${E}": a single row cannot exceed ${r}. The limit is on the STORED bytes, which are UTF-8. Keep the payload in R2 (ctx.storage) and store a reference on the row.`)},Rt=(a,c,E)=>{throw a.isUniqueViolation(c)?new Le(`unique constraint violation on "${E}"`,"unique"):(di(a,c,E),c)},xe=new WeakMap,pi=a=>{const{crossShardCounter:c,crossShardReader:E,exec:r,maxRelationKeys:p,schema:w}=a,{dialect:d}=a,L={fieldRef:F,...d.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...d.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...d.name==="sqlite"?{}:{inList:Jt}},g=new WeakMap,T=t=>{const n=g.get(t);if(n!==void 0)return n;const i={...L,serialize:(o,s)=>J(t,s,o)};return g.set(t,i),i},b=(t,n)=>Ke(d.name,t,n),C=t=>{const n=Z(t.columns),i=ne(t.values),o=u=>d.name==="mysql"?e`VALUES(${e.identifier(u)})`:e`excluded.${e.identifier(u)}`,s=u=>d.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(u)}`:e`${e.identifier(u)}`,l=e.join(Object.entries(t.set(o,s)).map(([u,y])=>e`${e.identifier(u)} = ${y}`),e`, `),h=d.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${l}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${l}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${i}) ${h}`},N=a.clock??(()=>Date.now()),W=a.idGenerator??(()=>crypto.randomUUID()),G=a.cdc??!1,V=typeof a.cdcRetentionMs=="number"&&Number.isFinite(a.cdcRetentionMs)&&a.cdcRetentionMs>0?a.cdcRetentionMs:void 0,ie=a.auth??{identity:null,userId:null},oe=async(t,n,i,o)=>{if(!G||(await oi(r,N(),t,n,i,o,d),V===void 0))return;const s=N();if(!(s-pt<Jn)){pt=s;try{await ti(r,d,V,s)}catch{}}},Lt=a.scheduler??Zt,ke=Un();let Re=0;const Me=a.provisionScope??{},U=async()=>{const t=xe.get(Me);if(t)return t;const n=(async()=>{await Ln(r,w,d),await kn(r,w,d),await Mn(r,w,d),await xt(r,d),await Kt(r,w,d),G&&await Zn(r,d)})().catch(i=>{throw xe.delete(Me),i});return xe.set(Me,n),n},re=async(t,n)=>{await U();const i=await xn(r,d,w,t,ke);if(!(n!==void 0&&i!==n))return i},se=new Map,je=async(t,n)=>{const i=Q(t,n);return(await m(r,d,d.tableExists(i))).length>0},Se=async(t,n)=>{const i=`${t}::${n.name}`,o=se.get(i);if(o!==void 0)return o;if(!await je(t,n.name))return se.set(i,!1),!1;const l=w.tables[t];if(!l)return se.set(i,!1),!1;const h=n.by??[],u=new Map;await $t(r,d,l,t,$=>{if(n.where&&!Fe($,n.where))return;const _=Y(h,$);ut(u,_,n,$)});const y=Q(t,n.name);await M(r,d,e`DELETE FROM ${e.identifier(y)}`);const f=[];for(const[$,_]of u)f.push(e`INSERT INTO ${e.identifier(y)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${$}, ${_.value}, ${_.count})`);return await _t(r,d,f),se.set(i,!0),!0},kt=async(t,n,i,o)=>{const s=new Map;let l,h=!0;for(;h;){const u=l===void 0?o:[...o,e`${e.identifier("id")} > ${l}`],y=u.length>0?e` WHERE ${e.join(u,e` AND `)}`:e``,f=await m(r,d,e`SELECT ${e.identifier("id")}, ${F(i.field??"")} FROM ${e.identifier(n)}${y} ORDER BY ${e.identifier("id")} ASC LIMIT ${e.raw(String(Ue))}`);for(const $ of ft(t,f))ut(s,"",i,$);l=f.at(-1)?.id,h=f.length===Ue}return s.get("")?.value??null},Mt=async(t,n,i)=>{const o=n.field??"",s=[],l=w.tables[t],h=($,_)=>l?J(l,$,_):We(_);for(const $ of n.by??[]){const _=h($,i[$]??null);s.push(_===null?e`${F($)} IS NULL`:e`${F($)} = ${_}`)}for(const[$,_]of Object.entries(n.where??{})){const R=_!==null&&typeof _=="object"&&!Array.isArray(_)?_.eq:_,S=h($,R);s.push(S===null?e`${F($)} IS NULL`:e`${F($)} = ${S}`)}const u=s.length>0?e` WHERE ${e.join(s,e` AND `)}`:e``;if(l&&It(l.shape[o]))return kt(l,t,n,s);const y=$e(n.op),f=await m(r,d,e`SELECT ${e.raw(y)}(${F(o)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}${u}`);return te(f[0]?.value)},Nt=async(t,n)=>{await M(r,d,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},qt=async(t,n,i,o)=>{const s=Q(t,n.name),{op:l}=n,h=n.field??"",u=i&&(!n.where||Fe(i,n.where))?i:void 0,y=o&&(!n.where||Fe(o,n.where))?o:void 0;if(!(!u&&!y)){if(l==="count"||l==="sum"||l==="avg"){const f=new Set;for(const[$,_]of[[u,-1],[y,1]]){if(!$)continue;const R=l==="count"?1:Oe($[h]);if(R===void 0)continue;const S=Y(n.by??[],$);f.add(S),await M(r,d,C({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(I,A)=>({__count__:e`${A("__count__")} + ${I("__count__")}`,__value__:l==="count"?e`${A("__value__")} + ${I("__value__")}`:e`COALESCE(${A("__value__")}, 0) + ${I("__value__")}`}),table:s,values:[S,_*R,_]}))}for(const $ of f)await Nt(s,$);return}if(u){const f=Y(n.by??[],u),$=Oe(u[h]),R=(await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${f}`))[0],S=te(R?.value),I=(R?.count??0)-1;if(I<=0)await M(r,d,e`DELETE FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${f}`);else if(R&&$!==void 0&&S!==null&&$===S){const A=await Mt(t,n,u);await M(r,d,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__value__")} = ${A}, ${e.identifier("__count__")} = ${I} WHERE ${e.identifier("__key__")} = ${f}`)}else await M(r,d,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${f}`)}if(y){const f=Y(n.by??[],y),$=Oe(y[h]);if($===void 0)await M(r,d,C({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(_,R)=>({__count__:e`${R("__count__")} + 1`}),table:s,values:[f,null,1]}));else{const _=l==="min"?"MIN":"MAX";await M(r,d,C({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(R,S)=>({__count__:e`${S("__count__")} + 1`,__value__:e`${e.raw(_)}(COALESCE(${S("__value__")}, ${R("__value__")}), ${R("__value__")})`}),table:s,values:[f,$,1]}))}}}},ge=async t=>{const n=w.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const i of n)await Se(t,i)},ae=async(t,n,i)=>{const o=w.tables[t]?.aggregateIndexes;if(!(!o||o.length===0))for(const s of o){const l=`${t}::${s.name}`;(se.get(l)??await je(t,s.name))&&await qt(t,s,n,i)}},ce=new Map,Ge=async(t,n)=>{const i=we(t,n);return(await m(r,d,d.tableExists(i))).length>0},Ne=async(t,n)=>{const i=`${t}::rank::${n.name}`,o=ce.get(i);if(o!==void 0)return o;if(!await Ge(t,n.name))return ce.set(i,!1),!1;const l=w.tables[t];if(!l)return ce.set(i,!1),!1;const h=we(t,n.name);await M(r,d,e`DELETE FROM ${e.identifier(h)}`);const u=n.sortBy.map((_,R)=>ye(R)),y=Z(["__id__","__partition__",...u]);let f=[];const $=async()=>{if(f.length===0)return;const _=f;f=[],await _t(r,d,_)};return await $t(r,d,l,t,async _=>{if(n.where&&!lt(_,n.where))return;const R=Ae(n.partitionBy??[],_),S=n.sortBy.map(I=>We(_[I.field]??null));f.push(e`INSERT INTO ${e.identifier(h)} (${y}) VALUES (${ne([_._id,R,...S])})`),f.length>=Ue&&await $()}),await $(),ce.set(i,!0),!0},ve=async t=>{const n=w.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const i of n)await Ne(t,i)},X=async(t,n,i,o)=>{const s=w.tables[t],l=s?.rankIndexes;if(!l||l.length===0)return;const h=s?.softDeleteMode?.field,u=h===void 0||o===void 0?void 0:o[h],y=u!=null;for(const f of l){if(i!==void 0&&o!==void 0&&Hn(f,i,o))continue;const $=`${t}::rank::${f.name}`;if(!(ce.get($)??await Ge(t,f.name)))continue;const S=we(t,f.name);if(i&&await M(r,d,e`DELETE FROM ${e.identifier(S)} WHERE ${e.identifier("__id__")} = ${n}`),o&&!y){if(f.where&&!lt(o,f.where))continue;const I=f.sortBy.map((D,j)=>ye(j)),A=Z(["__id__","__partition__",...I]),O=Ae(f.partitionBy??[],o),k=f.sortBy.map(D=>We(o[D.field]??null));await M(r,d,e`INSERT INTO ${e.identifier(S)} (${A}) VALUES (${ne([n,O,...k])})`)}}},de=Ht({dialect:d,exec:r,schema:w}),Ve=new Set;for(const[t,n]of Object.entries(w.tables))for(const i of Object.values(n.triggerMap??{}))Ve.add(`${t} ${i.timing} ${i.op}`);const H=(t,n,i)=>Ve.has(`${t} ${n} ${i}`);let Ye;const K=async(t,n,i)=>{if(Re+=1,Re>Et)throw Re-=1,new Le(`trigger recursion exceeded ${String(Et)} levels on "${i.table}" — check for a self-triggering write`,"trigger");try{await Rn({ctx:Ye,event:i,op:n,schema:w,tableName:i.table,timing:t})}finally{Re-=1}},Dt=async(t,n)=>{try{await M(r,d,n)}catch(i){Rt(d,i,t)}},Te=async(t,n)=>(await m(r,d,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],me=async(t,n,i,o)=>{if(o===void 0)return;const s=e`${e.identifier(Ee)}`,l=e.join([b(e`${e.identifier("id")}`,o.id),b(s,o[Ee]??null)],e` AND `),h=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${i}, ${s} = ${wt.sql(s)} WHERE ${l}`:e`DELETE FROM ${e.identifier(t)} WHERE ${l}`,u=()=>{throw new Le(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(d.supportsReturning)(await m(r,d,e`${h} RETURNING ${e.identifier("id")}`)).length===0&&u();else{const y=await M(r,d,h);(d.affectedRows?d.affectedRows(y??{rowsAffected:0}):0)===0&&u()}}catch(y){Rt(d,y,t)}},qe=(t,n=t?._creationTime)=>({_creationTime:n,[Ee]:wt.value(t?.[Ee])}),Bt=(t,n,i,o)=>{const s=Object.keys(t.shape);return{columns:["id","_creationTime",...s],values:[n,i,...s.map(l=>J(t,l,o[l]??null))]}},Ft=async(t,n,i,o)=>{const s=gn(n,i.op,i.field,o.by,o.where);if(!s||!await Se(t,s.index))return;const h=Q(t,s.index.name),u=Object.keys(s.partial);if(u.length===(s.index.by??[]).length&&u.length>0){const f=Y(s.index.by??[],s.partial),$=await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(h)} WHERE ${e.identifier("__key__")} = ${f}`);if($.length===0)return[];const _=$[0];return[{key:{...s.partial},value:Be(i.op,{count:_.count,value:te(_.value)})}]}return u.length>0?void 0:(await m(r,d,e`SELECT ${e.identifier("__key__")} AS ${e.identifier("key")}, ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(h)}`)).map(f=>{const $=f;return{key:gt(JSON.parse($.key)),value:Be(i.op,{count:$.count,value:te($.value)})}})},Xe=t=>{const n=w.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},ze=t=>{throw new v("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`)},Ot=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new v("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 i={};if(n?.relationBaseWhere)for(const o of Object.keys(w.tables)){const s=n.relationBaseWhere(o);s!==void 0&&(i[o]=s)}return{orderBy:n?.orderBy,relationPolicies:i,where:B(n?.baseWhere,n?.where),with:n?.with}},Qe=(t,n)=>Xe(t)?E?E(t,Ot(t,n)):ze(t):x.findMany(t,n),be=(t,n,i)=>st(t,{fetcher:Qe,maxRelationKeys:p,relationBaseWhere:i,schema:w,tableName:n}),Wt=Dn(async(t,n)=>{const i=await m(r,d,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${ne(n)})`),o=new Map;for(const s of i){const{id:l}=s;typeof l=="string"&&o.set(l,s)}return o}),x={async cdcChangedTables(t,n){if(G)try{return await U(),await ri(r,t,d,{...n,retained:V!==void 0})}catch{return}},async aggregate(t,n){const i=w.tables[t];if(!i)throw new v("INTERNAL",`unknown table: ${t}`);if(await U(),$e(n.op),n.op==="count")return x.count(t,{baseWhere:n.baseWhere,relationBaseWhere:n.relationBaseWhere,restrictsCounts:n.restrictsCounts,where:n.where});if(!n.field)throw new v("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const o=_e(i.softDeleteMode,void 0),s=B(B(n.baseWhere,n.where),o),l=await be(s,t,n.relationBaseWhere),h=l!==s;if(i.aggregateIndexes&&!n.baseWhere&&!h&&!o){const R=pn(i.aggregateIndexes,n.op,n.field,n.where);if(R&&await Se(t,R.index)){const I=Y(R.index.by??[],R.key),A=Q(t,R.index.name),k=(await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(A)} WHERE ${e.identifier("__key__")} = ${I}`))[0];return Be(n.op,k===void 0?void 0:{count:k.count,value:te(k.value)})}}Pe(i,n.field,`aggregate(${t}, { op: "${n.op}", field: "${n.field}" })`);const u=he(l,T(i)),y=e.raw($e(n.op)),f=e`SELECT ${y}(${F(n.field)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}`,_=(await m(r,d,u?e`${f} WHERE ${u}`:f))[0]?.value;return _==null?null:Number(_)},async count(t,n){const i=w.tables[t];if(!i)throw new v("INTERNAL",`unknown table: ${t}`);await U();const o=En(n);if(o.restrictsCounts)throw new rt(t);const s=_e(i.softDeleteMode,void 0),l=B(B(o.baseWhere,o.where),s),h=await be(l,t,o.relationBaseWhere),u=h!==l;if(i.aggregateIndexes&&!o.baseWhere&&!u&&!s){const _=yn(i.aggregateIndexes,o.where);if(_&&await Se(t,_.index)){const S=Y(_.index.by??[],_.key),I=Q(t,_.index.name),A=await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")} FROM ${e.identifier(I)} WHERE ${e.identifier("__key__")} = ${S}`);return Number(A[0]?.value??0)}}const y=he(h,T(i)),f=e`SELECT COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(t)}`,$=await m(r,d,y?e`${f} WHERE ${y}`:f);return Number($[0]?.count??0)},async delete(t,n,i){const o=await re(t,n);if(!o)return;const s=w.tables[o];if(!s)return;const l=await Te(o,t),h=ee(s,l),u=i?.hard===!0,y=!u&&s.softDeleteMode?s.softDeleteMode.field:void 0;if(!(y&&(!h||h[y]!==null&&h[y]!==void 0))){if(H(o,"before","delete")&&await K("before","delete",{id:t,op:"delete",previous:h??void 0,table:o}),await hn({deletedId:t,deletedReference:f=>h?.[f],findHolders:async(f,$,_)=>{if(w.tables[f]?.shardMode?.kind==="shardBy")throw new v("INTERNAL",`cross-backend cascade from global '${o}' into shardBy '${f}' is not supported — would require Query Coordinator fan-out across shards`);return(await x.findMany(f,{includeDeleted:u,where:{[$]:_}})).page},onCascade:(f,$)=>x.delete($,void 0,i),onRestrict:f=>{throw new Le(f,"restrict")},onSetNull:(f,$,_)=>x.patch($,{[_]:null}),schema:w,tableName:o}),await ge(o),await ve(o),y&&h){const f={...h,[y]:N()},$=e.join(Object.keys(s.shape).map(_=>e`${e.identifier(_)} = ${J(s,_,f[_]??null)}`),e`, `);await me(o,"UPDATE",$,l),await ae(o,h,f),await X(o,t,h,void 0),await de(o,t,{document:f,previous:h,written:qe(l)}),await oe(o,t,"update",f),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:h,table:o});return}await me(o,"DELETE",void 0,l),ke.delete(t),await ae(o,h??void 0,void 0),await X(o,t,h??void 0,void 0),await de(o,t,void 0),await oe(o,t,"delete"),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:h??void 0,table:o})}},async findFirst(t,n={}){return(await x.findMany(t,{...n,limit:1})).page[0]??null},async findFirstOrThrow(t,n={}){const i=await x.findFirst(t,n);if(i===null)throw new _n(`findFirstOrThrow: no "${t}" document matched`);return i},async findMany(t,n={}){const i=w.tables[t];if(!i)throw new v("INTERNAL",`unknown table: ${t}`);await U();const o=dn(n.orderBy,i.shape,{pinned:un(n.where),uniqueBy:ln(i.indexes,i.shape)}),s=n.cursor?fn(o,wn(n.cursor)):void 0,l=Qe,h=async(k,D,j,Ie)=>{if(Xe(k))return c?Tn(c,k,D,j,Ie):ze(k);const le=w.tables[k];if(!le)throw new v("INTERNAL",`unknown table: ${k}`);const Ce=_e(le.softDeleteMode,void 0),z={[D]:{in:j}},q=B(B(z,Ie),Ce),ue=await be(q,k,void 0),Je=he(ue,T(le)),Ze=F(D);let fe=e`SELECT ${Ze} AS __fk__, COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(k)}`;Je&&(fe=e`${fe} WHERE ${Je}`),fe=e`${fe} GROUP BY ${Ze}`;const Ut=await m(r,d,fe),et=new Map;for(const tt of Ut)et.set(tt.__fk__,Number(tt.count??0));return et};let u=B(n.baseWhere,n.where);u=B(u,_e(i.softDeleteMode,n.includeDeleted)),u=await st(u,{fetcher:l,maxRelationKeys:p,relationBaseWhere:n.relationBaseWhere,schema:w,tableName:t}),s&&(u=u?{AND:[u,s]}:s);const y=he(u,T(i)),f=Fn(o,d);let $=e`SELECT * FROM ${e.identifier(t)}`;y&&($=e`${$} WHERE ${y}`),$=e`${$} ORDER BY ${f}`;const _=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;_!==void 0&&($=e`${$} LIMIT ${e.raw(String(_+1))}`);const R=await m(r,d,$),S=ft(i,R);if(_===void 0)return n.with&&await at({fetcher:l,groupedCounter:h,parents:S,...ct(n),schema:w,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:dt(S,n.select,n.with)};const I=S.length>_,A=I?S.slice(0,_):S,O=A.at(-1);return n.with&&await at({fetcher:l,groupedCounter:h,parents:A,...ct(n),schema:w,tableName:t,with:n.with}),{continueCursor:I&&O?$n(O,o):null,isDone:!I,page:dt(A,n.select,n.with)}},async get(t,n){const i=await re(t,n);if(!i)return null;const o=w.tables[i];return o?ee(o,await Wt.load(i,t)):null},async groupBy(t,n){const i=w.tables[t];if(!i)throw new v("INTERNAL",`unknown table: ${t}`);await U();const o=n.agg??{op:"count"};if($e(o.op),o.op!=="count"&&!o.field)throw new v("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);const s=_e(i.softDeleteMode,void 0),l=B(B(n.baseWhere,n.where),s),h=await be(l,t,n.relationBaseWhere),u=h!==l;if(i.aggregateIndexes&&!n.baseWhere&&!u&&!s){const S=await Ft(t,i.aggregateIndexes,o,n);if(S!==void 0)return S}Xn(i,t,n.by,o);const y=he(h,T(i)),f=n.by.map(S=>e`${F(S)} AS ${e.identifier(S)}`);if(o.op==="count")f.push(e`COUNT(*) AS ${e.identifier("value")}`);else{if(!o.field)throw new v("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);f.push(e`${e.raw($e(o.op))}(${F(o.field)}) AS ${e.identifier("value")}`)}const $=e.join(n.by.map(S=>F(S)),e`, `);let _=e`SELECT ${e.join(f,e`, `)} FROM ${e.identifier(t)}`;y&&(_=e`${_} WHERE ${y}`),_=e`${_} GROUP BY ${$}`;const R=await m(r,d,_);return Pn(i,n.by,R)},async insert(t,n,i){const o=w.tables[t];if(!o)throw new v("INTERNAL",`unknown table: ${t}`);await U();const s=On(o,n,ie);De(o,s);let l,h=!0;i?.clientId!==void 0?(cn(i.clientId),l=i.clientId):i?.allowExplicitId&&typeof s._id=="string"?l=s._id:(l=W(),h=!1);const u=i?.allowExplicitId&&typeof s._creationTime=="number"?s._creationTime:N(),y={...s,_creationTime:u,_id:l};H(t,"before","insert")&&await K("before","insert",{doc:{...y},id:l,op:"insert",table:t}),await ge(t),await ve(t);const{columns:f,values:$}=Bt(o,l,u,s);return await Dt(t,e`INSERT INTO ${e.identifier(t)} (${Z(f)}) VALUES (${ne($)})`),h&&ke.set(l,t),await ae(t,void 0,y),await X(t,l,void 0,y),await de(t,l,{document:y,written:{_creationTime:u,[Ee]:null}}),await oe(t,l,"insert",y),H(t,"after","insert")&&await K("after","insert",{doc:y,id:l,op:"insert",table:t}),l},normalizeId(t,n){return an(w,t,n)},async patch(t,n,i){nt("patch",n);const o=await re(t,i);if(!o)throw new v("INTERNAL",`document not found: ${t}`);const s=w.tables[o];if(!s)throw new v("INTERNAL",`document not found: ${t}`);const l=await Te(o,t),h=ee(s,l);if(!h)throw new v("INTERNAL",`document not found: ${t}`);const u={...h,...sn(n),_id:t};yt(s,n,u,ie),De(s,u,!0),H(o,"before","update")&&await K("before","update",{doc:{...u},id:t,op:"update",previous:h,table:o}),await ge(o),await ve(o);const y=Object.keys(s.shape),f=e.join(y.map($=>e`${e.identifier($)} = ${J(s,$,u[$]??null)}`),e`, `);await me(o,"UPDATE",f,l),await ae(o,h,u),await X(o,t,h,u),await de(o,t,{document:u,previous:h,written:qe(l)}),await oe(o,t,"update",u),H(o,"after","update")&&await K("after","update",{doc:u,id:t,op:"update",previous:h,table:o})},async restore(t,n){const i=await re(t,n);if(!i)throw new v("INTERNAL",`document not found: ${t}`);const o=w.tables[i],s=o?.softDeleteMode?.field;if(!o||!s)throw new v("INTERNAL",`ctx.db.restore: table "${i}" is not a .softDelete() table`);const l=await Te(i,t),h=l?.[s]!==null&&l?.[s]!==void 0;if(await x.patch(t,{[s]:null},n),h){const u=ee(o,l);u!==null&&await X(i,t,void 0,{...u,[s]:null})}},query(t){const n=w.tables[t];if(!n)throw new v("INTERNAL",`unknown table: ${t}`);const i="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",o=[],s=u=>o.every(y=>y(u)),l=async(u,y)=>{await U();const f=o.length>0,$=await Yt(r,d,n,t,u,Xt(f?void 0:y));if(!f)return y===void 0&&zt($),$;const _=$.filter(R=>s(R));return y===void 0?_:_.slice(0,y)},h=u=>{const y={async*[Symbol.asyncIterator](){if(!u)throw new v("INTERNAL",i);yield*await l(u,void 0)},async collect(){if(!u)throw new v("INTERNAL",i);return l(u,void 0)},async collectWithScores(){throw new v("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(f){return o.push(f),y},async first(){if(!u)throw new v("INTERNAL",i);return(await l(u,1))[0]??null},order(){return y},async paginate(f){if(!u)throw new v("INTERNAL",i);const $=Gt(f);return Vt(await l(u,Qt($)),$)},async take(f){if(!u)throw new v("INTERNAL",i);return l(u,f)},async unique(){if(!u)throw new v("INTERNAL",i);const f=await l(u,2);if(f.length>1)throw new bn(`unique() on table "${t}" matched ${String(f.length)} documents; expected at most one`);return f[0]??null},withGeoIndex(){throw new v("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new v("INTERNAL",i)},withSearchIndex(f,$){const _=(n.searchIndexes??[]).find(S=>S.name===f);if(!_)throw new v("INTERNAL",`unknown search index "${f}" on table "${t}"`);const R={definition:_,field:_.field,filters:[],hasQuery:!1,indexName:f,query:""};if($(jt(R,t,Pt(_.language))),!R.hasQuery)throw new v("INTERNAL",`search index "${f}" on table "${t}" requires a .search(field, query) call`);return h(R)}};return y};return h(void 0)},async rank(t,n,i){const o=w.tables[t];if(!o)throw new v("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(D=>D.name===n);if(!s)throw new v("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(i.restrictsCounts)throw new rt(t);if(await U(),!await Ne(t,s))return null;const h=typeof i.row=="string"?i.row:i.row._id;if(!h)return null;const u=we(t,s.name),y=s.sortBy.map((D,j)=>ye(j)),f=Z(["__partition__",...y]),_=(await m(r,d,e`SELECT ${f} FROM ${e.identifier(u)} WHERE ${e.identifier("__id__")} = ${h}`))[0];if(!_)return null;const R=_.__partition__,S=B(i.baseWhere,i.where);it(S,w,t,"rank");const I=ot(s,S);if(I&&Ae(s.partitionBy??[],I)!==R)return null;const A=Kn(d.name,s,y,_,h),O=await m(r,d,e`SELECT COUNT(*) AS c FROM ${e.identifier(u)} WHERE ${e.identifier("__partition__")} = ${R} AND (${A})`),k=await m(r,d,e`SELECT COUNT(*) AS c FROM ${e.identifier(u)} WHERE ${e.identifier("__partition__")} = ${R}`);return{position:Number(O[0]?.c??0)+1,total:Number(k[0]?.c??0)}},async rankPage(t,n,i={}){it(B(i.baseWhere,i.where),w,t,"rankPage");const o=w.tables[t];if(!o)throw new v("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(q=>q.name===n);if(!s)throw new v("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await U(),!await Ne(t,s))return{continueCursor:null,isDone:!0,page:[]};const h=we(t,s.name),u=s.sortBy.map((q,ue)=>ye(ue)),y=Math.max(1,Math.min(1e3,Math.floor(i.take??100))),f=B(i.baseWhere,i.where),$=ot(s,f),_=Gn(s,u),R=e.join(_.map(q=>e`${e.identifier(q.column)} ${e.raw(`${q.direction==="desc"?"DESC":"ASC"}${mt(d,{direction:q.direction,nullable:q.nullable})}`)}`),e`, `),S=[];typeof i.partitionKey=="string"?S.push(e`${e.identifier("__partition__")} = ${i.partitionKey}`):$&&S.push(e`${e.identifier("__partition__")} = ${Ae(s.partitionBy??[],$)}`);const I=rn(i);if(I!==void 0){const q=jn(d.name,_,I);q!==void 0&&S.push(q)}const A=Z([pe,"__partition__",...u]);let O=e`SELECT ${A} FROM ${e.identifier(h)}`;S.length>0&&(O=e`${O} WHERE ${e.join(S,e` AND `)}`),O=e`${O} ORDER BY ${R} LIMIT ${e.raw(String(y+1))}`;const k=await m(r,d,O),D=k.length>y,j=D?k.slice(0,y):k,Ie=j.map(q=>q[pe]),le=await Vn(r,d,o,t,Ie);let Ce=null;const z=j.at(-1);if(D&&z!==void 0){const q=[z.__partition__,...u.map(ue=>z[ue]),z[pe]];Ce=Yn(q)}return{continueCursor:Ce,isDone:!D,page:le}},async replace(t,n,i,o){nt("replace",n);const s=await re(t,i);if(!s)throw new v("INTERNAL",`document not found: ${t}`);const l=w.tables[s];if(!l)throw new v("INTERNAL",`document not found: ${t}`);const h=await Te(s,t);if(h===void 0)throw new v("INTERNAL",`document not found: ${t}`);const y=on(w,s,"update")||(l.aggregateIndexes??[]).length>0||(l.rankIndexes??[]).length>0?ee(l,h)??void 0:void 0,f=o?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:void 0,$=typeof h._creationTime=="number"?h._creationTime:void 0,_=f??$??N(),R={...n,_creationTime:_,_id:t};yt(l,n,R,ie),De(l,R),H(s,"before","update")&&await K("before","update",{doc:{...R},id:t,op:"update",previous:y,table:s}),await ge(s),await ve(s);const S=Object.keys(l.shape),I=e.join([e`${e.identifier("_creationTime")} = ${_}`,...S.map(A=>e`${e.identifier(A)} = ${J(l,A,R[A]??null)}`)],e`, `);await me(s,"UPDATE",I,h),await ae(s,y,R),await X(s,t,y,R),await de(s,t,{document:R,previous:y,written:qe(h,_)}),await oe(s,t,"update",R),H(s,"after","update")&&await K("after","update",{doc:R,id:t,op:"update",previous:y,table:s})}};return Ye={db:x,scheduler:Lt},x};export{gi as backfillSqlSearchIndexes,pi as createSqlCtxDb,Ti as decodeGlobalRow,ri as readSqlCdcChangedTables,yi as readSqlCdcChanges,At as readSqlCdcFloor,Zn as runSqlCdcMigration,Kt as runSqlSearchMigrations,ti as sweepSqlCdcRetention};
@@ -0,0 +1 @@
1
+ import{LunoraError as g}from"@lunora/errors";import{D as C,c as vt,m as Dt,r as b,a as qt,l as St,w as q,b as Ft}from"./ctx-db-search-state-DGbsWTp6.mjs";import{ftsUnmappedPage as bt,groupUnmappedRows as Ut,ftsWriteDocument as Et,ftsPurgeDocument as lt,ftsCompanionDdl as kt,unionAll as Ht,ftsRowidMapName as Pt}from"@lunora/shard-engine";import{sql as i}from"drizzle-orm";import{OCC_VERSION_COLUMN as Bt,nullSafeEqualsSql as Wt,queryAll as h,decodeRow as Y,runInOrder as O,indexState as M,createIndexIfNotExists as Q,dropIndexIfExists as v,queryRun as p,decodeRows as mt,columnRefSql as et,serializeColumnValue as jt,readRowsPage as xt,forEachRowPaged as Kt}from"./decodeGlobalRow-VOl_TIbk.mjs";const Gt=n=>{const t=atob(n),e=Uint8Array.from(t,r=>r.codePointAt(0)??0);return new TextDecoder().decode(e)},Yt=()=>new g("BAD_REQUEST","invalid cursor"),it=16,rt=8,y=1024,U=(n,t)=>t.query(n),Qt=(n,t)=>{if(!t)return{exact:!0,lower:n,upper:n};const e=[...n].at(-1)??"",r=(e.codePointAt(0)??0)+1;if(r>=55296&&r<=57343||r>1114111)return{exact:!0,lower:n,upper:n};const o=n.slice(0,n.length-e.length);return{exact:!1,lower:n,upper:o+String.fromCodePoint(r)}},Cn=(n,t,e)=>{const r={eq:(o,s)=>{if(!n.definition.filterFields?.includes(o))throw new g("INTERNAL",`field "${o}" is not a filter field of search index "${n.indexName}" on table "${t}"`);if(n.filters.length>=rt)throw new g("BAD_REQUEST",`search index "${n.indexName}" on table "${t}": at most ${String(rt)} .eq() filters are supported per search query`);return n.filters.push({field:o,value:s}),r},search:(o,s)=>{const a=n;if(o!==a.definition.field)throw new g("INTERNAL",`search index "${a.indexName}" on table "${t}" indexes "${a.definition.field}", not "${o}"`);const f=U(s,e).length;if(f>it)throw new g("BAD_REQUEST",`search index "${a.indexName}" on table "${t}": at most ${String(it)} search terms are supported (got ${String(f)})`);return a.field=o,a.query=s,a.hasQuery=!0,r}};return r},Ln=n=>{if(n.length>y)throw new g("BAD_REQUEST",`more than ${String(y)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},Mn=n=>Math.min(n.offset+n.numItems+1,y),Vt=n=>btoa(`search:${String(n)}`),Xt=n=>{let t;try{t=Gt(n)}catch{return}if(!t.startsWith("search:"))return;const e=Number(t.slice(7));return Number.isInteger(e)&&e>=0?e:void 0},vn=n=>{if(typeof n.endCursor=="string")throw new g("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(n.numItems))throw new g("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(n.numItems)}`);const t=Math.max(0,Math.floor(n.numItems)),e=n.cursor?Xt(n.cursor):0;if(e===void 0)throw Yt();if(e+t>=y)throw new g("BAD_REQUEST",`search pagination reaches the ${String(y)}-document limit (offset ${String(e)} + ${String(t)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,y-e-1))} or fewer, or narrow the query or the filters instead`);return{numItems:t,offset:e}},Dn=(n,t)=>{const e=t.offset+t.numItems,r=t.numItems>0&&n.length>e;return{continueCursor:r?Vt(e):null,isDone:!r,page:n.slice(t.offset,e)}},qn=n=>{if(n===void 0)return y+1;if(!Number.isFinite(n))return y;const t=Math.max(0,Math.floor(n));if(t>y)throw new g("BAD_REQUEST",`search returns at most ${String(y)} documents (asked for ${String(t)}) — narrow the query or paginate instead`);return t},Jt=(n,t)=>{if(!t.includes("."))return n[t];let e=n;for(const r of t.split(".")){if(e===null||typeof e!="object"||Array.isArray(e))return;e=e[r]}return e},k=(n,t)=>`${n}__fts_${t}`,S="__id__",T="__token__",A="__n__",zt=1e3,ht=(n,t)=>t.document(n),j=(n,t)=>Jt(n,t),Zt=n=>typeof n=="string"?n:n==null?"":typeof n=="number"||typeof n=="bigint"||typeof n=="boolean"?String(n):JSON.stringify(n)??"",tn=(n,t,e)=>n!==void 0&&t!==void 0&&j(n,e.field)===j(t,e.field),nn=(n,t)=>ht(Zt(j(n,t.field)),C(t.language)).slice(0,zt),D=(n,t)=>nn(n,t).join(" "),pt=(n,t)=>{const e=new Map;for(const r of ht(n,t))e.set(r,(e.get(r)??0)+1);return e},gt=[Bt,"_creationTime"],ot=50,$=(n,t)=>i`${i.identifier(n)}.${i.identifier(t)}`,I=(n,t,e)=>i`DELETE FROM ${i.identifier(n)} WHERE ${$(n,S)} = ${t}${e===void 0?i``:i` AND ${e}`}`,Tt=(n,{row:t,table:e})=>{const r=gt.map(o=>i` AND ${Wt(n.name,$(e,o),t[o]??null)}`);return i`SELECT 1 FROM ${i.identifier(e)} WHERE ${$(e,"id")} = ${t.id}${i.join(r)}${n.name==="postgres"?i` FOR SHARE`:i``}`},F=(n,t)=>i`EXISTS (${Tt(n,t)})`,V=(n,t)=>i`NOT EXISTS (SELECT 1 FROM ${i.identifier(n)} WHERE ${$(n,"id")} = ${t})`,yt=(n,t,e,r)=>r===void 0?V(t,e):F(n,{row:r,table:t}),Rt=async(n,t,e,r)=>{const o=new Map;for(let s=0;s<r.length;s+=ot){const a=r.slice(s,s+ot),f=await h(n,t,i`SELECT * FROM ${i.identifier(e)} WHERE ${$(e,"id")} IN (${i.join(a.map(u=>i`${u}`),i`, `)})`);for(const u of f)o.set(String(u.id),u)}return o},x=(n,t,e)=>n.name==="mysql"?i`${i.identifier(t)}(${i.raw(String(e))})`:n.textPatternOperatorClass===void 0?i`${i.identifier(t)}`:i`${i.identifier(t)} ${i.raw(n.textPatternOperatorClass)}`,X=512,J=(n,t)=>({columns:i`${x(n,T,256)}, ${x(n,S,X)}`,concurrently:!0,name:`${t}__unique`,table:t,unique:!0}),B=n=>i`${n} COLLATE utf8mb4_0900_bin`,W=(n,t)=>{const e=JSON.stringify(t.map(([r,o])=>({o,t:r})));switch(n.name){case"mysql":return i`JSON_TABLE(${e}, '$[*]' COLUMNS (${i.identifier("t")} VARCHAR(256) PATH '$.t', ${i.identifier("o")} INT PATH '$.o')) AS ${i.identifier("j")}`;case"postgres":return i`json_to_recordset(${e}::json) AS ${i.identifier("j")}(${i.identifier("t")} text, ${i.identifier("o")} integer)`;default:return i`(SELECT json_extract(${$("e","value")}, '$.t') AS ${i.identifier("t")}, json_extract(${$("e","value")}, '$.o') AS ${i.identifier("o")} FROM json_each(${e}) AS ${i.identifier("e")}) AS ${i.identifier("j")}`}},_t=(n,t,e,r,o)=>{const s=i.join([T,S,A].map(f=>i.identifier(f)),i`, `),a=f=>i`INSERT INTO ${i.identifier(t)} (${s}) SELECT ${$("j","t")}, ${e}, ${$("j","o")} FROM ${W(n,r)} WHERE ${f}`;switch(n.name){case"mysql":{const f=F(n,o),u=$(t,T),c=i.identifier("held");return[i`${a(i`${f} AND NOT EXISTS (SELECT 1 FROM ${i.identifier(t)} AS ${c} WHERE ${$("held",S)} = ${e} AND ${$("held",T)} = ${B($("j","t"))})`)} ON DUPLICATE KEY UPDATE ${$(t,A)} = ${$(t,A)}`,i`UPDATE ${i.identifier(t)} JOIN ${W(n,r)} ON ${u} = ${B($("j","t"))} SET ${$(t,A)} = ${$("j","o")} WHERE ${$(t,S)} = ${e} AND ${f}`,i`DELETE FROM ${i.identifier(t)} WHERE ${$(t,S)} = ${e} AND ${f} AND ${u} NOT IN (SELECT ${B($("j","t"))} FROM ${W(n,r)})`]}case"postgres":{const f=i.identifier("__source__"),u=i.identifier("__purged__"),c=i`EXISTS (SELECT 1 FROM ${f})`;return[i`WITH ${f} AS (${Tt(n,o)}), ${u} AS (${I(t,e,c)} RETURNING 1) ${a(i`${c} AND (SELECT COUNT(*) FROM ${u}) >= 0`)} ON CONFLICT DO NOTHING`]}default:{const f=F(n,o);return[I(t,e,f),i`${a(f)} ON CONFLICT DO NOTHING`]}}},Nt={uniqueKeyMissing:!1,unmappedSkipped:0},st=new Set,at=(n,t)=>{st.has(n)||(st.add(n),console.warn(`[@lunora/sql-store] ${t}`))},ft=100,ut=3,K=async(n,t,e,r=0)=>{const{companion:o,definition:s,index:a,tableName:f}=e,u={done:!0,last:r,left:0};if((await h(n,t,t.tableExists(f))).length===0)return u;const d=await h(n,t,bt(o,ft,r));if(d.length===0)return u;const w=Math.max(...d.map(_=>Number(_.rowid))),l=Ut(d),E=await Rt(n,t,f,[...l.keys()]),m=[];for(const[_,Z]of l){const P=E.get(_),tt=P===void 0?void 0:Y(s,P),nt=yt(t,f,_,P);m.push(...tt?Et(o,_,D(tt,a),{guard:nt,unmappedRowids:Z}):lt(o,_,{guard:nt,unmappedRowids:Z}))}await O(n,t,m);const R=await h(n,t,i`SELECT COUNT(*) AS ${i.identifier("n")} FROM ${i.identifier(o)} WHERE ${$(o,"rowid")} > ${Math.max(0,r)} AND ${$(o,"rowid")} <= ${w}`);return{done:d.length<ft,last:w,left:Number(R[0]?.n??0)}},en=async(n,t,e)=>{let r=0,o=0;for(;;){let s=await K(n,t,e,r);for(let a=1;s.left>0&&a<ut;a+=1)s=await K(n,t,e,r);if(s.left>0&&(o+=s.left,console.warn(`[@lunora/sql-store] search migration of "${e.companion}": ${String(s.left)} row(s) lost every one of ${String(ut)} attempts to a concurrent write and were left for a later pass.`)),s.done)return o;r=s.last}},rn=async(n,t,e,r)=>r==="step"?(await K(n,t,e),Nt):{uniqueKeyMissing:!1,unmappedSkipped:await en(n,t,e)},G=n=>`${n}__btree`,on=async(n,t,e)=>{const r=J(t,e),o=await M(n,t,e,r.name);if(o!=="valid"){if(o==="absent"&&(await h(n,t,i`SELECT 1 AS ${i.identifier("present")} FROM ${i.identifier(e)} LIMIT 1`)).length===0)try{await Q(n,t,{...r,concurrently:!1}),await v(n,t,e,G(e));return}catch(a){if(await M(n,t,e,r.name).catch(()=>{})==="valid")return;at(`${e}:empty`,`search companion "${e}": adding its unique key failed (${String(a)}); run backfillSqlSearchIndexes.`);return}at(`${e}:missing`,`search companion "${e}" has no usable unique key, so two backfills racing over one row can index it twice. Run backfillSqlSearchIndexes, which adds it.`)}},sn=async(n,t,e)=>{const r=$(e,S),o=$(e,T);return(await h(n,t,i`SELECT ${r} AS ${i.identifier("id")}, ${o} AS ${i.identifier("token")}, COUNT(*) AS ${i.identifier("n")} FROM ${i.identifier(e)} GROUP BY ${r}, ${o} HAVING COUNT(*) > 1`)).map(a=>({count:Number(a.n),id:String(a.id),token:String(a.token)}))},an=(n,t,{count:e,id:r,token:o})=>{const s=i`${$(t,S)} = ${r} AND ${$(t,T)} = ${o}`;switch(n.name){case"mysql":return i`DELETE FROM ${i.identifier(t)} WHERE ${s} LIMIT ${i.raw(String(e-1))}`;case"postgres":return i`DELETE FROM ${i.identifier(t)} WHERE ctid = ANY (ARRAY(SELECT ctid FROM ${i.identifier(t)} WHERE ${s} OFFSET 1))`;default:return i`DELETE FROM ${i.identifier(t)} WHERE rowid IN (SELECT rowid FROM ${i.identifier(t)} WHERE ${s} LIMIT -1 OFFSET 1)`}},fn=async(n,t,e,r)=>{const{companion:o,definition:s,index:a,tableName:f}=e;for(const d of r)await p(n,t,an(t,o,d));const u=[...new Set(r.map(d=>d.id))],c=await Rt(n,t,f,u);for(const d of u){const w=c.get(d),l=w===void 0?void 0:Y(s,w);if(w!==void 0&&l){const E=[...pt(D(l,a),C(a.language))];await O(n,t,_t(t,o,d,E,{row:w,table:f}));continue}await p(n,t,I(o,d,yt(t,f,d,w)))}},un=async(n,t,e)=>t.name!=="mysql"?"":(await h(n,t,i`SELECT COLUMN_NAME AS ${i.identifier("name")}, COLLATION_NAME AS ${i.identifier("collation")} FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ${e} AND COLUMN_NAME IN (${T}, ${S})`)).filter(o=>!String(o.collation).endsWith("_bin")).map(o=>` Its ${String(o.name)} column uses ${String(o.collation)}, which treats values differing only in case or accents as one; convert it with ALTER TABLE \`${e}\` MODIFY \`${String(o.name)}\` VARCHAR(768) COLLATE utf8mb4_0900_bin NOT NULL.`).join(""),cn=async(n,t,e)=>{if(t.name!=="mysql")return 0;const r=$(e,S),o=await h(n,t,i`SELECT COUNT(*) AS ${i.identifier("n")} FROM (SELECT 1 AS ${i.identifier("x")} FROM ${i.identifier(e)} GROUP BY LEFT(${r}, ${i.raw(String(X))}), ${$(e,T)} HAVING COUNT(DISTINCT ${r}) > 1) AS ${i.identifier("shared")}`);return Number(o[0]?.n??0)},dn=async(n,t,e)=>{const r=J(t,e),o=await M(n,t,e,r.name);if(o==="valid")return"valid";o==="invalid"&&await v(n,t,e,r.name);try{return await Q(n,t,r),"built"}catch(s){const a=await M(n,t,e,r.name);if(a==="valid")return"valid";if(a==="invalid"&&await v(n,t,e,r.name),!t.isUniqueViolation(s))throw s;return"refused"}},ct=3,$n=async(n,t,e)=>{const{companion:r}=e,o=await un(n,t,r);let s="";o!==""&&console.warn(`[@lunora/sql-store] search companion "${r}" folds case and accents in its unique key.${o}`);for(let a=0;a<ct;a+=1){const f=await dn(n,t,r);if(f==="valid")return await v(n,t,r,G(r)),!0;if(f==="refused"){const u=await sn(n,t,r);if(u.length>0)await fn(n,t,e,u);else{const c=await cn(n,t,r);s=c>0?` ${String(c)} token(s) are held by document ids that agree on their first ${String(X)} characters, which the key cannot tell apart; shorten those ids.`:o}}}return await M(n,t,r,J(t,r).name)==="valid"?(await v(n,t,r,G(r)),!0):(console.warn(`[@lunora/sql-store] search companion "${r}" still has no unique key after ${String(ct)} attempts: writes keep working, but two backfills racing over one row can index it twice.${s}`),!1)},wn=async(n,t,e,r)=>r==="step"?Nt:{uniqueKeyMissing:!await $n(n,t,e),unmappedSkipped:0},Sn=(n,t)=>t?i`${i.identifier(T)} LIKE ${`${n}%`}`:i`${i.identifier(T)} = ${n}`,At=(n,t)=>{const e=t.filters.map(r=>i`m.${et(r.field)} = ${jt(r.value)}`);return n.softDeleteMode&&e.push(i`m.${et(n.softDeleteMode.field)} IS NULL`),e},Ot=async(n,t,e,r,o,s,a)=>{const f=At(e,o);let u=i`SELECT m.* FROM (${a}) s JOIN ${i.identifier(r)} m ON m.${i.identifier("id")} = s.${i.identifier(S)}`;return f.length>0&&(u=i`${u} WHERE ${i.join(f,i` AND `)}`),u=i`${u} ORDER BY s.${i.identifier("__score__")} DESC, m.${i.identifier("_creationTime")} DESC, m.${i.identifier("id")} ASC LIMIT ${i.raw(String(s))}`,mt(e,await h(n,t,u))},En=async(n,t,e,r,o,s)=>{const a=U(o.query,C(o.definition.language));if(a.length===0)return[];const f=k(r,o.indexName),u=a.length-1,c=a.map((m,R)=>Sn(m,R===u)),d=i.join(c,i` OR `),w=c.map(m=>i`SUM(CASE WHEN ${m} THEN ${i.identifier(A)} ELSE 0 END)`),l=i.join(w.map(m=>i`${m} > 0`),i` AND `),E=i`SELECT ${i.identifier(S)}, ${i.join(w,i` + `)} AS ${i.identifier("__score__")} FROM ${i.identifier(f)} WHERE ${d} GROUP BY ${i.identifier(S)} HAVING ${l}`;return Ot(n,t,e,r,o,s,E)},ln=async(n,t,e,r,o,s)=>{const a=U(o.query,C(o.definition.language));if(a.length===0)return[];const f=k(r,o.indexName),u=`${f}__vocab`,c=a.length-1,d=a.map((E,m)=>{const R=Qt(E,m===c),_=R.exact?i`${i.identifier("term")} = ${R.lower}`:i`${i.identifier("term")} >= ${R.lower} AND ${i.identifier("term")} < ${R.upper}`;return i`SELECT ${i.identifier("doc")}, ${i.raw(String(m))} AS ${i.identifier("__term__")}, COUNT(*) AS ${i.identifier("__n__")} FROM ${i.identifier(u)} WHERE ${_} GROUP BY ${i.identifier("doc")}`}),w=a.map((E,m)=>i`SUM(CASE WHEN u.${i.identifier("__term__")} = ${i.raw(String(m))} THEN u.${i.identifier("__n__")} ELSE 0 END)`),l=i`SELECT f.${i.identifier(S)} AS ${i.identifier(S)}, ${i.join(w,i` + `)} AS ${i.identifier("__score__")} FROM (${Ht(d)}) u JOIN ${i.identifier(f)} f ON f.rowid = u.${i.identifier("doc")} GROUP BY f.${i.identifier(S)} HAVING ${i.join(w.map(E=>i`${E} > 0`),i` AND `)}`;return Ot(n,t,e,r,o,s,l)},mn=async(n,t,e,r,o,s)=>{const a=t.nativeTextSearch,f=U(o.query,C(o.definition.language));if(!a||f.length===0)return[];const u=k(r,o.indexName),c=[a.matches(u,f),...At(e,o)],d=i`SELECT m.* FROM ${i.identifier(u)} JOIN ${i.identifier(r)} m ON m.${i.identifier("id")} = ${i.identifier(u)}.${i.identifier(S)} WHERE ${i.join(c,i` AND `)} ORDER BY ${a.rank(u,f)} DESC, m.${i.identifier("_creationTime")} DESC, m.${i.identifier("id")} ASC LIMIT ${i.raw(String(s))}`;return mt(e,await h(n,t,d))},hn={ensureCompanion:async(n,t,e)=>{const{integer:r,key:o}=t.companionTypes;await p(n,t,i`CREATE TABLE IF NOT EXISTS ${i.identifier(e)} (${i.identifier(T)} ${i.raw(o)} NOT NULL, ${i.identifier(S)} ${i.raw(o)} NOT NULL, ${i.identifier(A)} ${i.raw(r)} NOT NULL)`),await Q(n,t,{columns:x(t,S,191),name:`${e}__by_id`,table:e,unique:!1}),await on(n,t,e)},indexDocument:async(n,t,e,r,o,s)=>{const a=[...pt(D(r,o),C(o.language))];await O(n,t,_t(t,e,String(s.row.id),a,s))},migrate:wn,name:"inverted",purgeDocument:async(n,t,e,r,o)=>{await p(n,t,I(e,r,V(o,r)))},runSearch:En},pn={ensureCompanion:async(n,t,e)=>{await O(n,t,kt(e))},indexDocument:async(n,t,e,r,o,s)=>{await O(n,t,Et(e,String(s.row.id),D(r,o),{guard:F(t,s)}))},migrate:rn,name:"fts5",purgeDocument:async(n,t,e,r,o)=>{await O(n,t,lt(e,r,{guard:V(o,r)}))},runSearch:ln},gn={ensureCompanion:async(n,t,e)=>{const r=t.nativeTextSearch;if(r){await p(n,t,r.createCompanion(e,t.companionTypes.key));for(const o of r.createIndexes(e))await p(n,t,o)}},indexDocument:async(n,t,e,r,o,s)=>{const a=t.nativeTextSearch;if(!a)return;const f=String(s.row.id);await p(n,t,I(e,f)),await p(n,t,a.indexDocument(e,f,D(r,o)))},name:"native",purgeDocument:async(n,t,e,r)=>{await p(n,t,I(e,r))},runSearch:mn},L=(n,t)=>n.strategy==="native"&&t.nativeTextSearch!==void 0?gn:t.supportsFts5?pn:hn,H=(n,t)=>`${vt(n)}/${L(n,t).name}`,z=function*(n){for(const[t,e]of Object.entries(n.tables)){const r=e.searchIndexes;if(!(e.shardMode!==void 0&&e.shardMode.kind!=="global"||!r))for(const o of r)yield[t,e,o]}},N=(n,t)=>k(n,t.name),Tn=async(n,t,e,r)=>{const o=N(e,r);return St(await b(n,t,o),H(r,t)).finished?!0:Ft(n,t,o)},Fn=async(n,t,e,r,o,s)=>{if(!await Tn(n,t,r,o.definition))throw new g("SEARCH_INDEX_BUILDING",`search index "${o.indexName}" on table "${r}" is still backfilling and currently covers only part of the table — retry once it finishes${t.searchBackfillHint===void 0?"":`, or complete it now: ${t.searchBackfillHint}`}`);return L(o.definition,t).runSearch(n,t,e,r,o,s)},dt=n=>n.slice(n.lastIndexOf("/")+1),$t=200,wt=5,yn=async(n,t,e,r)=>{const o=[...r.keys()],s=await h(n,t,i`SELECT * FROM ${i.identifier(e)} WHERE ${i.identifier("id")} >= ${o[0]} AND ${i.identifier("id")} <= ${o.at(-1)} ORDER BY ${i.identifier("id")} ASC`),a=new Map;for(const f of s){const u=f.id,c=r.get(u)?.row;c&&gt.some(d=>String(c[d])!==String(f[d]))&&a.set(u,{row:f})}return a},It=async(n,t,e,r,o,s,a)=>{const f=L(s,t);let u=a;for(let c=0;u.size>0&&c<wt;c+=1){for(const{document:d,row:w}of u.values()){const l=d??Y(e,w);l&&await f.indexDocument(n,t,o,l,s,{row:w,table:r})}u=await yn(n,t,r,u)}u.size>0&&console.warn(`[@lunora/sql-store] search index "${o}": ${String(u.size)} row(s) were rewritten on every one of ${String(wt)} re-check rounds and were left to their writers — each stays stale only if none of those writes changed its indexed text.`)},Ct=async(n,t,e,r,o)=>{const s=N(r,o),a=H(o,t),f=St(await b(n,t,s),a);if(f.finished)return!0;if(f.wipe&&await q(n,t,s,void 0,!1,a),(await h(n,t,t.tableExists(r))).length===0)return await q(n,t,s,void 0,!0,a),!0;const c=await xt(n,t,r,f.cursor,$t),d=c.findLast(E=>typeof E.id=="string")?.id,w=new Map;for(const E of c)typeof E.id=="string"&&w.set(E.id,{row:E});await It(n,t,e,r,s,o,w);const l=c.length<$t;return await q(n,t,s,d??f.cursor,l,a),l},Lt=async(n,t,e)=>{await Dt(n,e);for(const[r,,o]of z(t)){const s=N(r,o),a=H(o,e),f=await b(n,e,s);f.profile!==void 0&&dt(f.profile)!==dt(a)&&(await p(n,e,i`DROP TABLE IF EXISTS ${i.identifier(s)}`),await p(n,e,i`DROP TABLE IF EXISTS ${i.identifier(Pt(s))}`),await qt(n,e,s)),await L(o,e).ensureCompanion(n,e,s)}},Rn=async(n,t,e,r,o)=>{const s=N(r,o);if((await b(n,t,s)).profile!==void 0)return;let f=0;(await h(n,t,t.tableExists(r))).length>0&&await Kt(n,t,e,r,()=>{f+=1},{limit:1}),await q(n,t,s,void 0,f===0,H(o,t))},Mt=async(n,t,e,r,o,s)=>await L(o,t).migrate?.(n,t,{companion:N(r,o),definition:e,index:o,tableName:r},s)??{uniqueKeyMissing:!1,unmappedSkipped:0},bn=async(n,t,e)=>{await Lt(n,t,e);for(const[r,o,s]of z(t)){if(await Mt(n,e,o,r,s,"step"),s.staged){await Rn(n,e,o,r,s);continue}await Ct(n,e,o,r,s)}},Un=async(n,t,e)=>{const r={uniqueKeyMissing:[],unmappedSkipped:0};await Lt(n,t,e);for(const[o,s,a]of z(t)){const f=await Mt(n,e,s,o,a,"drain");r.unmappedSkipped+=f.unmappedSkipped,f.uniqueKeyMissing&&r.uniqueKeyMissing.push(N(o,a));let u=!1;for(;!u;)u=await Ct(n,e,s,o,a)}return r},kn=n=>{const{dialect:t,exec:e,schema:r}=n;return async(o,s,a)=>{const f=r.tables[o],u=f?.searchIndexes;if(!(!f||!u||u.length===0))for(const c of u){if(tn(a?.previous,a?.document,c))continue;const d=N(o,c);if(a){await It(e,t,f,o,d,c,new Map([[s,{document:a.document,row:{...a.written,id:s}}]]));continue}await L(c,t).purgeDocument(e,t,d,s,o)}}};export{Cn as A,vn as C,Dn as R,qn as T,Fn as a,Mn as b,kn as c,Un as d,bn as r,Ln as x};
@@ -1 +1 @@
1
- import{sql as e}from"drizzle-orm";import{queryRun as p,queryAll as m}from"./decodeGlobalRow-C5EqHgwt.mjs";const y=["de","en","es","fr","it","nl","none","pt"],L=i=>y.includes(i),A="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",R="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",F="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",N="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",_="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",q="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",x="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ê",C=new RegExp("(?<=\\p{Script=Cyrillic})[\\u0300-\\u0305\\u0307\\u0309-\\u036F]|(?<!\\p{Script=Cyrillic})[\\u0300-\\u036F]","gu"),O=/[\u0080-\u{10FFFF}]/u,b=/[\p{L}\p{N}]+/gu,H=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]+/gu,g=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u,D=i=>{if(!g.test(i))return[i];const n=[];let t=0;for(const r of i.matchAll(H)){const o=r.index,s=[...r[0]];if(o>t&&n.push(i.slice(t,o)),t=o+r[0].length,s.length===1){n.push(r[0]);continue}for(let a=0;a+1<s.length;a+=1)n.push(`${String(s[a])}${String(s[a+1])}`)}return t<i.length&&n.push(i.slice(t)),n},v=i=>O.test(i)?i.normalize("NFD").replaceAll(C,"").normalize("NFC").toLowerCase():i.toLowerCase(),f=i=>new Set(v(i).split(" ")),j={de:f(R),en:f(A),es:f(F),fr:f(N),it:f(_),nl:f(q),none:new Set,pt:f(x)},z=3,U=256,w=new Map,k=i=>{const n=i!==void 0&&L(i)?i:"none",t=w.get(n);if(t)return t;const r=j[n],o=a=>{const d=v(a),$=d.match(b)??[],u=(g.test(d)?$.flatMap(l=>D(l)):$).filter(l=>l.length<=U);return r.size===0?u:u.filter(l=>!r.has(l))},s={document:o,profile:`${n}-v${String(z)}`,query:a=>{const d=o(a);return d.filter(($,u)=>d.lastIndexOf($)===u)}};return w.set(n,s),s},W=i=>`${k(i.language).profile}:${i.field}`,S=i=>{const n=i.slice(i.indexOf(":")+1),t=n.lastIndexOf("/");return t===-1?n:n.slice(0,t)},V=(i,n)=>i.profile!==n?{cursor:void 0,finished:!1,wipe:i.cursor!==void 0||i.done}:{cursor:i.cursor,finished:i.done,wipe:!1},I=(i,n)=>typeof i=="string"&&S(i)===S(n),c="__lunora_search_state",K=async(i,n)=>{const{integer:t,key:r}=n.companionTypes,o=async(s,a)=>{try{await p(i,n,e`ALTER TABLE ${e.identifier(c)} ADD COLUMN ${e.identifier(s)} ${e.raw(a)}`)}catch{}};await p(i,n,e`CREATE TABLE IF NOT EXISTS ${e.identifier(c)} (${e.identifier("companion")} ${e.raw(r)} PRIMARY KEY, ${e.identifier("cursor")} ${e.raw(r)}, ${e.identifier("done")} ${e.raw(t)} NOT NULL DEFAULT 0, ${e.identifier("profile")} ${e.raw(r)}, ${e.identifier("covered")} ${e.raw(t)} NOT NULL DEFAULT 0)`),await o("profile",r),await o("covered",`${t} NOT NULL DEFAULT 0`),await p(i,n,e`UPDATE ${e.identifier(c)} SET ${e.identifier("covered")} = 1 WHERE ${e.identifier("done")} = 1 AND ${e.identifier("covered")} = 0`)},T=i=>i===1||i===!0||i==="1",P=async(i,n,t)=>{const r=await m(i,n,e`SELECT ${e.identifier("covered")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`);return T(r[0]?.covered)},Y=async(i,n,t)=>{await p(i,n,e`DELETE FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`)},X=async(i,n,t)=>{const o=(await m(i,n,e`SELECT ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`))[0];if(!o)return{cursor:void 0,done:!1,profile:void 0};const{cursor:s,profile:a}=o;return{cursor:typeof s=="string"?s:void 0,done:T(o.done),profile:typeof a=="string"?a:void 0}},G=async(i,n,t,r,o,s)=>{const a=r??null,d=await m(i,n,e`SELECT ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`),$=I(d[0]?.profile,s),u=o?1:0,l=o||!$?e`${e.identifier("covered")} = ${u}`:e`${e.identifier("covered")} = ${e.identifier("covered")}`,h=e`UPDATE ${e.identifier(c)} SET ${e.identifier("cursor")} = ${a}, ${e.identifier("done")} = ${u}, ${e.identifier("profile")} = ${s}, ${l} WHERE ${e.identifier("companion")} = ${t}`;if(d.length>0){await p(i,n,h);return}try{await p(i,n,e`INSERT INTO ${e.identifier(c)} (${e.identifier("companion")}, ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")}, ${e.identifier("covered")}) VALUES (${t}, ${a}, ${o?1:0}, ${s}, ${o?1:0})`)}catch(E){if(!n.isUniqueViolation(E))throw E;await p(i,n,h)}};export{k as D,c as S,Y as a,P as b,W as c,V as l,K as m,X as r,G as w};
1
+ import{sql as e}from"drizzle-orm";import{queryRun as p,queryAll as m}from"./decodeGlobalRow-VOl_TIbk.mjs";const y=["de","en","es","fr","it","nl","none","pt"],L=i=>y.includes(i),A="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",R="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",F="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",N="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",_="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",q="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",x="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ê",C=new RegExp("(?<=\\p{Script=Cyrillic})[\\u0300-\\u0305\\u0307\\u0309-\\u036F]|(?<!\\p{Script=Cyrillic})[\\u0300-\\u036F]","gu"),O=/[\u0080-\u{10FFFF}]/u,b=/[\p{L}\p{N}]+/gu,H=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]+/gu,g=/[\p{Script_Extensions=Han}\p{Script_Extensions=Hiragana}\p{Script_Extensions=Katakana}\p{Script_Extensions=Hangul}]/u,D=i=>{if(!g.test(i))return[i];const n=[];let t=0;for(const r of i.matchAll(H)){const o=r.index,s=[...r[0]];if(o>t&&n.push(i.slice(t,o)),t=o+r[0].length,s.length===1){n.push(r[0]);continue}for(let a=0;a+1<s.length;a+=1)n.push(`${String(s[a])}${String(s[a+1])}`)}return t<i.length&&n.push(i.slice(t)),n},v=i=>O.test(i)?i.normalize("NFD").replaceAll(C,"").normalize("NFC").toLowerCase():i.toLowerCase(),f=i=>new Set(v(i).split(" ")),j={de:f(R),en:f(A),es:f(F),fr:f(N),it:f(_),nl:f(q),none:new Set,pt:f(x)},z=3,U=256,w=new Map,k=i=>{const n=i!==void 0&&L(i)?i:"none",t=w.get(n);if(t)return t;const r=j[n],o=a=>{const d=v(a),$=d.match(b)??[],u=(g.test(d)?$.flatMap(l=>D(l)):$).filter(l=>l.length<=U);return r.size===0?u:u.filter(l=>!r.has(l))},s={document:o,profile:`${n}-v${String(z)}`,query:a=>{const d=o(a);return d.filter(($,u)=>d.lastIndexOf($)===u)}};return w.set(n,s),s},W=i=>`${k(i.language).profile}:${i.field}`,S=i=>{const n=i.slice(i.indexOf(":")+1),t=n.lastIndexOf("/");return t===-1?n:n.slice(0,t)},V=(i,n)=>i.profile!==n?{cursor:void 0,finished:!1,wipe:i.cursor!==void 0||i.done}:{cursor:i.cursor,finished:i.done,wipe:!1},I=(i,n)=>typeof i=="string"&&S(i)===S(n),c="__lunora_search_state",K=async(i,n)=>{const{integer:t,key:r}=n.companionTypes,o=async(s,a)=>{try{await p(i,n,e`ALTER TABLE ${e.identifier(c)} ADD COLUMN ${e.identifier(s)} ${e.raw(a)}`)}catch{}};await p(i,n,e`CREATE TABLE IF NOT EXISTS ${e.identifier(c)} (${e.identifier("companion")} ${e.raw(r)} PRIMARY KEY, ${e.identifier("cursor")} ${e.raw(r)}, ${e.identifier("done")} ${e.raw(t)} NOT NULL DEFAULT 0, ${e.identifier("profile")} ${e.raw(r)}, ${e.identifier("covered")} ${e.raw(t)} NOT NULL DEFAULT 0)`),await o("profile",r),await o("covered",`${t} NOT NULL DEFAULT 0`),await p(i,n,e`UPDATE ${e.identifier(c)} SET ${e.identifier("covered")} = 1 WHERE ${e.identifier("done")} = 1 AND ${e.identifier("covered")} = 0`)},T=i=>i===1||i===!0||i==="1",P=async(i,n,t)=>{const r=await m(i,n,e`SELECT ${e.identifier("covered")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`);return T(r[0]?.covered)},Y=async(i,n,t)=>{await p(i,n,e`DELETE FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`)},X=async(i,n,t)=>{const o=(await m(i,n,e`SELECT ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`))[0];if(!o)return{cursor:void 0,done:!1,profile:void 0};const{cursor:s,profile:a}=o;return{cursor:typeof s=="string"?s:void 0,done:T(o.done),profile:typeof a=="string"?a:void 0}},G=async(i,n,t,r,o,s)=>{const a=r??null,d=await m(i,n,e`SELECT ${e.identifier("profile")} FROM ${e.identifier(c)} WHERE ${e.identifier("companion")} = ${t}`),$=I(d[0]?.profile,s),u=o?1:0,l=o||!$?e`${e.identifier("covered")} = ${u}`:e`${e.identifier("covered")} = ${e.identifier("covered")}`,h=e`UPDATE ${e.identifier(c)} SET ${e.identifier("cursor")} = ${a}, ${e.identifier("done")} = ${u}, ${e.identifier("profile")} = ${s}, ${l} WHERE ${e.identifier("companion")} = ${t}`;if(d.length>0){await p(i,n,h);return}try{await p(i,n,e`INSERT INTO ${e.identifier(c)} (${e.identifier("companion")}, ${e.identifier("cursor")}, ${e.identifier("done")}, ${e.identifier("profile")}, ${e.identifier("covered")}) VALUES (${t}, ${a}, ${o?1:0}, ${s}, ${o?1:0})`)}catch(E){if(!n.isUniqueViolation(E))throw E;await p(i,n,h)}};export{k as D,c as S,Y as a,P as b,W as c,V as l,K as m,X as r,G as w};
@@ -0,0 +1 @@
1
+ import{renderSql as m}from"@lunora/shard-engine";import{sql as r}from"drizzle-orm";import{s as I,b as y,e as N}from"./value-codec-DC_dHxUY.mjs";const v="_version",C=n=>n==="_id"||n==="id"?"id":n,L=n=>r`${r.identifier(C(n))}`,F=(n,t)=>r`${r.identifier(n)}.${r.identifier(C(t))}`,K=n=>{const t=[];for(const[e,o]of Object.entries(n.shape)){const s=o._meta?.column;s&&t.push([e,s])}return t},d=(n,t,e)=>{const{params:o,sql:s}=m(t.name,e);return n.all(s,o)},u=(n,t,e)=>{const{params:o,sql:s}=m(t.name,e);return n.run(s,o)},k=(n,t,e)=>n==="postgres"?r`${t} IS NOT DISTINCT FROM ${e}`:n==="mysql"?r`${t} <=> ${e}`:r`${t} IS ${e}`,B={sql:n=>r`COALESCE(${n}, 0) + 1`,value:n=>(n==null?0:Number(n))+1},P=async(n,t,e)=>{if(e.length!==0){if(!n.batch){for(const o of e)await u(n,t,o);return}await n.batch(e.map(o=>m(t.name,o)))}},W=async(n,t,e)=>{if(n.batch&&t.name==="sqlite"){await n.batch(e.map(o=>m(t.name,o)));return}for(const o of e)await u(n,t,o)},X=async(n,t,e)=>{const o=e.unique?r`UNIQUE `:r``,s=e.concurrently===!0&&t.name==="postgres"?r`CONCURRENTLY `:r``;if(t.name==="mysql"){try{await u(n,t,r`CREATE ${o}INDEX ${r.identifier(e.name)} ON ${r.identifier(e.table)} (${e.columns})`)}catch(i){const a=i;if(a.errno!==1061&&a.code!=="ER_DUP_KEYNAME"&&a.code!==1061)throw i}return}await u(n,t,r`CREATE ${o}INDEX ${s}IF NOT EXISTS ${r.identifier(e.name)} ON ${r.identifier(e.table)} (${e.columns})`)},x=async(n,t,e,o)=>{if(t.name!=="mysql"){await u(n,t,r`DROP INDEX IF EXISTS ${r.identifier(o)}`);return}try{await u(n,t,r`DROP INDEX ${r.identifier(o)} ON ${r.identifier(e)}`)}catch(s){const i=s;if(i.errno!==1091&&i.code!=="ER_CANT_DROP_FIELD_OR_KEY"&&i.code!==1091)throw s}},H=async(n,t,e,o)=>{switch(t.name){case"mysql":return(await d(n,t,r`SELECT 1 AS ${r.identifier("present")} FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = ${e} AND index_name = ${o} LIMIT 1`)).length>0?"valid":"absent";case"postgres":{const s=await d(n,t,r`SELECT indisvalid FROM pg_index WHERE indexrelid = to_regclass(quote_ident(${o}))`);return s.length===0?"absent":s[0]?.indisvalid===!0?"valid":"invalid"}default:return(await d(n,t,r`SELECT 1 AS ${r.identifier("present")} FROM sqlite_master WHERE type = 'index' AND name = ${o}`)).length>0?"valid":"absent"}},U=I,f=n=>{if(n===void 0)return!1;if(n._meta?.column?.notNull===!1)return!0;switch(n.kind){case"any":case"null":return!0;case"literal":return n._meta?.value===null;case"optional":return f(n._meta?.inner);case"union":return n._meta?.members?.some(t=>f(t))===!0;default:return!1}},q=n=>n.kind==="optional"&&!f(n),R=new WeakMap,S=n=>{let t=R.get(n);return t===void 0&&(t=Object.entries(n.shape).map(([e,o])=>[e,N(o),q(o)]),R.set(n,t)),t},h=new WeakMap,b=(n,t)=>{let e=h.get(n);return e===void 0&&(e=new Map(S(n).map(([o,s])=>[o,s])),h.set(n,e)),e.get(t)},Y=(n,t,e)=>I(e,b(n,t)),g=(n,t)=>{const e={};for(const[o,s,i]of S(n)){const a=t[o];a===void 0||i&&a===null||(e[o]=y(a,s))}return e._id=t.id,e._creationTime=t._creationTime,e},O=(n,t)=>t?g(n,t):null,z=(n,t)=>{const e=[];for(const o of t){const s=O(n,o);s&&e.push(s)}return e},_=500,T=(n,t,e,o,s)=>{const i=r`${r.identifier(e)}.${r.identifier("id")}`,a=o===void 0?r``:r` WHERE ${i} > ${o}`;return d(n,t,r`SELECT * FROM ${r.identifier(e)}${a} ORDER BY ${i} ASC LIMIT ${r.raw(String(s))}`)},V=async(n,t,e,o,s,i={})=>{let a=i.after,c=i.limit,E=!0;for(;E&&(c===void 0||c>0);){const $=c===void 0?_:Math.min(_,c),l=await T(n,t,o,a,$);for(const p of l){const w=O(e,p);w&&await s(w)}a=l.at(-1)?.id,E=l.length===$,c=c===void 0?void 0:c-l.length}};export{_ as BACKFILL_BATCH_SIZE,v as OCC_VERSION_COLUMN,L as columnRefSql,X as createIndexIfNotExists,g as decodeGlobalRow,O as decodeRow,z as decodeRows,x as dropIndexIfExists,V as forEachRowPaged,H as indexState,B as nextRowVersion,k as nullSafeEqualsSql,C as physicalColumn,F as qualifiedColumnRefSql,d as queryAll,P as queryBatch,u as queryRun,T as readRowsPage,W as runInOrder,U as serializeColumnValue,Y as serializeDocumentColumn,K as tableColumns};
@@ -1 +1 @@
1
- import{LunoraError as N}from"@lunora/errors";import{aggregateTableName as x,rankTableName as D,sortColumnName as A,renderSql as U,bigintSqlKey as M}from"@lunora/shard-engine";import{sql as n}from"drizzle-orm";import{queryRun as g,queryAll as E,createIndexIfNotExists as p,OCC_VERSION_COLUMN as h,tableColumns as k,qualifiedColumnRefSql as B,columnRefSql as d,queryBatch as P}from"./decodeGlobalRow-C5EqHgwt.mjs";import{e as w,i as j,B as b,r as F,U as K,a as G}from"./value-codec-DC_dHxUY.mjs";const L=(i,t,e=!1)=>t.columnType(w(i),{unique:e||i._meta?.column?.unique===!0}),S=i=>{const t=new Set;for(const e of i.indexes)e.unique===!0&&e.fields.length===1&&t.add(e.fields[0]);return t},Y=(i,t,e)=>{if(e.indexKeyPrefix!==void 0)for(const o of t.indexes){if(o.unique!==!0||o.fields.length<=1)continue;const r=o.fields.filter(u=>{const l=t.shape[u];return l!==void 0&&e.indexKeyPrefix?.(w(l))!==void 0});if(r.length>0)throw new Error(`${i}.${o.name}: a composite unique index cannot cover ${r.join(", ")} in full on this engine (its key limit forces a prefix, which would constrain the prefix rather than the value). Split it into single-column unique indexes, or store those fields as a bounded type.`)}},V=(i,t,e)=>{const o=[],r=S(t);for(const[a,f]of Object.entries(t.shape)){if(!f._meta?.column)continue;const c=f._meta.column.notNull&&f.kind!=="optional"?" NOT NULL":"";o.push(n`${n.identifier(a)} ${n.raw(`${L(f,e,r.has(a))}${c}`)}`)}const u=[...e.frameworkColumns().map(a=>n`${n.identifier(a.name)} ${n.raw(a.type)}`),n`${n.identifier(h)} ${n.raw(e.companionTypes.integer)}`],l=u.length+o.length,s=e.maxTableColumns;if(s!==void 0&&l>s){const a=l-1===s,f="Move one or more fields into a single object field, or split the table — either way the existing rows need a data migration (`defineMigration` + `lunora migrate up`); there is no in-place path.";throw new N("VALIDATION_ERROR",`@lunora/sql-store: global table "${i}" needs ${String(l)} columns, over this engine's ${String(s)}-column limit. ${a?`One of them is "${h}", the row version every guarded write reads, which caps declared fields at ${String(s-u.length)}. A table provisioned at ${String(s)} columns before that column existed cannot be widened to hold it. `:""}${f}`)}return n.join([...u,...o],n`, `)},H=i=>{if(i.indexKeyPrefix?.("string")===void 0)return n`${d("_creationTime")}, ${d("id")}`},q=async(i,t,e,o)=>{const r=n.join(e.refs.map(l=>n`${l} IS NOT NULL`),n` AND `);if((await E(i,t,n`SELECT ${e.columns} FROM ${n.identifier(e.table)} WHERE ${r} GROUP BY ${e.columns} HAVING COUNT(*) > 1 LIMIT 1`)).length>0)throw new N("INTERNAL",`unique index "${e.name}" on "${e.table}" ${o}: existing rows are duplicates under it. De-duplicate the table with a data migration first.`)},I=async(i,t,e)=>{if(!e.unique){await p(i,t,e);return}try{await p(i,t,e)}catch(o){throw t.isUniqueViolation(o)&&await q(i,t,e,"cannot be created"),o}},X=async(i,t,e)=>{if(t.name!=="sqlite")return;const r=(await E(i,t,n`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${e.name} AND tbl_name = ${e.table}`))[0]?.sql;if(typeof r!="string")return;const u=a=>{const f=a.indexOf("(");return f===-1?void 0:a.slice(f,a.lastIndexOf(")")+1)},l=e.unique?n`UNIQUE `:n``,s=u(U(t.name,n`CREATE ${l}INDEX ${n.identifier(e.name)} ON ${n.identifier(e.table)} (${e.columns})`).sql);s===void 0||s===u(r)||(e.unique&&await q(i,t,e,"cannot be re-created with its new column list; the previous index is left in place"),await g(i,t,n`DROP INDEX IF EXISTS ${n.identifier(e.name)}`))},W=async(i,t,e,o)=>{Y(t,e,o);const r=S(e),u=s=>{const a=d(s),f=e.shape[s],c=f&&o.indexKeyPrefix&&f._meta?.column?.unique!==!0&&!r.has(s)?o.indexKeyPrefix(w(f)):void 0;return c===void 0?a:n`${a}(${n.raw(String(c))})`},l=H(o);for(const s of e.indexes){const a=s.fields.map($=>u($)),f=n.join(a,n`, `),c=s.unique??!1,m={columns:c||l===void 0?f:n`${f}, ${l}`,name:`${t}_${s.name}`,refs:a,table:t,unique:c};await X(i,o,m),await I(i,o,m)}l!==void 0&&await p(i,o,{columns:l,name:`${t}__by_creation`,table:t,unique:!1});for(const[s,a]of k(e)){if(!a.unique)continue;const f=u(s);await I(i,o,{columns:f,name:`${t}_unique_${s}`,refs:[f],table:t,unique:!0})}},_="__lunora_migration_state",Q=async(i,t)=>{await g(i,t,n`CREATE TABLE IF NOT EXISTS ${n.identifier(_)} (${n.identifier("name")} ${n.raw(t.companionTypes.key)} PRIMARY KEY)`)},z=async(i,t,e)=>(await E(i,t,n`SELECT ${n.identifier("name")} FROM ${n.identifier(_)} WHERE ${n.identifier("name")} = ${e}`)).length>0,J=async(i,t,e,o,r,u)=>{r>0&&u!==void 0&&console.warn(`[@lunora/sql-store] storage migration "${e}" on "${o}": ${String(r)} row(s) ${u} and were left as stored — range filters and ORDER BY over them stay wrong until they are corrected by hand.`);try{await g(i,t,n`INSERT INTO ${n.identifier(_)} (${n.identifier("name")}) VALUES (${e})`)}catch(l){if(!t.isUniqueViolation(l))throw l}},Z=100,nn=(i,t)=>{const e=[],o=[];for(const r of t.fields){const u=i[r],l=t.convert(u);l!==void 0&&(e.push(n`${d(r)} = ${l}`),o.push(n`${d(r)} = ${u}`))}return{assignments:e,guards:o}},O=async(i,t,e,o)=>{if(o.fields.length===0||(await Q(i,e),await z(i,e,o.marker)))return;const r=n.join(o.fields.map(a=>o.probe(a)),n` OR `),u=n.join([d("id"),...o.fields.map(a=>d(a))],n`, `);let l="",s=0;for(;;){const a=await E(i,e,n`SELECT ${u} FROM ${n.identifier(t)} WHERE (${r}) AND ${d("id")} > ${l} ORDER BY ${d("id")} LIMIT ${n.raw(String(Z))}`);if(a.length===0){await J(i,e,o.marker,t,s,o.describeUnconvertible);return}const f=[];for(const m of a){const{id:$}=m,{assignments:T,guards:C}=typeof $=="string"?nn(m,o):{assignments:[],guards:[]};if(T.length===0){s+=1;continue}f.push(n`UPDATE ${n.identifier(t)} SET ${n.join(T,n`, `)} WHERE ${d("id")} = ${$} AND ${n.join(C,n` AND `)}`)}await P(i,e,f);const c=a.at(-1)?.id;if(typeof c!="string")return;l=c}},R=i=>`'${i}%'`,en=i=>Object.entries(i.shape).filter(([,t])=>t._meta?.column!==void 0&&w(t)==="bigint").map(([t])=>t),tn=i=>Object.entries(i.shape).filter(([,t])=>t._meta?.column!==void 0&&j(w(t))).map(([t])=>t),on=async(i,t,e,o)=>O(i,t,o,{convert:r=>{if(!(typeof r!="string"||r.length===b))try{return M(BigInt(r))}catch{return}},describeUnconvertible:"hold a value the order-preserving key cannot represent (non-numeric text, or a magnitude past 39 digits)",fields:en(e),marker:`bigint-key:${t}`,probe:r=>n`(${d(r)} IS NOT NULL AND LENGTH(${d(r)}) <> ${b})`}),rn=async(i,t,e,o)=>O(i,t,o,{convert:F,fields:tn(e),marker:`untyped-number-key:${t}`,probe:r=>n`(${d(r)} LIKE ${n.raw(R(K))} AND ${d(r)} NOT LIKE ${n.raw(R(G))})`}),sn=async(i,t,e,o)=>{const r=[[h,o.companionTypes.integer],...Object.entries(e.shape).filter(([,s])=>s._meta?.column!==void 0).map(([s,a])=>[s,L(a,o)])],u="t",l=async s=>{try{return await E(i,o,n`SELECT ${n.join(s.map(a=>B(u,a)),n`, `)} FROM ${n.identifier(t)} AS ${n.identifier(u)} LIMIT 0`),!0}catch{return!1}};if(!await l(r.map(([s])=>s)))for(const[s,a]of r)await l([s])||await g(i,o,n`ALTER TABLE ${n.identifier(t)} ADD COLUMN ${n.identifier(s)} ${n.raw(a)}`)},$n=async(i,t,e)=>{for(const[o,r]of Object.entries(t.tables)){if(r.shardMode?.kind!=="global")continue;const u=V(o,r,e);await g(i,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(o)} (${u})`),await sn(i,o,r,e),await W(i,o,r,e),await on(i,o,r,e),await rn(i,o,r,e)}},v=i=>i.shardMode===void 0||i.shardMode.kind==="global",gn=async(i,t,e)=>{const{integer:o,key:r,real:u}=e.companionTypes;for(const[l,s]of Object.entries(t.tables)){const a=s.aggregateIndexes;if(!(!a||a.length===0||!v(s)))for(const f of a){const c=x(l,f.name);await g(i,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(c)} (${n.identifier("__key__")} ${n.raw(r)} PRIMARY KEY, ${n.identifier("__value__")} ${n.raw(u)}, ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0)`),e.name==="sqlite"&&((await E(i,e,n`PRAGMA table_info(${n.identifier(c)})`)).some($=>$.name==="__count__")||await g(i,e,n`ALTER TABLE ${n.identifier(c)} ADD COLUMN ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0`))}}},y=(i,t,e,o)=>{const r=i.name==="mysql"&&o?n`${n.identifier(t)}(191)`:n`${n.identifier(t)}`;return n`${r} ${n.raw(e)}`},an=(i,t,e)=>{const o=[y(i,"__partition__","ASC",!0)];for(const[r,u]of t.sortBy.entries()){const l=e.shape[u.field],s=l!==void 0&&i.indexKeyPrefix?.(w(l))!==void 0;o.push(y(i,A(r),u.direction==="desc"?"DESC":"ASC",s))}return o.push(y(i,"__id__","ASC",!0)),o},un=(i,t,e)=>t.sortBy.map((o,r)=>{const u=e.shape[o.field],l=i.columnType(u?w(u):void 0);return n`${n.identifier(A(r))} ${n.raw(l)}`}),wn=async(i,t,e)=>{const{key:o}=e.companionTypes;for(const[r,u]of Object.entries(t.tables)){const l=u.rankIndexes;if(!(!l||l.length===0||!v(u)))for(const s of l){const a=D(r,s.name),f=un(e,s,u),c=f.length>0?n`, ${n.join(f,n`, `)}`:n``;await g(i,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(a)} (${n.identifier("__id__")} ${n.raw(o)} PRIMARY KEY, ${n.identifier("__partition__")} ${n.raw(o)} NOT NULL${c})`);const m=an(e,s,u),$=`${r}__rank_${s.name}__btree`;await p(i,e,{columns:n.join(m,n`, `),name:$,table:a,unique:!1})}}};export{gn as runSqlAggregateMigrations,$n as runSqlGlobalTableMigrations,wn as runSqlRankMigrations};
1
+ import{LunoraError as N}from"@lunora/errors";import{aggregateTableName as x,rankTableName as D,sortColumnName as A,renderSql as U,bigintSqlKey as M}from"@lunora/shard-engine";import{sql as n}from"drizzle-orm";import{queryRun as g,queryAll as E,createIndexIfNotExists as p,OCC_VERSION_COLUMN as h,tableColumns as k,qualifiedColumnRefSql as B,columnRefSql as d,queryBatch as P}from"./decodeGlobalRow-VOl_TIbk.mjs";import{e as w,i as j,B as b,r as F,U as K,a as G}from"./value-codec-DC_dHxUY.mjs";const L=(i,t,e=!1)=>t.columnType(w(i),{unique:e||i._meta?.column?.unique===!0}),S=i=>{const t=new Set;for(const e of i.indexes)e.unique===!0&&e.fields.length===1&&t.add(e.fields[0]);return t},Y=(i,t,e)=>{if(e.indexKeyPrefix!==void 0)for(const o of t.indexes){if(o.unique!==!0||o.fields.length<=1)continue;const r=o.fields.filter(u=>{const l=t.shape[u];return l!==void 0&&e.indexKeyPrefix?.(w(l))!==void 0});if(r.length>0)throw new Error(`${i}.${o.name}: a composite unique index cannot cover ${r.join(", ")} in full on this engine (its key limit forces a prefix, which would constrain the prefix rather than the value). Split it into single-column unique indexes, or store those fields as a bounded type.`)}},V=(i,t,e)=>{const o=[],r=S(t);for(const[a,f]of Object.entries(t.shape)){if(!f._meta?.column)continue;const c=f._meta.column.notNull&&f.kind!=="optional"?" NOT NULL":"";o.push(n`${n.identifier(a)} ${n.raw(`${L(f,e,r.has(a))}${c}`)}`)}const u=[...e.frameworkColumns().map(a=>n`${n.identifier(a.name)} ${n.raw(a.type)}`),n`${n.identifier(h)} ${n.raw(e.companionTypes.integer)}`],l=u.length+o.length,s=e.maxTableColumns;if(s!==void 0&&l>s){const a=l-1===s,f="Move one or more fields into a single object field, or split the table — either way the existing rows need a data migration (`defineMigration` + `lunora migrate up`); there is no in-place path.";throw new N("VALIDATION_ERROR",`@lunora/sql-store: global table "${i}" needs ${String(l)} columns, over this engine's ${String(s)}-column limit. ${a?`One of them is "${h}", the row version every guarded write reads, which caps declared fields at ${String(s-u.length)}. A table provisioned at ${String(s)} columns before that column existed cannot be widened to hold it. `:""}${f}`)}return n.join([...u,...o],n`, `)},H=i=>{if(i.indexKeyPrefix?.("string")===void 0)return n`${d("_creationTime")}, ${d("id")}`},q=async(i,t,e,o)=>{const r=n.join(e.refs.map(l=>n`${l} IS NOT NULL`),n` AND `);if((await E(i,t,n`SELECT ${e.columns} FROM ${n.identifier(e.table)} WHERE ${r} GROUP BY ${e.columns} HAVING COUNT(*) > 1 LIMIT 1`)).length>0)throw new N("INTERNAL",`unique index "${e.name}" on "${e.table}" ${o}: existing rows are duplicates under it. De-duplicate the table with a data migration first.`)},I=async(i,t,e)=>{if(!e.unique){await p(i,t,e);return}try{await p(i,t,e)}catch(o){throw t.isUniqueViolation(o)&&await q(i,t,e,"cannot be created"),o}},X=async(i,t,e)=>{if(t.name!=="sqlite")return;const r=(await E(i,t,n`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${e.name} AND tbl_name = ${e.table}`))[0]?.sql;if(typeof r!="string")return;const u=a=>{const f=a.indexOf("(");return f===-1?void 0:a.slice(f,a.lastIndexOf(")")+1)},l=e.unique?n`UNIQUE `:n``,s=u(U(t.name,n`CREATE ${l}INDEX ${n.identifier(e.name)} ON ${n.identifier(e.table)} (${e.columns})`).sql);s===void 0||s===u(r)||(e.unique&&await q(i,t,e,"cannot be re-created with its new column list; the previous index is left in place"),await g(i,t,n`DROP INDEX IF EXISTS ${n.identifier(e.name)}`))},W=async(i,t,e,o)=>{Y(t,e,o);const r=S(e),u=s=>{const a=d(s),f=e.shape[s],c=f&&o.indexKeyPrefix&&f._meta?.column?.unique!==!0&&!r.has(s)?o.indexKeyPrefix(w(f)):void 0;return c===void 0?a:n`${a}(${n.raw(String(c))})`},l=H(o);for(const s of e.indexes){const a=s.fields.map($=>u($)),f=n.join(a,n`, `),c=s.unique??!1,m={columns:c||l===void 0?f:n`${f}, ${l}`,name:`${t}_${s.name}`,refs:a,table:t,unique:c};await X(i,o,m),await I(i,o,m)}l!==void 0&&await p(i,o,{columns:l,name:`${t}__by_creation`,table:t,unique:!1});for(const[s,a]of k(e)){if(!a.unique)continue;const f=u(s);await I(i,o,{columns:f,name:`${t}_unique_${s}`,refs:[f],table:t,unique:!0})}},_="__lunora_migration_state",Q=async(i,t)=>{await g(i,t,n`CREATE TABLE IF NOT EXISTS ${n.identifier(_)} (${n.identifier("name")} ${n.raw(t.companionTypes.key)} PRIMARY KEY)`)},z=async(i,t,e)=>(await E(i,t,n`SELECT ${n.identifier("name")} FROM ${n.identifier(_)} WHERE ${n.identifier("name")} = ${e}`)).length>0,J=async(i,t,e,o,r,u)=>{r>0&&u!==void 0&&console.warn(`[@lunora/sql-store] storage migration "${e}" on "${o}": ${String(r)} row(s) ${u} and were left as stored — range filters and ORDER BY over them stay wrong until they are corrected by hand.`);try{await g(i,t,n`INSERT INTO ${n.identifier(_)} (${n.identifier("name")}) VALUES (${e})`)}catch(l){if(!t.isUniqueViolation(l))throw l}},Z=100,nn=(i,t)=>{const e=[],o=[];for(const r of t.fields){const u=i[r],l=t.convert(u);l!==void 0&&(e.push(n`${d(r)} = ${l}`),o.push(n`${d(r)} = ${u}`))}return{assignments:e,guards:o}},O=async(i,t,e,o)=>{if(o.fields.length===0||(await Q(i,e),await z(i,e,o.marker)))return;const r=n.join(o.fields.map(a=>o.probe(a)),n` OR `),u=n.join([d("id"),...o.fields.map(a=>d(a))],n`, `);let l="",s=0;for(;;){const a=await E(i,e,n`SELECT ${u} FROM ${n.identifier(t)} WHERE (${r}) AND ${d("id")} > ${l} ORDER BY ${d("id")} LIMIT ${n.raw(String(Z))}`);if(a.length===0){await J(i,e,o.marker,t,s,o.describeUnconvertible);return}const f=[];for(const m of a){const{id:$}=m,{assignments:T,guards:C}=typeof $=="string"?nn(m,o):{assignments:[],guards:[]};if(T.length===0){s+=1;continue}f.push(n`UPDATE ${n.identifier(t)} SET ${n.join(T,n`, `)} WHERE ${d("id")} = ${$} AND ${n.join(C,n` AND `)}`)}await P(i,e,f);const c=a.at(-1)?.id;if(typeof c!="string")return;l=c}},R=i=>`'${i}%'`,en=i=>Object.entries(i.shape).filter(([,t])=>t._meta?.column!==void 0&&w(t)==="bigint").map(([t])=>t),tn=i=>Object.entries(i.shape).filter(([,t])=>t._meta?.column!==void 0&&j(w(t))).map(([t])=>t),on=async(i,t,e,o)=>O(i,t,o,{convert:r=>{if(!(typeof r!="string"||r.length===b))try{return M(BigInt(r))}catch{return}},describeUnconvertible:"hold a value the order-preserving key cannot represent (non-numeric text, or a magnitude past 39 digits)",fields:en(e),marker:`bigint-key:${t}`,probe:r=>n`(${d(r)} IS NOT NULL AND LENGTH(${d(r)}) <> ${b})`}),rn=async(i,t,e,o)=>O(i,t,o,{convert:F,fields:tn(e),marker:`untyped-number-key:${t}`,probe:r=>n`(${d(r)} LIKE ${n.raw(R(K))} AND ${d(r)} NOT LIKE ${n.raw(R(G))})`}),sn=async(i,t,e,o)=>{const r=[[h,o.companionTypes.integer],...Object.entries(e.shape).filter(([,s])=>s._meta?.column!==void 0).map(([s,a])=>[s,L(a,o)])],u="t",l=async s=>{try{return await E(i,o,n`SELECT ${n.join(s.map(a=>B(u,a)),n`, `)} FROM ${n.identifier(t)} AS ${n.identifier(u)} LIMIT 0`),!0}catch{return!1}};if(!await l(r.map(([s])=>s)))for(const[s,a]of r)await l([s])||await g(i,o,n`ALTER TABLE ${n.identifier(t)} ADD COLUMN ${n.identifier(s)} ${n.raw(a)}`)},$n=async(i,t,e)=>{for(const[o,r]of Object.entries(t.tables)){if(r.shardMode?.kind!=="global")continue;const u=V(o,r,e);await g(i,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(o)} (${u})`),await sn(i,o,r,e),await W(i,o,r,e),await on(i,o,r,e),await rn(i,o,r,e)}},v=i=>i.shardMode===void 0||i.shardMode.kind==="global",gn=async(i,t,e)=>{const{integer:o,key:r,real:u}=e.companionTypes;for(const[l,s]of Object.entries(t.tables)){const a=s.aggregateIndexes;if(!(!a||a.length===0||!v(s)))for(const f of a){const c=x(l,f.name);await g(i,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(c)} (${n.identifier("__key__")} ${n.raw(r)} PRIMARY KEY, ${n.identifier("__value__")} ${n.raw(u)}, ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0)`),e.name==="sqlite"&&((await E(i,e,n`PRAGMA table_info(${n.identifier(c)})`)).some($=>$.name==="__count__")||await g(i,e,n`ALTER TABLE ${n.identifier(c)} ADD COLUMN ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0`))}}},y=(i,t,e,o)=>{const r=i.name==="mysql"&&o?n`${n.identifier(t)}(191)`:n`${n.identifier(t)}`;return n`${r} ${n.raw(e)}`},an=(i,t,e)=>{const o=[y(i,"__partition__","ASC",!0)];for(const[r,u]of t.sortBy.entries()){const l=e.shape[u.field],s=l!==void 0&&i.indexKeyPrefix?.(w(l))!==void 0;o.push(y(i,A(r),u.direction==="desc"?"DESC":"ASC",s))}return o.push(y(i,"__id__","ASC",!0)),o},un=(i,t,e)=>t.sortBy.map((o,r)=>{const u=e.shape[o.field],l=i.columnType(u?w(u):void 0);return n`${n.identifier(A(r))} ${n.raw(l)}`}),wn=async(i,t,e)=>{const{key:o}=e.companionTypes;for(const[r,u]of Object.entries(t.tables)){const l=u.rankIndexes;if(!(!l||l.length===0||!v(u)))for(const s of l){const a=D(r,s.name),f=un(e,s,u),c=f.length>0?n`, ${n.join(f,n`, `)}`:n``;await g(i,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(a)} (${n.identifier("__id__")} ${n.raw(o)} PRIMARY KEY, ${n.identifier("__partition__")} ${n.raw(o)} NOT NULL${c})`);const m=an(e,s,u),$=`${r}__rank_${s.name}__btree`;await p(i,e,{columns:n.join(m,n`, `),name:$,table:a,unique:!1})}}};export{gn as runSqlAggregateMigrations,$n as runSqlGlobalTableMigrations,wn as runSqlRankMigrations};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/sql-store",
3
- "version": "1.0.0-alpha.134",
3
+ "version": "1.0.0-alpha.136",
4
4
  "description": "Internal dialect-parameterized SQL store core for Lunora .global() backends (D1, PlanetScale)",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@lunora/errors": "1.0.0-alpha.41",
54
- "@lunora/shard-engine": "1.0.0-alpha.82",
54
+ "@lunora/shard-engine": "1.0.0-alpha.83",
55
55
  "drizzle-orm": "^0.45.2"
56
56
  },
57
57
  "engines": {
@@ -1 +0,0 @@
1
- import"./ctx-db-search-state-DaAD01za.mjs";import{d as S,c as s,a as i,r as l}from"./ctx-db-search-BU0YOW8P.mjs";import"./decodeGlobalRow-C5EqHgwt.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
@@ -1,7 +0,0 @@
1
- import{LunoraError as T}from"@lunora/errors";import{m as Wt,D as Ut}from"./ctx-db-search-state-DaAD01za.mjs";import{c as xt,r as Pt,A as Ht,C as Kt,R as jt,a as Gt,T as Vt,x as Yt,b as Xt}from"./ctx-db-search-BU0YOW8P.mjs";import{d as Ri}from"./ctx-db-search-BU0YOW8P.mjs";import{literalInList as zt,throwingScheduler as Qt,CDC_LOG_TABLE as P,cdcForkedError as Jt,cursorBelowRetainedFloor as Zt,cdcTrimmedError as en,assertNoExplicitUndefined as et,hasTrigger as tn,runRowValidators as Ne,assertFlatPredicate as tt,mergeWhere as B,rankTableName as we,sortColumnName as Ee,resolveRankPartition as nt,encodePartitionKey as Ce,resolveRankSeekTuple as nn,RANK_TIEBREAK as ye,CountRlsUnsupportedError as it,stripReservedPatchFields as on,normalizeIdStructurally as rn,assertValidClientId as sn,aggregateSqlFunction as $e,softDeleteScope as _e,compileWhereSql as he,normalizeOrderKeys as an,uniqueIndexFields as cn,equalityPinnedFields as dn,buildSeekWhere as ln,decodeCursor as un,resolveRelationPredicates as ot,resolveWith as rt,relationHooks as st,applySelect as at,encodeCursor as fn,NotFoundError as wn,applyOnDelete as $n,ConflictError as Ae,normalizeCountArgument as _n,selectIndexForCount as hn,encodeAggregateKey as Y,aggregateTableName as Q,selectIndexForAggregate as En,readAggregateValue as qe,runTriggers as yn,matchesRankStaticWhere as ct,rankPivotConditionSql as pt,CURSOR_PREFIX as pn,selectIndexForGroupBy as Rn,tiebreakDirectionFor as Sn,fanOutScalarCounts as gn,matchesStaticWhere as De,foldAggregateTally as dt,coerceAggregateNumber as Be,CDC_LOG_TABLE_SEQ_INDEX as Tn,NotUniqueError as vn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{d as Rt,b as mn,e as St,n as In,c as bn}from"./value-codec-DC_dHxUY.mjs";import{runSqlGlobalTableMigrations as Cn,runSqlAggregateMigrations as An,runSqlRankMigrations as Ln}from"./runSqlAggregateMigrations-B9-Aq3_d.mjs";import{queryAll as m,queryRun as M,createIndexIfNotExists as kn,decodeRow as ee,serializeDocumentColumn as J,columnRefSql as O,decodeRows as lt,tableColumns as gt,OCC_VERSION_COLUMN as ut,serializeColumnValue as Oe,forEachRowPaged as ft,BACKFILL_BATCH_SIZE as Fe,queryBatch as wt}from"./decodeGlobalRow-C5EqHgwt.mjs";import{decodeGlobalRow as gi}from"./decodeGlobalRow-C5EqHgwt.mjs";const Mn=(a,c)=>{if(a.size<c)return;const h=a.keys().next().value;h!==void 0&&a.delete(h)},$t=50,Nn=(a,c={})=>{const h=c.maxBatch??$t,r=Number.isInteger(h)&&h>0?h:$t,p=new Map;let w=!1;const d=async(g,v)=>{const I=[...v.keys()];for(let C=0;C<I.length;C+=r){const N=I.slice(C,C+r);try{const W=await a(g,N);for(const G of N){const V=W.get(G);for(const ie of v.get(G)??[])ie.resolve(V)}}catch(W){for(const G of N)for(const V of v.get(G)??[])V.reject(W)}}},L=()=>{w=!1;const g=[...p.entries()];p.clear();for(const[v,I]of g)d(v,I).catch(()=>{})};return{async load(g,v){return new Promise((I,C)=>{let N=p.get(g);N||(N=new Map,p.set(g,N));const W=N.get(v);W?W.push({reject:C,resolve:I}):N.set(v,[{reject:C,resolve:I}]),w||(w=!0,queueMicrotask(L))})}}},qn=new Set(["_id","id"]),Pe=(a,c,h)=>a==="postgres"?e`${c} IS NOT DISTINCT FROM ${h}`:a==="mysql"?e`${c} <=> ${h}`:e`${c} IS ${h}`,Tt=(a,c)=>a.name!=="postgres"||c.nullable!==!0?"":c.direction==="desc"?" NULLS LAST":" NULLS FIRST",Dn=(a,c)=>{const h=a.map(r=>e`${O(r.field)} ${e.raw(`${r.direction==="desc"?"DESC":"ASC"}${Tt(c,r)}`)}`);if(!a.some(r=>qn.has(r.field))){const r=Sn(a);h.push(e`${O("id")} ${e.raw(r==="desc"?"DESC":"ASC")}`)}return e.join(h,e`, `)},_t=50,Bn=(a,c,h)=>{const r={...c};for(const[p,w]of gt(a)){if(w.serverDefault){r[p]=w.serverDefault({auth:h});continue}r[p]===void 0&&(w.defaultFn?r[p]=w.defaultFn():"defaultValue"in w&&(r[p]=w.defaultValue))}return r},ht=(a,c,h,r)=>{for(const[p,w]of gt(a)){if(w.serverDefault){p in c&&(h[p]=w.serverDefault({auth:r}));continue}w.onUpdateFn&&!(p in c)&&(h[p]=w.onUpdateFn())}},On=128,Fn=()=>{const a=new Map;return{delete:c=>{a.delete(c)},get:c=>{const h=a.get(c);if(h!==void 0)return a.delete(c),a.set(c,h),h},set:(c,h)=>{a.has(c)?a.delete(c):Mn(a,On),a.set(c,h)}}},Wn=async(a,c,h,r,p)=>{const w=p.get(r);if(w!==void 0)return w;const d=Object.entries(h.tables).filter(([,g])=>g.shardMode===void 0||g.shardMode.kind==="global").map(([g])=>g),L=await Promise.all(d.map(async g=>({found:(await m(a,c,e`SELECT 1 FROM ${e.identifier(g)} WHERE ${e.identifier("id")} = ${r} LIMIT 1`)).length>0,tableName:g})));for(const g of L)if(g.found)return p.set(r,g.tableName),g.tableName},te=a=>a==null?null:Number(a),Un=(a,c,h)=>h.map(r=>{const p={};for(const w of c){const d=a.shape[w];p[w]=mn(r[w]??null,d&&St(d))}return{key:p,value:te(r.value)}}),xn=(a,c,h)=>[...a.partitionBy??[],...a.sortBy.map(p=>p.field),...a.where?Object.keys(a.where):[]].every(p=>c[p]===h[p]),vt=a=>a.length===1?a[0]:e`(${e.join(a,e` AND `)})`,Z=a=>e.join(a.map(c=>e`${e.identifier(c)}`),e`, `),ne=a=>e.join(a.map(c=>e`${c}`),e`, `),Pn=(a,c,h,r,p)=>{const w=[];for(let d=0;d<h.length+1;d+=1){const L=h[d],g=c.sortBy[d],v=d<h.length&&L!==void 0&&g!==void 0,I=g?.direction==="desc"?"desc":"asc",C=v?pt(L,r[L],I,!1):e`${e.identifier(ye)} < ${p}`;if(C===void 0)continue;const N=h.slice(0,d).map(W=>Pe(a,e`${e.identifier(W)}`,r[W]));N.push(C),w.push(vt(N))}return w.length>0?e.join(w,e` OR `):e`1 = 0`},Hn=(a,c,h)=>{if(h.length!==c.length)return;const r=[];for(const[p,w]of c.entries()){const d=pt(w.column,h[p],w.direction,!0);if(d===void 0)continue;const L=[];for(let g=0;g<p;g+=1){const v=c[g];v!==void 0&&L.push(Pe(a,e`${e.identifier(v.column)}`,h[g]))}L.push(d),r.push(vt(L))}return r.length===0?e`(1 = 0)`:e`(${e.join(r,e` OR `)})`},Kn=(a,c)=>{if(a.sortBy.length===0)throw new T("INTERNAL",`rankIndex "${a.name}" requires at least one "sortBy" column for stable pagination`);const h=[{column:"__partition__",direction:"asc",nullable:!1}];for(const[r,p]of a.sortBy.entries())h.push({column:c[r]??Ee(r),direction:p.direction,nullable:!0});return h.push({column:ye,direction:"asc",nullable:!1}),h},jn=async(a,c,h,r,p)=>{const d=[];for(let I=0;I<p.length;I+=50)d.push(p.slice(I,I+50));const L=await Promise.all(d.map(async I=>m(a,c,e`SELECT * FROM ${e.identifier(r)} WHERE ${e.identifier("id")} IN (${ne(I)})`))),g=new Map;for(const I of L)for(const C of I)g.set(C.id,C);const v=[];for(const I of p){const C=ee(h,g.get(I));C&&v.push(C)}return v},Gn=a=>{const c=JSON.stringify(a),h=new TextEncoder().encode(c);let r="";for(const p of h)r+=String.fromCodePoint(p);return pn+btoa(r)},mt=a=>{if(a===void 0)return!1;const c=St(a);return c==="any"||c==="bigint"||c==="from"||c==="union"},Ue=(a,c,h)=>{if(mt(a.shape[c]))throw new T("BAD_REQUEST",`${h}: "${c}" may hold an order-preserving key rather than a value SQL can reduce or group — declare an aggregateIndex covering this (by, field, op) so the maintained companion answers it instead (its running total is a REAL, so it stays exact only while the total is inside 2^53)`)},Vn=(a,c,h,r)=>{for(const p of h)Ue(a,p,`groupBy(${c}, { by: [..."${p}"] })`);r.field!==void 0&&Ue(a,r.field,`groupBy(${c}, { agg: { op: "${r.op}", field: "${r.field}" } })`)},xe="__cdc_sweep",It="global",Yn=6e4,Xn=1e4,zn=3e4;let Et=0;const Qn=async(a,c)=>{const{autoincrementPrimaryKey:h,key:r,real:p,text:w}=c.companionTypes;await M(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(P)} (${e.identifier("seq")} ${e.raw(h)}, ${e.identifier("ts")} ${e.raw(p)} NOT NULL, ${e.identifier("table")} ${e.raw(r)} NOT NULL, ${e.identifier("id")} ${e.raw(r)} NOT NULL, ${e.identifier("op")} ${e.raw(r)} NOT NULL, ${e.identifier("doc")} ${e.raw(w)})`);const d=c.indexKeyPrefix?.("string");await kn(a,c,{columns:e`${d===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(d))})`}, ${e.identifier("seq")}`,name:Tn,table:P,unique:!1}),await M(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(xe)} (${e.identifier("id")} ${e.raw(r)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(p)} NOT NULL)`),await M(a,c,e`INSERT INTO ${e.identifier(xe)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${It}, ${0}) ${c.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},Jn=async(a,c,h)=>{const r=e`UPDATE ${e.identifier(xe)} SET ${e.identifier("lease_until")} = ${h+Yn} WHERE ${e.identifier("id")} = ${It} AND ${e.identifier("lease_until")} <= ${h}`;if(c.supportsReturning)return(await m(a,c,e`${r} RETURNING ${e.identifier("id")}`)).length>0;const p=await M(a,c,r);return(c.affectedRows?c.affectedRows(p??{rowsAffected:0}):0)>0},Zn=async(a,c,h,r)=>{if(!await Jn(a,c,r))return;const p=r-h;await M(a,c,e`
2
- DELETE FROM ${e.identifier(P)} WHERE ${e.identifier("seq")} IN (
3
- SELECT ${e.identifier("seq")} FROM (
4
- SELECT ${e.identifier("seq")} FROM ${e.identifier(P)} WHERE ${e.identifier("ts")} <= ${p} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(Xn))}
5
- ) AS ${e.identifier("expired")}
6
- )
7
- `)},bt=async(a,c)=>{const h=await m(a,c,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(P)}`),r=Number(h[0]?.seq??Number.NaN);return Number.isFinite(r)?r:void 0},ei=async(a,c)=>{if(c.name!=="sqlite")return;const h=await m(a,c,e`SELECT ${e.identifier("seq")} AS ${e.identifier("seq")} FROM ${e.identifier("sqlite_sequence")} WHERE ${e.identifier("name")} = ${P}`),r=Number(h[0]?.seq??Number.NaN);return Number.isFinite(r)?r:0},ti=a=>JSON.stringify(In(a)?bn(a):a),ni=async(a,c,h,r,p,w,d)=>{await M(a,d,e`INSERT INTO ${e.identifier(P)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${c}, ${h}, ${r}, ${p}, ${w===void 0?null:ti(w)})`)},hi=async(a,c,h)=>{const r=c.sinceSeq??0,p=Math.max(1,Math.min(c.limit??1e3,1e4)),w=await bt(a,h),d=await ei(a,h);if(d!==void 0&&r>d)throw Jt(d,r,"global");if(w!==void 0&&Zt(w,r))throw en(w,r,"global");const g=(await m(a,h,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(P)} WHERE seq > ${r} ORDER BY seq ASC LIMIT ${e.raw(String(p))}`)).map(v=>{const{doc:I}=v,C={id:String(v.id),op:String(v.op),seq:Number(v.seq),table:String(v.table),ts:Number(v.ts)};return typeof I=="string"?{...C,doc:Rt(JSON.parse(I))}:C});return{changes:g,cursor:g.at(-1)?.seq??r}},ii=async(a,c,h,r={})=>{if(r.cursorOnly){const g=await m(a,h,e`SELECT MAX(seq) AS seq FROM ${e.identifier(P)}`),v=Number(g[0]?.seq??c);return{cursor:Number.isFinite(v)?v:c,tables:[]}}const p=await m(a,h,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(P)} WHERE seq > ${c} GROUP BY ${e.identifier("table")}`);let w=c;const d=[];for(const g of p){const v=Number(g.seq);Number.isFinite(v)&&v>w&&(w=v),d.push(String(g.table))}const L=r.retained===!0?await bt(a,h):void 0;return{cursor:w,tables:d,...L===void 0?{}:{floor:L}}},oi=/string or blob too big/iu,ri=/row is too big/iu,si=(a,c)=>{const{code:h,errno:r}=c,p=c instanceof Error?c.message:"";switch(a.name){case"mysql":return r===1118||h==="ER_TOO_BIG_ROWSIZE"?"InnoDB's per-row ceiling — roughly 8 KB, half a 16 KB page, for the part of the row stored inline":void 0;case"postgres":return ri.test(p)?"the 8 KB heap page a tuple must fit once its wide columns have been TOASTed out":void 0;default:return oi.test(p)?"the storage engine's per-row ceiling (2 MB on D1)":void 0}},ai=(a,c,h)=>{const r=si(a,c);if(r!==void 0)throw new T("PAYLOAD_TOO_LARGE",`document is too large to store in "${h}": a single row cannot exceed ${r}. The limit is on the STORED bytes, which are UTF-8. Keep the payload in R2 (ctx.storage) and store a reference on the row.`)},yt=(a,c,h)=>{throw a.isUniqueViolation(c)?new Ae(`unique constraint violation on "${h}"`,"unique"):(ai(a,c,h),c)},We=new WeakMap,Ei=a=>{const{crossShardCounter:c,crossShardReader:h,exec:r,maxRelationKeys:p,schema:w}=a,{dialect:d}=a,L={fieldRef:O,...d.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...d.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...d.name==="sqlite"?{}:{inList:zt}},g=new WeakMap,v=t=>{const n=g.get(t);if(n!==void 0)return n;const i={...L,serialize:(o,s)=>J(t,s,o)};return g.set(t,i),i},I=(t,n)=>Pe(d.name,t,n),C=t=>{const n=Z(t.columns),i=ne(t.values),o=u=>d.name==="mysql"?e`VALUES(${e.identifier(u)})`:e`excluded.${e.identifier(u)}`,s=u=>d.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(u)}`:e`${e.identifier(u)}`,l=e.join(Object.entries(t.set(o,s)).map(([u,y])=>e`${e.identifier(u)} = ${y}`),e`, `),E=d.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${l}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${l}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${i}) ${E}`},N=a.clock??(()=>Date.now()),W=a.idGenerator??(()=>crypto.randomUUID()),G=a.cdc??!1,V=typeof a.cdcRetentionMs=="number"&&Number.isFinite(a.cdcRetentionMs)&&a.cdcRetentionMs>0?a.cdcRetentionMs:void 0,ie=a.auth??{identity:null,userId:null},oe=async(t,n,i,o)=>{if(!G||(await ni(r,N(),t,n,i,o,d),V===void 0))return;const s=N();if(!(s-Et<zn)){Et=s;try{await Zn(r,d,V,s)}catch{}}},Ct=a.scheduler??Qt,Le=Fn();let pe=0;const ke=a.provisionScope??{},U=async()=>{const t=We.get(ke);if(t)return t;const n=(async()=>{await Cn(r,w,d),await An(r,w,d),await Ln(r,w,d),await Wt(r,d),await Pt(r,w,d),G&&await Qn(r,d)})().catch(i=>{throw We.delete(ke),i});return We.set(ke,n),n},re=async(t,n)=>{await U();const i=await Wn(r,d,w,t,Le);if(!(n!==void 0&&i!==n))return i},se=new Map,He=async(t,n)=>{const i=Q(t,n);return(await m(r,d,d.tableExists(i))).length>0},Re=async(t,n)=>{const i=`${t}::${n.name}`,o=se.get(i);if(o!==void 0)return o;if(!await He(t,n.name))return se.set(i,!1),!1;const l=w.tables[t];if(!l)return se.set(i,!1),!1;const E=n.by??[],u=new Map;await ft(r,d,l,t,$=>{if(n.where&&!De($,n.where))return;const _=Y(E,$);dt(u,_,n,$)});const y=Q(t,n.name);await M(r,d,e`DELETE FROM ${e.identifier(y)}`);const f=[];for(const[$,_]of u)f.push(e`INSERT INTO ${e.identifier(y)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${$}, ${_.value}, ${_.count})`);return await wt(r,d,f),se.set(i,!0),!0},At=async(t,n,i,o)=>{const s=new Map;let l,E=!0;for(;E;){const u=l===void 0?o:[...o,e`${e.identifier("id")} > ${l}`],y=u.length>0?e` WHERE ${e.join(u,e` AND `)}`:e``,f=await m(r,d,e`SELECT ${e.identifier("id")}, ${O(i.field??"")} FROM ${e.identifier(n)}${y} ORDER BY ${e.identifier("id")} ASC LIMIT ${e.raw(String(Fe))}`);for(const $ of lt(t,f))dt(s,"",i,$);l=f.at(-1)?.id,E=f.length===Fe}return s.get("")?.value??null},Lt=async(t,n,i)=>{const o=n.field??"",s=[],l=w.tables[t],E=($,_)=>l?J(l,$,_):Oe(_);for(const $ of n.by??[]){const _=E($,i[$]??null);s.push(_===null?e`${O($)} IS NULL`:e`${O($)} = ${_}`)}for(const[$,_]of Object.entries(n.where??{})){const R=_!==null&&typeof _=="object"&&!Array.isArray(_)?_.eq:_,S=E($,R);s.push(S===null?e`${O($)} IS NULL`:e`${O($)} = ${S}`)}const u=s.length>0?e` WHERE ${e.join(s,e` AND `)}`:e``;if(l&&mt(l.shape[o]))return At(l,t,n,s);const y=$e(n.op),f=await m(r,d,e`SELECT ${e.raw(y)}(${O(o)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}${u}`);return te(f[0]?.value)},kt=async(t,n)=>{await M(r,d,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},Mt=async(t,n,i,o)=>{const s=Q(t,n.name),{op:l}=n,E=n.field??"",u=i&&(!n.where||De(i,n.where))?i:void 0,y=o&&(!n.where||De(o,n.where))?o:void 0;if(!(!u&&!y)){if(l==="count"||l==="sum"||l==="avg"){const f=new Set;for(const[$,_]of[[u,-1],[y,1]]){if(!$)continue;const R=l==="count"?1:Be($[E]);if(R===void 0)continue;const S=Y(n.by??[],$);f.add(S),await M(r,d,C({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(b,A)=>({__count__:e`${A("__count__")} + ${b("__count__")}`,__value__:l==="count"?e`${A("__value__")} + ${b("__value__")}`:e`COALESCE(${A("__value__")}, 0) + ${b("__value__")}`}),table:s,values:[S,_*R,_]}))}for(const $ of f)await kt(s,$);return}if(u){const f=Y(n.by??[],u),$=Be(u[E]),R=(await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${f}`))[0],S=te(R?.value),b=(R?.count??0)-1;if(b<=0)await M(r,d,e`DELETE FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${f}`);else if(R&&$!==void 0&&S!==null&&$===S){const A=await Lt(t,n,u);await M(r,d,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__value__")} = ${A}, ${e.identifier("__count__")} = ${b} WHERE ${e.identifier("__key__")} = ${f}`)}else await M(r,d,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${f}`)}if(y){const f=Y(n.by??[],y),$=Be(y[E]);if($===void 0)await M(r,d,C({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(_,R)=>({__count__:e`${R("__count__")} + 1`}),table:s,values:[f,null,1]}));else{const _=l==="min"?"MIN":"MAX";await M(r,d,C({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(R,S)=>({__count__:e`${S("__count__")} + 1`,__value__:e`${e.raw(_)}(COALESCE(${S("__value__")}, ${R("__value__")}), ${R("__value__")})`}),table:s,values:[f,$,1]}))}}}},Se=async t=>{const n=w.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const i of n)await Re(t,i)},ae=async(t,n,i)=>{const o=w.tables[t]?.aggregateIndexes;if(!(!o||o.length===0))for(const s of o){const l=`${t}::${s.name}`;(se.get(l)??await He(t,s.name))&&await Mt(t,s,n,i)}},ce=new Map,Ke=async(t,n)=>{const i=we(t,n);return(await m(r,d,d.tableExists(i))).length>0},Me=async(t,n)=>{const i=`${t}::rank::${n.name}`,o=ce.get(i);if(o!==void 0)return o;if(!await Ke(t,n.name))return ce.set(i,!1),!1;const l=w.tables[t];if(!l)return ce.set(i,!1),!1;const E=we(t,n.name);await M(r,d,e`DELETE FROM ${e.identifier(E)}`);const u=n.sortBy.map((_,R)=>Ee(R)),y=Z(["__id__","__partition__",...u]);let f=[];const $=async()=>{if(f.length===0)return;const _=f;f=[],await wt(r,d,_)};return await ft(r,d,l,t,async _=>{if(n.where&&!ct(_,n.where))return;const R=Ce(n.partitionBy??[],_),S=n.sortBy.map(b=>Oe(_[b.field]??null));f.push(e`INSERT INTO ${e.identifier(E)} (${y}) VALUES (${ne([_._id,R,...S])})`),f.length>=Fe&&await $()}),await $(),ce.set(i,!0),!0},ge=async t=>{const n=w.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const i of n)await Me(t,i)},X=async(t,n,i,o)=>{const s=w.tables[t],l=s?.rankIndexes;if(!l||l.length===0)return;const E=s?.softDeleteMode?.field,u=E===void 0||o===void 0?void 0:o[E],y=u!=null;for(const f of l){if(i!==void 0&&o!==void 0&&xn(f,i,o))continue;const $=`${t}::rank::${f.name}`;if(!(ce.get($)??await Ke(t,f.name)))continue;const S=we(t,f.name);if(i&&await M(r,d,e`DELETE FROM ${e.identifier(S)} WHERE ${e.identifier("__id__")} = ${n}`),o&&!y){if(f.where&&!ct(o,f.where))continue;const b=f.sortBy.map((D,j)=>Ee(j)),A=Z(["__id__","__partition__",...b]),F=Ce(f.partitionBy??[],o),k=f.sortBy.map(D=>Oe(o[D.field]??null));await M(r,d,e`INSERT INTO ${e.identifier(S)} (${A}) VALUES (${ne([n,F,...k])})`)}}},de=xt({dialect:d,exec:r,schema:w}),je=new Set;for(const[t,n]of Object.entries(w.tables))for(const i of Object.values(n.triggerMap??{}))je.add(`${t} ${i.timing} ${i.op}`);const H=(t,n,i)=>je.has(`${t} ${n} ${i}`);let Ge;const K=async(t,n,i)=>{if(pe+=1,pe>_t)throw pe-=1,new Ae(`trigger recursion exceeded ${String(_t)} levels on "${i.table}" — check for a self-triggering write`,"trigger");try{await yn({ctx:Ge,event:i,op:n,schema:w,tableName:i.table,timing:t})}finally{pe-=1}},Nt=async(t,n)=>{try{await M(r,d,n)}catch(i){yt(d,i,t)}},Te=async(t,n)=>(await m(r,d,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],ve=async(t,n,i,o)=>{if(o===void 0)return;const s=e`${e.identifier(ut)}`,l=e.join([I(e`${e.identifier("id")}`,o.id),I(s,o[ut]??null)],e` AND `),E=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${i}, ${s} = COALESCE(${s}, 0) + 1 WHERE ${l}`:e`DELETE FROM ${e.identifier(t)} WHERE ${l}`,u=()=>{throw new Ae(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(d.supportsReturning)(await m(r,d,e`${E} RETURNING ${e.identifier("id")}`)).length===0&&u();else{const y=await M(r,d,E);(d.affectedRows?d.affectedRows(y??{rowsAffected:0}):0)===0&&u()}}catch(y){yt(d,y,t)}},qt=(t,n,i,o)=>{const s=Object.keys(t.shape);return{columns:["id","_creationTime",...s],values:[n,i,...s.map(l=>J(t,l,o[l]??null))]}},Dt=async(t,n,i,o)=>{const s=Rn(n,i.op,i.field,o.by,o.where);if(!s||!await Re(t,s.index))return;const E=Q(t,s.index.name),u=Object.keys(s.partial);if(u.length===(s.index.by??[]).length&&u.length>0){const f=Y(s.index.by??[],s.partial),$=await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(E)} WHERE ${e.identifier("__key__")} = ${f}`);if($.length===0)return[];const _=$[0];return[{key:{...s.partial},value:qe(i.op,{count:_.count,value:te(_.value)})}]}return u.length>0?void 0:(await m(r,d,e`SELECT ${e.identifier("__key__")} AS ${e.identifier("key")}, ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(E)}`)).map(f=>{const $=f;return{key:Rt(JSON.parse($.key)),value:qe(i.op,{count:$.count,value:te($.value)})}})},Ve=t=>{const n=w.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},Ye=t=>{throw new T("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`)},Bt=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new T("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 i={};if(n?.relationBaseWhere)for(const o of Object.keys(w.tables)){const s=n.relationBaseWhere(o);s!==void 0&&(i[o]=s)}return{orderBy:n?.orderBy,relationPolicies:i,where:B(n?.baseWhere,n?.where),with:n?.with}},Xe=(t,n)=>Ve(t)?h?h(t,Bt(t,n)):Ye(t):x.findMany(t,n),me=(t,n,i)=>ot(t,{fetcher:Xe,maxRelationKeys:p,relationBaseWhere:i,schema:w,tableName:n}),Ot=Nn(async(t,n)=>{const i=await m(r,d,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${ne(n)})`),o=new Map;for(const s of i){const{id:l}=s;typeof l=="string"&&o.set(l,s)}return o}),x={async cdcChangedTables(t,n){if(G)try{return await U(),await ii(r,t,d,{...n,retained:V!==void 0})}catch{return}},async aggregate(t,n){const i=w.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);if(await U(),$e(n.op),n.op==="count")return x.count(t,{baseWhere:n.baseWhere,relationBaseWhere:n.relationBaseWhere,restrictsCounts:n.restrictsCounts,where:n.where});if(!n.field)throw new T("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const o=_e(i.softDeleteMode,void 0),s=B(B(n.baseWhere,n.where),o),l=await me(s,t,n.relationBaseWhere),E=l!==s;if(i.aggregateIndexes&&!n.baseWhere&&!E&&!o){const R=En(i.aggregateIndexes,n.op,n.field,n.where);if(R&&await Re(t,R.index)){const b=Y(R.index.by??[],R.key),A=Q(t,R.index.name),k=(await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(A)} WHERE ${e.identifier("__key__")} = ${b}`))[0];return qe(n.op,k===void 0?void 0:{count:k.count,value:te(k.value)})}}Ue(i,n.field,`aggregate(${t}, { op: "${n.op}", field: "${n.field}" })`);const u=he(l,v(i)),y=e.raw($e(n.op)),f=e`SELECT ${y}(${O(n.field)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}`,_=(await m(r,d,u?e`${f} WHERE ${u}`:f))[0]?.value;return _==null?null:Number(_)},async count(t,n){const i=w.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=_n(n);if(o.restrictsCounts)throw new it(t);const s=_e(i.softDeleteMode,void 0),l=B(B(o.baseWhere,o.where),s),E=await me(l,t,o.relationBaseWhere),u=E!==l;if(i.aggregateIndexes&&!o.baseWhere&&!u&&!s){const _=hn(i.aggregateIndexes,o.where);if(_&&await Re(t,_.index)){const S=Y(_.index.by??[],_.key),b=Q(t,_.index.name),A=await m(r,d,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")} FROM ${e.identifier(b)} WHERE ${e.identifier("__key__")} = ${S}`);return Number(A[0]?.value??0)}}const y=he(E,v(i)),f=e`SELECT COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(t)}`,$=await m(r,d,y?e`${f} WHERE ${y}`:f);return Number($[0]?.count??0)},async delete(t,n,i){const o=await re(t,n);if(!o)return;const s=w.tables[o];if(!s)return;const l=await Te(o,t),E=ee(s,l),u=i?.hard===!0,y=!u&&s.softDeleteMode?s.softDeleteMode.field:void 0;if(!(y&&(!E||E[y]!==null&&E[y]!==void 0))){if(H(o,"before","delete")&&await K("before","delete",{id:t,op:"delete",previous:E??void 0,table:o}),await $n({deletedId:t,deletedReference:f=>E?.[f],findHolders:async(f,$,_)=>{if(w.tables[f]?.shardMode?.kind==="shardBy")throw new T("INTERNAL",`cross-backend cascade from global '${o}' into shardBy '${f}' is not supported — would require Query Coordinator fan-out across shards`);return(await x.findMany(f,{includeDeleted:u,where:{[$]:_}})).page},onCascade:(f,$)=>x.delete($,void 0,i),onRestrict:f=>{throw new Ae(f,"restrict")},onSetNull:(f,$,_)=>x.patch($,{[_]:null}),schema:w,tableName:o}),await Se(o),await ge(o),y&&E){const f={...E,[y]:N()},$=e.join(Object.keys(s.shape).map(_=>e`${e.identifier(_)} = ${J(s,_,f[_]??null)}`),e`, `);await ve(o,"UPDATE",$,l),await ae(o,E,f),await X(o,t,E,void 0),await de(o,t,f,E),await oe(o,t,"update",f),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:E,table:o});return}await ve(o,"DELETE",void 0,l),Le.delete(t),await ae(o,E??void 0,void 0),await X(o,t,E??void 0,void 0),await de(o,t,void 0),await oe(o,t,"delete"),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:E??void 0,table:o})}},async findFirst(t,n={}){return(await x.findMany(t,{...n,limit:1})).page[0]??null},async findFirstOrThrow(t,n={}){const i=await x.findFirst(t,n);if(i===null)throw new wn(`findFirstOrThrow: no "${t}" document matched`);return i},async findMany(t,n={}){const i=w.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=an(n.orderBy,i.shape,{pinned:dn(n.where),uniqueBy:cn(i.indexes,i.shape)}),s=n.cursor?ln(o,un(n.cursor)):void 0,l=Xe,E=async(k,D,j,Ie)=>{if(Ve(k))return c?gn(c,k,D,j,Ie):Ye(k);const le=w.tables[k];if(!le)throw new T("INTERNAL",`unknown table: ${k}`);const be=_e(le.softDeleteMode,void 0),z={[D]:{in:j}},q=B(B(z,Ie),be),ue=await me(q,k,void 0),ze=he(ue,v(le)),Qe=O(D);let fe=e`SELECT ${Qe} AS __fk__, COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(k)}`;ze&&(fe=e`${fe} WHERE ${ze}`),fe=e`${fe} GROUP BY ${Qe}`;const Ft=await m(r,d,fe),Je=new Map;for(const Ze of Ft)Je.set(Ze.__fk__,Number(Ze.count??0));return Je};let u=B(n.baseWhere,n.where);u=B(u,_e(i.softDeleteMode,n.includeDeleted)),u=await ot(u,{fetcher:l,maxRelationKeys:p,relationBaseWhere:n.relationBaseWhere,schema:w,tableName:t}),s&&(u=u?{AND:[u,s]}:s);const y=he(u,v(i)),f=Dn(o,d);let $=e`SELECT * FROM ${e.identifier(t)}`;y&&($=e`${$} WHERE ${y}`),$=e`${$} ORDER BY ${f}`;const _=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;_!==void 0&&($=e`${$} LIMIT ${e.raw(String(_+1))}`);const R=await m(r,d,$),S=lt(i,R);if(_===void 0)return n.with&&await rt({fetcher:l,groupedCounter:E,parents:S,...st(n),schema:w,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:at(S,n.select,n.with)};const b=S.length>_,A=b?S.slice(0,_):S,F=A.at(-1);return n.with&&await rt({fetcher:l,groupedCounter:E,parents:A,...st(n),schema:w,tableName:t,with:n.with}),{continueCursor:b&&F?fn(F,o):null,isDone:!b,page:at(A,n.select,n.with)}},async get(t,n){const i=await re(t,n);if(!i)return null;const o=w.tables[i];return o?ee(o,await Ot.load(i,t)):null},async groupBy(t,n){const i=w.tables[t];if(!i)throw new T("INTERNAL",`unknown table: ${t}`);await U();const o=n.agg??{op:"count"};if($e(o.op),o.op!=="count"&&!o.field)throw new T("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);const s=_e(i.softDeleteMode,void 0),l=B(B(n.baseWhere,n.where),s),E=await me(l,t,n.relationBaseWhere),u=E!==l;if(i.aggregateIndexes&&!n.baseWhere&&!u&&!s){const S=await Dt(t,i.aggregateIndexes,o,n);if(S!==void 0)return S}Vn(i,t,n.by,o);const y=he(E,v(i)),f=n.by.map(S=>e`${O(S)} AS ${e.identifier(S)}`);if(o.op==="count")f.push(e`COUNT(*) AS ${e.identifier("value")}`);else{if(!o.field)throw new T("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);f.push(e`${e.raw($e(o.op))}(${O(o.field)}) AS ${e.identifier("value")}`)}const $=e.join(n.by.map(S=>O(S)),e`, `);let _=e`SELECT ${e.join(f,e`, `)} FROM ${e.identifier(t)}`;y&&(_=e`${_} WHERE ${y}`),_=e`${_} GROUP BY ${$}`;const R=await m(r,d,_);return Un(i,n.by,R)},async insert(t,n,i){const o=w.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);await U();const s=Bn(o,n,ie);Ne(o,s);let l,E=!0;i?.clientId!==void 0?(sn(i.clientId),l=i.clientId):i?.allowExplicitId&&typeof s._id=="string"?l=s._id:(l=W(),E=!1);const u=i?.allowExplicitId&&typeof s._creationTime=="number"?s._creationTime:N(),y={...s,_creationTime:u,_id:l};H(t,"before","insert")&&await K("before","insert",{doc:{...y},id:l,op:"insert",table:t}),await Se(t),await ge(t);const{columns:f,values:$}=qt(o,l,u,s);return await Nt(t,e`INSERT INTO ${e.identifier(t)} (${Z(f)}) VALUES (${ne($)})`),E&&Le.set(l,t),await ae(t,void 0,y),await X(t,l,void 0,y),await de(t,l,y),await oe(t,l,"insert",y),H(t,"after","insert")&&await K("after","insert",{doc:y,id:l,op:"insert",table:t}),l},normalizeId(t,n){return rn(w,t,n)},async patch(t,n,i){et("patch",n);const o=await re(t,i);if(!o)throw new T("INTERNAL",`document not found: ${t}`);const s=w.tables[o];if(!s)throw new T("INTERNAL",`document not found: ${t}`);const l=await Te(o,t),E=ee(s,l);if(!E)throw new T("INTERNAL",`document not found: ${t}`);const u={...E,...on(n),_id:t};ht(s,n,u,ie),Ne(s,u,!0),H(o,"before","update")&&await K("before","update",{doc:{...u},id:t,op:"update",previous:E,table:o}),await Se(o),await ge(o);const y=Object.keys(s.shape),f=e.join(y.map($=>e`${e.identifier($)} = ${J(s,$,u[$]??null)}`),e`, `);await ve(o,"UPDATE",f,l),await ae(o,E,u),await X(o,t,E,u),await de(o,t,u,E),await oe(o,t,"update",u),H(o,"after","update")&&await K("after","update",{doc:u,id:t,op:"update",previous:E,table:o})},async restore(t,n){const i=await re(t,n);if(!i)throw new T("INTERNAL",`document not found: ${t}`);const o=w.tables[i],s=o?.softDeleteMode?.field;if(!o||!s)throw new T("INTERNAL",`ctx.db.restore: table "${i}" is not a .softDelete() table`);const l=await Te(i,t),E=l?.[s]!==null&&l?.[s]!==void 0;if(await x.patch(t,{[s]:null},n),E){const u=ee(o,l);u!==null&&await X(i,t,void 0,{...u,[s]:null})}},query(t){const n=w.tables[t];if(!n)throw new T("INTERNAL",`unknown table: ${t}`);const i="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",o=[],s=u=>o.every(y=>y(u)),l=async(u,y)=>{await U();const f=o.length>0,$=await Gt(r,d,n,t,u,Vt(f?void 0:y));if(!f)return y===void 0&&Yt($),$;const _=$.filter(R=>s(R));return y===void 0?_:_.slice(0,y)},E=u=>{const y={async*[Symbol.asyncIterator](){if(!u)throw new T("INTERNAL",i);yield*await l(u,void 0)},async collect(){if(!u)throw new T("INTERNAL",i);return l(u,void 0)},async collectWithScores(){throw new T("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(f){return o.push(f),y},async first(){if(!u)throw new T("INTERNAL",i);return(await l(u,1))[0]??null},order(){return y},async paginate(f){if(!u)throw new T("INTERNAL",i);const $=Kt(f);return jt(await l(u,Xt($)),$)},async take(f){if(!u)throw new T("INTERNAL",i);return l(u,f)},async unique(){if(!u)throw new T("INTERNAL",i);const f=await l(u,2);if(f.length>1)throw new vn(`unique() on table "${t}" matched ${String(f.length)} documents; expected at most one`);return f[0]??null},withGeoIndex(){throw new T("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new T("INTERNAL",i)},withSearchIndex(f,$){const _=(n.searchIndexes??[]).find(S=>S.name===f);if(!_)throw new T("INTERNAL",`unknown search index "${f}" on table "${t}"`);const R={definition:_,field:_.field,filters:[],hasQuery:!1,indexName:f,query:""};if($(Ht(R,t,Ut(_.language))),!R.hasQuery)throw new T("INTERNAL",`search index "${f}" on table "${t}" requires a .search(field, query) call`);return E(R)}};return y};return E(void 0)},async rank(t,n,i){const o=w.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(D=>D.name===n);if(!s)throw new T("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(i.restrictsCounts)throw new it(t);if(await U(),!await Me(t,s))return null;const E=typeof i.row=="string"?i.row:i.row._id;if(!E)return null;const u=we(t,s.name),y=s.sortBy.map((D,j)=>Ee(j)),f=Z(["__partition__",...y]),_=(await m(r,d,e`SELECT ${f} FROM ${e.identifier(u)} WHERE ${e.identifier("__id__")} = ${E}`))[0];if(!_)return null;const R=_.__partition__,S=B(i.baseWhere,i.where);tt(S,w,t,"rank");const b=nt(s,S);if(b&&Ce(s.partitionBy??[],b)!==R)return null;const A=Pn(d.name,s,y,_,E),F=await m(r,d,e`SELECT COUNT(*) AS c FROM ${e.identifier(u)} WHERE ${e.identifier("__partition__")} = ${R} AND (${A})`),k=await m(r,d,e`SELECT COUNT(*) AS c FROM ${e.identifier(u)} WHERE ${e.identifier("__partition__")} = ${R}`);return{position:Number(F[0]?.c??0)+1,total:Number(k[0]?.c??0)}},async rankPage(t,n,i={}){tt(B(i.baseWhere,i.where),w,t,"rankPage");const o=w.tables[t];if(!o)throw new T("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(q=>q.name===n);if(!s)throw new T("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await U(),!await Me(t,s))return{continueCursor:null,isDone:!0,page:[]};const E=we(t,s.name),u=s.sortBy.map((q,ue)=>Ee(ue)),y=Math.max(1,Math.min(1e3,Math.floor(i.take??100))),f=B(i.baseWhere,i.where),$=nt(s,f),_=Kn(s,u),R=e.join(_.map(q=>e`${e.identifier(q.column)} ${e.raw(`${q.direction==="desc"?"DESC":"ASC"}${Tt(d,{direction:q.direction,nullable:q.nullable})}`)}`),e`, `),S=[];typeof i.partitionKey=="string"?S.push(e`${e.identifier("__partition__")} = ${i.partitionKey}`):$&&S.push(e`${e.identifier("__partition__")} = ${Ce(s.partitionBy??[],$)}`);const b=nn(i);if(b!==void 0){const q=Hn(d.name,_,b);q!==void 0&&S.push(q)}const A=Z([ye,"__partition__",...u]);let F=e`SELECT ${A} FROM ${e.identifier(E)}`;S.length>0&&(F=e`${F} WHERE ${e.join(S,e` AND `)}`),F=e`${F} ORDER BY ${R} LIMIT ${e.raw(String(y+1))}`;const k=await m(r,d,F),D=k.length>y,j=D?k.slice(0,y):k,Ie=j.map(q=>q[ye]),le=await jn(r,d,o,t,Ie);let be=null;const z=j.at(-1);if(D&&z!==void 0){const q=[z.__partition__,...u.map(ue=>z[ue]),z[ye]];be=Gn(q)}return{continueCursor:be,isDone:!D,page:le}},async replace(t,n,i,o){et("replace",n);const s=await re(t,i);if(!s)throw new T("INTERNAL",`document not found: ${t}`);const l=w.tables[s];if(!l)throw new T("INTERNAL",`document not found: ${t}`);const E=await Te(s,t);if(E===void 0)throw new T("INTERNAL",`document not found: ${t}`);const y=tn(w,s,"update")||(l.aggregateIndexes??[]).length>0||(l.rankIndexes??[]).length>0?ee(l,E)??void 0:void 0,f=o?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:void 0,$=typeof E._creationTime=="number"?E._creationTime:void 0,_=f??$??N(),R={...n,_creationTime:_,_id:t};ht(l,n,R,ie),Ne(l,R),H(s,"before","update")&&await K("before","update",{doc:{...R},id:t,op:"update",previous:y,table:s}),await Se(s),await ge(s);const S=Object.keys(l.shape),b=e.join([e`${e.identifier("_creationTime")} = ${_}`,...S.map(A=>e`${e.identifier(A)} = ${J(l,A,R[A]??null)}`)],e`, `);await ve(s,"UPDATE",b,E),await ae(s,y,R),await X(s,t,y,R),await de(s,t,R,y),await oe(s,t,"update",R),H(s,"after","update")&&await K("after","update",{doc:R,id:t,op:"update",previous:y,table:s})}};return Ge={db:x,scheduler:Ct},x};export{Ri as backfillSqlSearchIndexes,Ei as createSqlCtxDb,gi as decodeGlobalRow,ii as readSqlCdcChangedTables,hi as readSqlCdcChanges,bt as readSqlCdcFloor,Qn as runSqlCdcMigration,Pt as runSqlSearchMigrations,Zn as sweepSqlCdcRetention};
@@ -1 +0,0 @@
1
- import{LunoraError as S}from"@lunora/errors";import{D,c as Sn,m as hn,r as b,a as pn,l as on,w as M,b as En}from"./ctx-db-search-state-DaAD01za.mjs";import{ftsUnmappedPage as gn,groupUnmappedRows as _n,ftsWriteDocument as W,ftsPurgeDocument as sn,ftsCompanionDdl as yn,unionAll as Rn,ftsRowidMapName as Tn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{queryAll as g,decodeRow as an,runInOrder as O,queryRun as R,decodeRows as cn,queryBatch as In,createIndexIfNotExists as V,OCC_VERSION_COLUMN as An,columnRefSql as X,serializeColumnValue as Nn,readRowsPage as On,forEachRowPaged as Cn}from"./decodeGlobalRow-C5EqHgwt.mjs";const Dn=n=>{const t=atob(n),r=Uint8Array.from(t,i=>i.codePointAt(0)??0);return new TextDecoder().decode(r)},vn=()=>new S("BAD_REQUEST","invalid cursor"),Y=16,J=8,p=1024,B=(n,t)=>t.query(n),Ln=(n,t)=>{if(!t)return{exact:!0,lower:n,upper:n};const r=[...n].at(-1)??"",i=(r.codePointAt(0)??0)+1;if(i>=55296&&i<=57343||i>1114111)return{exact:!0,lower:n,upper:n};const o=n.slice(0,n.length-r.length);return{exact:!1,lower:n,upper:o+String.fromCodePoint(i)}},it=(n,t,r)=>{const i={eq:(o,s)=>{if(!n.definition.filterFields?.includes(o))throw new S("INTERNAL",`field "${o}" is not a filter field of search index "${n.indexName}" on table "${t}"`);if(n.filters.length>=J)throw new S("BAD_REQUEST",`search index "${n.indexName}" on table "${t}": at most ${String(J)} .eq() filters are supported per search query`);return n.filters.push({field:o,value:s}),i},search:(o,s)=>{const a=n;if(o!==a.definition.field)throw new S("INTERNAL",`search index "${a.indexName}" on table "${t}" indexes "${a.definition.field}", not "${o}"`);const c=B(s,r).length;if(c>Y)throw new S("BAD_REQUEST",`search index "${a.indexName}" on table "${t}": at most ${String(Y)} search terms are supported (got ${String(c)})`);return a.field=o,a.query=s,a.hasQuery=!0,i}};return i},ot=n=>{if(n.length>p)throw new S("BAD_REQUEST",`more than ${String(p)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},st=n=>Math.min(n.offset+n.numItems+1,p),Mn=n=>btoa(`search:${String(n)}`),Un=n=>{let t;try{t=Dn(n)}catch{return}if(!t.startsWith("search:"))return;const r=Number(t.slice(7));return Number.isInteger(r)&&r>=0?r:void 0},at=n=>{if(typeof n.endCursor=="string")throw new S("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(n.numItems))throw new S("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(n.numItems)}`);const t=Math.max(0,Math.floor(n.numItems)),r=n.cursor?Un(n.cursor):0;if(r===void 0)throw vn();if(r+t>=p)throw new S("BAD_REQUEST",`search pagination reaches the ${String(p)}-document limit (offset ${String(r)} + ${String(t)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,p-r-1))} or fewer, or narrow the query or the filters instead`);return{numItems:t,offset:r}},ct=(n,t)=>{const r=t.offset+t.numItems,i=t.numItems>0&&n.length>r;return{continueCursor:i?Mn(r):null,isDone:!i,page:n.slice(t.offset,r)}},ft=n=>{if(n===void 0)return p+1;if(!Number.isFinite(n))return p;const t=Math.max(0,Math.floor(n));if(t>p)throw new S("BAD_REQUEST",`search returns at most ${String(p)} documents (asked for ${String(t)}) — narrow the query or paginate instead`);return t},bn=(n,t)=>{if(!t.includes("."))return n[t];let r=n;for(const i of t.split(".")){if(r===null||typeof r!="object"||Array.isArray(r))return;r=r[i]}return r},q=(n,t)=>`${n}__fts_${t}`,l="__id__",C="__token__",F="__n__",Bn=1e3,fn=(n,t)=>t.document(n),x=(n,t)=>bn(n,t),qn=n=>typeof n=="string"?n:n==null?"":typeof n=="number"||typeof n=="bigint"||typeof n=="boolean"?String(n):JSON.stringify(n)??"",Pn=(n,t,r)=>n!==void 0&&t!==void 0&&x(n,r.field)===x(t,r.field),kn=(n,t)=>fn(qn(x(n,t.field)),D(t.language)).slice(0,Bn),v=(n,t)=>kn(n,t).join(" "),Fn=(n,t)=>{const r=new Map;for(const i of fn(n,t))r.set(i,(r.get(i)??0)+1);return r},un=[An,"_creationTime"],U=async(n,t,r,i)=>{await R(n,t,e`DELETE FROM ${e.identifier(r)} WHERE ${e.identifier(l)} = ${i}`)},k=(n,t)=>n.name==="mysql"?e`${e.identifier(t)}(191)`:n.textPatternOperatorClass===void 0?e`${e.identifier(t)}`:e`${e.identifier(t)} ${e.raw(n.textPatternOperatorClass)}`,K=50,xn=(n,t)=>t?e`${e.identifier(C)} LIKE ${`${n}%`}`:e`${e.identifier(C)} = ${n}`,dn=(n,t)=>{const r=t.filters.map(i=>e`m.${X(i.field)} = ${Nn(i.value)}`);return n.softDeleteMode&&r.push(e`m.${X(n.softDeleteMode.field)} IS NULL`),r},$n=async(n,t,r,i,o,s,a)=>{const c=dn(r,o);let f=e`SELECT m.* FROM (${a}) s JOIN ${e.identifier(i)} m ON m.${e.identifier("id")} = s.${e.identifier(l)}`;return c.length>0&&(f=e`${f} WHERE ${e.join(c,e` AND `)}`),f=e`${f} ORDER BY s.${e.identifier("__score__")} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`,cn(r,await g(n,t,f))},Hn=async(n,t,r,i,o,s)=>{const a=B(o.query,D(o.definition.language));if(a.length===0)return[];const c=q(i,o.indexName),f=a.length-1,u=a.map((w,_)=>xn(w,_===f)),d=e.join(u,e` OR `),$=u.map(w=>e`SUM(CASE WHEN ${w} THEN ${e.identifier(F)} ELSE 0 END)`),h=e.join($.map(w=>e`${w} > 0`),e` AND `),E=e`SELECT ${e.identifier(l)}, ${e.join($,e` + `)} AS ${e.identifier("__score__")} FROM ${e.identifier(c)} WHERE ${d} GROUP BY ${e.identifier(l)} HAVING ${h}`;return $n(n,t,r,i,o,s,E)},Wn=async(n,t,r,i,o,s)=>{const a=B(o.query,D(o.definition.language));if(a.length===0)return[];const c=q(i,o.indexName),f=`${c}__vocab`,u=a.length-1,d=a.map((E,w)=>{const _=Ln(E,w===u),m=_.exact?e`${e.identifier("term")} = ${_.lower}`:e`${e.identifier("term")} >= ${_.lower} AND ${e.identifier("term")} < ${_.upper}`;return e`SELECT ${e.identifier("doc")}, ${e.raw(String(w))} AS ${e.identifier("__term__")}, COUNT(*) AS ${e.identifier("__n__")} FROM ${e.identifier(f)} WHERE ${m} GROUP BY ${e.identifier("doc")}`}),$=a.map((E,w)=>e`SUM(CASE WHEN u.${e.identifier("__term__")} = ${e.raw(String(w))} THEN u.${e.identifier("__n__")} ELSE 0 END)`),h=e`SELECT f.${e.identifier(l)} AS ${e.identifier(l)}, ${e.join($,e` + `)} AS ${e.identifier("__score__")} FROM (${Rn(d)}) u JOIN ${e.identifier(c)} f ON f.rowid = u.${e.identifier("doc")} GROUP BY f.${e.identifier(l)} HAVING ${e.join($.map(E=>e`${E} > 0`),e` AND `)}`;return $n(n,t,r,i,o,s,h)},jn=async(n,t,r,i,o,s)=>{const a=t.nativeTextSearch,c=B(o.query,D(o.definition.language));if(!a||c.length===0)return[];const f=q(i,o.indexName),u=[a.matches(f,c),...dn(r,o)],d=e`SELECT m.* FROM ${e.identifier(f)} JOIN ${e.identifier(i)} m ON m.${e.identifier("id")} = ${e.identifier(f)}.${e.identifier(l)} WHERE ${e.join(u,e` AND `)} ORDER BY ${a.rank(f,c)} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`;return cn(r,await g(n,t,d))},Qn={ensureCompanion:async(n,t,r)=>{const{integer:i,key:o}=t.companionTypes;await R(n,t,e`CREATE TABLE IF NOT EXISTS ${e.identifier(r)} (${e.identifier(C)} ${e.raw(o)} NOT NULL, ${e.identifier(l)} ${e.raw(o)} NOT NULL, ${e.identifier(F)} ${e.raw(i)} NOT NULL)`),await V(n,t,{columns:e`${k(t,C)}, ${k(t,l)}`,name:`${r}__btree`,table:r,unique:!1}),await V(n,t,{columns:k(t,l),name:`${r}__by_id`,table:r,unique:!1})},indexDocument:async(n,t,r,i,o,s)=>{await U(n,t,r,i);const a=[...Fn(v(o,s),D(s.language))],c=e.join([C,l,F].map(u=>e.identifier(u)),e`, `),f=[];for(let u=0;u<a.length;u+=K){const d=e.join(a.slice(u,u+K).map(([$,h])=>e`(${$}, ${i}, ${h})`),e`, `);f.push(e`INSERT INTO ${e.identifier(r)} (${c}) VALUES ${d}`)}await In(n,t,f)},name:"inverted",purgeDocument:U,runSearch:Hn},N=(n,t)=>e`${e.identifier(n)}.${e.identifier(t)}`,wn=({row:n,table:t})=>e`EXISTS (SELECT 1 FROM ${e.identifier(t)} WHERE ${N(t,"id")} = ${n.id}${e.join(un.map(r=>e` AND ${N(t,r)} IS ${n[r]??null}`))})`,j={ensureCompanion:async(n,t,r)=>{await O(n,t,yn(r))},indexDocument:async(n,t,r,i,o,s)=>{await O(n,t,W(r,i,v(o,s)))},name:"fts5",purgeDocument:async(n,t,r,i)=>{await O(n,t,sn(r,i))},runSearch:Wn},Gn={ensureCompanion:async(n,t,r)=>{const i=t.nativeTextSearch;if(i){await R(n,t,i.createCompanion(r,t.companionTypes.key));for(const o of i.createIndexes(r))await R(n,t,o)}},indexDocument:async(n,t,r,i,o,s)=>{const a=t.nativeTextSearch;a&&(await U(n,t,r,i),await R(n,t,a.indexDocument(r,i,v(o,s))))},name:"native",purgeDocument:U,runSearch:jn},T=(n,t)=>n.strategy==="native"&&t.nativeTextSearch!==void 0?Gn:t.supportsFts5?j:Qn,P=(n,t)=>`${Sn(n)}/${T(n,t).name}`,Q=function*(n){for(const[t,r]of Object.entries(n.tables)){const i=r.searchIndexes;if(!(r.shardMode!==void 0&&r.shardMode.kind!=="global"||!i))for(const o of i)yield[t,r,o]}},I=(n,t)=>q(n,t.name),z=100,Z=50,Vn=async(n,t,r,i,o,s,a)=>{const c=String(a.row.id);if(n!==j){await n.indexDocument(t,r,i,c,o,s);return}await O(t,r,W(i,c,v(o,s),{guard:wn(a)}))},H=async(n,t,r,i,o,s=0)=>{const a={done:!0,last:s,left:0};if(T(o,t)!==j||(await g(n,t,t.tableExists(i))).length===0)return a;const f=I(i,o),u=await g(n,t,gn(f,z,s));if(u.length===0)return a;const d=Math.max(...u.map(m=>Number(m.rowid))),$=_n(u),h=[...$.keys()],E=new Map;for(let m=0;m<h.length;m+=Z){const L=h.slice(m,m+Z),A=await g(n,t,e`SELECT * FROM ${e.identifier(i)} WHERE ${N(i,"id")} IN (${e.join(L.map(y=>e`${y}`),e`, `)})`);for(const y of A)E.set(String(y.id),y)}const w=[];for(const[m,L]of $){const A=E.get(m),y=A===void 0?void 0:an(r,A),G=A===void 0?e`NOT EXISTS (SELECT 1 FROM ${e.identifier(i)} WHERE ${N(i,"id")} = ${m})`:wn({row:A,table:i});w.push(...y?W(f,m,v(y,o),{guard:G,unmappedRowids:L}):sn(f,m,{guard:G,unmappedRowids:L}))}await O(n,t,w);const _=await g(n,t,e`SELECT COUNT(*) AS ${e.identifier("n")} FROM ${e.identifier(f)} WHERE ${N(f,"rowid")} > ${Math.max(0,s)} AND ${N(f,"rowid")} <= ${d}`);return{done:u.length<z,last:d,left:Number(_[0]?.n??0)}},Xn=async(n,t,r,i)=>{const o=I(r,i);return on(await b(n,t,o),P(i,t)).finished?!0:En(n,t,o)},ut=async(n,t,r,i,o,s)=>{if(!await Xn(n,t,i,o.definition))throw new S("SEARCH_INDEX_BUILDING",`search index "${o.indexName}" on table "${i}" is still backfilling and currently covers only part of the table — retry once it finishes${t.searchBackfillHint===void 0?"":`, or complete it now: ${t.searchBackfillHint}`}`);return T(o.definition,t).runSearch(n,t,r,i,o,s)},nn=n=>n.slice(n.lastIndexOf("/")+1),tn=200,en=5,Yn=async(n,t,r,i)=>{const o=[...i.keys()],s=await g(n,t,e`SELECT * FROM ${e.identifier(r)} WHERE ${e.identifier("id")} >= ${o[0]} AND ${e.identifier("id")} <= ${o.at(-1)} ORDER BY ${e.identifier("id")} ASC`),a=new Map;for(const c of s){const f=c.id,u=i.get(f);u&&un.some(d=>String(u[d])!==String(c[d]))&&a.set(f,c)}return a},Jn=async(n,t,r,i,o,s,a)=>{const c=T(s,t);let f=new Map;for(const u of a)typeof u.id=="string"&&f.set(u.id,u);for(let u=0;f.size>0&&u<en;u+=1){for(const d of f.values()){const $=an(r,d);$&&await Vn(c,n,t,o,$,s,{row:d,table:i})}f=await Yn(n,t,i,f)}f.size>0&&console.warn(`[@lunora/sql-store] search backfill of "${o}": ${String(f.size)} row(s) were rewritten on every one of ${String(en)} re-check rounds and were left to their writers — each stays unindexed only if none of those writes changed its indexed text.`)},mn=async(n,t,r,i,o)=>{const s=I(i,o),a=P(o,t),c=on(await b(n,t,s),a);if(c.finished)return!0;if(c.wipe&&await M(n,t,s,void 0,!1,a),(await g(n,t,t.tableExists(i))).length===0)return await M(n,t,s,void 0,!0,a),!0;const u=await On(n,t,i,c.cursor,tn),d=u.findLast(h=>typeof h.id=="string")?.id;await Jn(n,t,r,i,s,o,u);const $=u.length<tn;return await M(n,t,s,d??c.cursor,$,a),$},ln=async(n,t,r)=>{await hn(n,r);for(const[i,,o]of Q(t)){const s=I(i,o),a=P(o,r),c=await b(n,r,s);c.profile!==void 0&&nn(c.profile)!==nn(a)&&(await R(n,r,e`DROP TABLE IF EXISTS ${e.identifier(s)}`),await R(n,r,e`DROP TABLE IF EXISTS ${e.identifier(Tn(s))}`),await pn(n,r,s)),await T(o,r).ensureCompanion(n,r,s)}},Kn=async(n,t,r,i,o)=>{const s=I(i,o);if((await b(n,t,s)).profile!==void 0)return;let c=0;(await g(n,t,t.tableExists(i))).length>0&&await Cn(n,t,r,i,()=>{c+=1},{limit:1}),await M(n,t,s,void 0,c===0,P(o,t))},dt=async(n,t,r)=>{await ln(n,t,r);for(const[i,o,s]of Q(t)){if(await H(n,r,o,i,s),s.staged){await Kn(n,r,o,i,s);continue}await mn(n,r,o,i,s)}},rn=3,zn=async(n,t,r,i,o)=>{let s=0,a=0;for(;;){let c=await H(n,t,r,i,o,s);for(let f=1;c.left>0&&f<rn;f+=1)c=await H(n,t,r,i,o,s);if(c.left>0&&(a+=c.left,console.warn(`[@lunora/sql-store] search migration of "${I(i,o)}": ${String(c.left)} row(s) lost every one of ${String(rn)} attempts to a concurrent write and were left for a later pass.`)),c.done)return a;s=c.last}},$t=async(n,t,r)=>{let i=0;await ln(n,t,r);for(const[o,s,a]of Q(t)){i+=await zn(n,r,s,o,a);let c=!1;for(;!c;)c=await mn(n,r,s,o,a)}return{unmappedSkipped:i}},wt=n=>{const{dialect:t,exec:r,schema:i}=n;return async(o,s,a,c)=>{const f=i.tables[o]?.searchIndexes;if(!(!f||f.length===0))for(const u of f){if(Pn(c,a,u))continue;const d=I(o,u);if(a){await T(u,t).indexDocument(r,t,d,s,a,u);continue}await T(u,t).purgeDocument(r,t,d,s)}}};export{it as A,at as C,ct as R,ft as T,ut as a,st as b,wt as c,$t as d,dt as r,ot as x};
@@ -1 +0,0 @@
1
- import{renderSql as d}from"@lunora/shard-engine";import{sql as r}from"drizzle-orm";import{s as C,b,e as I}from"./value-codec-DC_dHxUY.mjs";const K="_version",R=n=>n==="_id"||n==="id"?"id":n,v=n=>r`${r.identifier(R(n))}`,D=(n,e)=>r`${r.identifier(n)}.${r.identifier(R(e))}`,B=n=>{const e=[];for(const[t,o]of Object.entries(n.shape)){const s=o._meta?.column;s&&e.push([t,s])}return e},O=(n,e,t)=>{const{params:o,sql:s}=d(e.name,t);return n.all(s,o)},l=(n,e,t)=>{const{params:o,sql:s}=d(e.name,t);return n.run(s,o)},F=async(n,e,t)=>{if(t.length!==0){if(!n.batch){for(const o of t)await l(n,e,o);return}await n.batch(t.map(o=>d(e.name,o)))}},L=async(n,e,t)=>{if(n.batch&&e.name==="sqlite"){await n.batch(t.map(o=>d(e.name,o)));return}for(const o of t)await l(n,e,o)},U=async(n,e,t)=>{const o=t.unique?r`UNIQUE `:r``;if(e.name==="mysql"){try{await l(n,e,r`CREATE ${o}INDEX ${r.identifier(t.name)} ON ${r.identifier(t.table)} (${t.columns})`)}catch(s){const i=s;if(i.errno!==1061&&i.code!=="ER_DUP_KEYNAME"&&i.code!==1061)throw s}return}await l(n,e,r`CREATE ${o}INDEX IF NOT EXISTS ${r.identifier(t.name)} ON ${r.identifier(t.table)} (${t.columns})`)},z=C,m=n=>{if(n===void 0)return!1;if(n._meta?.column?.notNull===!1)return!0;switch(n.kind){case"any":case"null":return!0;case"literal":return n._meta?.value===null;case"optional":return m(n._meta?.inner);case"union":return n._meta?.members?.some(e=>m(e))===!0;default:return!1}},g=n=>n.kind==="optional"&&!m(n),E=new WeakMap,_=n=>{let e=E.get(n);return e===void 0&&(e=Object.entries(n.shape).map(([t,o])=>[t,I(o),g(o)]),E.set(n,e)),e},$=new WeakMap,N=(n,e)=>{let t=$.get(n);return t===void 0&&(t=new Map(_(n).map(([o,s])=>[o,s])),$.set(n,t)),t.get(e)},P=(n,e,t)=>C(t,N(n,e)),S=(n,e)=>{const t={};for(const[o,s,i]of _(n)){const c=e[o];c===void 0||i&&c===null||(t[o]=b(c,s))}return t._id=e.id,t._creationTime=e._creationTime,t},q=(n,e)=>e?S(n,e):null,W=(n,e)=>{const t=[];for(const o of e){const s=q(n,o);s&&t.push(s)}return t},p=500,M=(n,e,t,o,s)=>{const i=r`${r.identifier(t)}.${r.identifier("id")}`,c=o===void 0?r``:r` WHERE ${i} > ${o}`;return O(n,e,r`SELECT * FROM ${r.identifier(t)}${c} ORDER BY ${i} ASC LIMIT ${r.raw(String(s))}`)},X=async(n,e,t,o,s,i={})=>{let c=i.after,a=i.limit,f=!0;for(;f&&(a===void 0||a>0);){const h=a===void 0?p:Math.min(p,a),u=await M(n,e,o,c,h);for(const y of u){const w=q(t,y);w&&await s(w)}c=u.at(-1)?.id,f=u.length===h,a=a===void 0?void 0:a-u.length}};export{p as BACKFILL_BATCH_SIZE,K as OCC_VERSION_COLUMN,v as columnRefSql,U as createIndexIfNotExists,S as decodeGlobalRow,q as decodeRow,W as decodeRows,X as forEachRowPaged,R as physicalColumn,D as qualifiedColumnRefSql,O as queryAll,F as queryBatch,l as queryRun,M as readRowsPage,L as runInOrder,z as serializeColumnValue,P as serializeDocumentColumn,B as tableColumns};