@lunora/sql-store 1.0.0-alpha.105 → 1.0.0-alpha.106
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 +33 -33
- package/dist/index.d.ts +33 -33
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/OCC_VERSION_COLUMN-ByC64Jgx.mjs +1 -0
- package/dist/packem_shared/SEARCH_STATE_TABLE-BOO4Hza4.mjs +1 -0
- package/dist/packem_shared/backfillSqlSearchIndexes-px2Fcb4X.mjs +1 -0
- package/dist/packem_shared/createSqlCtxDb-B13OX97F.mjs +7 -0
- package/dist/packem_shared/ctx-db-search-Df3kW2QZ.mjs +1 -0
- package/dist/packem_shared/ctx-db-search-state-D3Cz0jkq.mjs +1 -0
- package/dist/packem_shared/{decodeBigint-PAoSEilU.mjs → decodeBigint-BUHeckfc.mjs} +1 -1
- package/dist/packem_shared/decodeGlobalRow-BNt0QNvu.mjs +1 -0
- package/dist/packem_shared/runSqlAggregateMigrations-B8Gv9CX6.mjs +1 -0
- package/dist/packem_shared/value-codec-CkEe2gLC.mjs +1 -0
- package/package.json +3 -3
- package/dist/packem_shared/SEARCH_STATE_TABLE-CZxjE5CH.mjs +0 -1
- package/dist/packem_shared/backfillSqlSearchIndexes-DUNgrE92.mjs +0 -1
- package/dist/packem_shared/createSqlCtxDb-GulsPHa-.mjs +0 -7
- package/dist/packem_shared/ctx-db-search-BmDhXVpE.mjs +0 -1
- package/dist/packem_shared/decodeGlobalRow-DtOXIcLj.mjs +0 -1
- package/dist/packem_shared/value-codec-CPoo8vyF.mjs +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -131,39 +131,6 @@ interface SqlCtxDbOptions {
|
|
|
131
131
|
scheduler?: SchedulerLike;
|
|
132
132
|
schema: SchemaLike;
|
|
133
133
|
}
|
|
134
|
-
/**
|
|
135
|
-
* Auto-provision every `.global()` table from the schema: `CREATE TABLE IF NOT
|
|
136
|
-
* EXISTS` with the physical `id`/`_creationTime` columns plus a typed column per
|
|
137
|
-
* declared field, then its secondary and `.unique()` indexes. This is the D1
|
|
138
|
-
* twin of `@lunora/do`'s `runShardMigrations` (which self-creates shard-local
|
|
139
|
-
* tables) — it makes the schema the single source of truth for global tables
|
|
140
|
-
* too, so a fresh database serves them without a hand-applied migration. The
|
|
141
|
-
* column set and dialect match exactly what this module reads and writes
|
|
142
|
-
* (`columnRef`, `serializeColumnValue`, `decodeGlobalRow`).
|
|
143
|
-
*
|
|
144
|
-
* Idempotent (`CREATE TABLE/INDEX IF NOT EXISTS`); additive only — it never
|
|
145
|
-
* drops or retypes an existing column, so destructive schema changes still need
|
|
146
|
-
* an explicit migration.
|
|
147
|
-
*/
|
|
148
|
-
declare const runSqlGlobalTableMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
149
|
-
/**
|
|
150
|
-
* Materialize the `__agg_<index>` companion tables for every declared
|
|
151
|
-
* `aggregateIndex` on a global table. Global tables in Lunora ship their own
|
|
152
|
-
* DDL — counter tables are opt-in so production hosts can decide where they
|
|
153
|
-
* live. Tests and dev hosts can call this once after their schema migration to
|
|
154
|
-
* unlock O(1) counts.
|
|
155
|
-
*
|
|
156
|
-
* Idempotent (`CREATE TABLE IF NOT EXISTS`).
|
|
157
|
-
*/
|
|
158
|
-
declare const runSqlAggregateMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
159
|
-
/**
|
|
160
|
-
* Materialize the `__rank_<index>` companion tables for every declared
|
|
161
|
-
* `rankIndex` on a global table. Mirrors `runSqlAggregateMigrations` — same
|
|
162
|
-
* opt-in pattern so production hosts decide whether to spend the DDL.
|
|
163
|
-
*
|
|
164
|
-
* Idempotent (`CREATE TABLE IF NOT EXISTS` + `createIndexIfNotExists`).
|
|
165
|
-
*/
|
|
166
|
-
declare const runSqlRankMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
167
134
|
/** Create the `__cdc_log` table. Idempotent; only run when CDC is enabled. */
|
|
168
135
|
declare const runSqlCdcMigration: (exec: SqlCtxExec, dialect: SqlDialect) => Promise<void>;
|
|
169
136
|
/**
|
|
@@ -238,6 +205,39 @@ declare const readSqlCdcChangedTables: (exec: SqlCtxExec, sinceSeq: number, dial
|
|
|
238
205
|
tables: string[];
|
|
239
206
|
}>;
|
|
240
207
|
declare const createSqlCtxDb: (options: SqlCtxDbOptions) => DatabaseWriterLike;
|
|
208
|
+
/**
|
|
209
|
+
* Auto-provision every `.global()` table from the schema: `CREATE TABLE IF NOT
|
|
210
|
+
* EXISTS` with the physical `id`/`_creationTime` columns plus a typed column per
|
|
211
|
+
* declared field, then its secondary and `.unique()` indexes. This is the D1
|
|
212
|
+
* twin of `@lunora/do`'s `runShardMigrations` (which self-creates shard-local
|
|
213
|
+
* tables) — it makes the schema the single source of truth for global tables
|
|
214
|
+
* too, so a fresh database serves them without a hand-applied migration. The
|
|
215
|
+
* column set and dialect match exactly what this module reads and writes
|
|
216
|
+
* (`columnRef`, `serializeColumnValue`, `decodeGlobalRow`).
|
|
217
|
+
*
|
|
218
|
+
* Idempotent (`CREATE TABLE/INDEX IF NOT EXISTS`); additive only — it never
|
|
219
|
+
* drops or retypes an existing column, so destructive schema changes still need
|
|
220
|
+
* an explicit migration.
|
|
221
|
+
*/
|
|
222
|
+
declare const runSqlGlobalTableMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
223
|
+
/**
|
|
224
|
+
* Materialize the `__agg_<index>` companion tables for every declared
|
|
225
|
+
* `aggregateIndex` on a global table. Global tables in Lunora ship their own
|
|
226
|
+
* DDL — counter tables are opt-in so production hosts can decide where they
|
|
227
|
+
* live. Tests and dev hosts can call this once after their schema migration to
|
|
228
|
+
* unlock O(1) counts.
|
|
229
|
+
*
|
|
230
|
+
* Idempotent (`CREATE TABLE IF NOT EXISTS`).
|
|
231
|
+
*/
|
|
232
|
+
declare const runSqlAggregateMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
233
|
+
/**
|
|
234
|
+
* Materialize the `__rank_<index>` companion tables for every declared
|
|
235
|
+
* `rankIndex` on a global table. Mirrors `runSqlAggregateMigrations` — same
|
|
236
|
+
* opt-in pattern so production hosts decide whether to spend the DDL.
|
|
237
|
+
*
|
|
238
|
+
* Idempotent (`CREATE TABLE IF NOT EXISTS` + `createIndexIfNotExists`).
|
|
239
|
+
*/
|
|
240
|
+
declare const runSqlRankMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
241
241
|
/** Reserved table holding one backfill-progress row per search companion. */
|
|
242
242
|
declare const SEARCH_STATE_TABLE = "__lunora_search_state";
|
|
243
243
|
/** Create the progress table. Idempotent; runs alongside the companion DDL. */
|
package/dist/index.d.ts
CHANGED
|
@@ -131,39 +131,6 @@ interface SqlCtxDbOptions {
|
|
|
131
131
|
scheduler?: SchedulerLike;
|
|
132
132
|
schema: SchemaLike;
|
|
133
133
|
}
|
|
134
|
-
/**
|
|
135
|
-
* Auto-provision every `.global()` table from the schema: `CREATE TABLE IF NOT
|
|
136
|
-
* EXISTS` with the physical `id`/`_creationTime` columns plus a typed column per
|
|
137
|
-
* declared field, then its secondary and `.unique()` indexes. This is the D1
|
|
138
|
-
* twin of `@lunora/do`'s `runShardMigrations` (which self-creates shard-local
|
|
139
|
-
* tables) — it makes the schema the single source of truth for global tables
|
|
140
|
-
* too, so a fresh database serves them without a hand-applied migration. The
|
|
141
|
-
* column set and dialect match exactly what this module reads and writes
|
|
142
|
-
* (`columnRef`, `serializeColumnValue`, `decodeGlobalRow`).
|
|
143
|
-
*
|
|
144
|
-
* Idempotent (`CREATE TABLE/INDEX IF NOT EXISTS`); additive only — it never
|
|
145
|
-
* drops or retypes an existing column, so destructive schema changes still need
|
|
146
|
-
* an explicit migration.
|
|
147
|
-
*/
|
|
148
|
-
declare const runSqlGlobalTableMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
149
|
-
/**
|
|
150
|
-
* Materialize the `__agg_<index>` companion tables for every declared
|
|
151
|
-
* `aggregateIndex` on a global table. Global tables in Lunora ship their own
|
|
152
|
-
* DDL — counter tables are opt-in so production hosts can decide where they
|
|
153
|
-
* live. Tests and dev hosts can call this once after their schema migration to
|
|
154
|
-
* unlock O(1) counts.
|
|
155
|
-
*
|
|
156
|
-
* Idempotent (`CREATE TABLE IF NOT EXISTS`).
|
|
157
|
-
*/
|
|
158
|
-
declare const runSqlAggregateMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
159
|
-
/**
|
|
160
|
-
* Materialize the `__rank_<index>` companion tables for every declared
|
|
161
|
-
* `rankIndex` on a global table. Mirrors `runSqlAggregateMigrations` — same
|
|
162
|
-
* opt-in pattern so production hosts decide whether to spend the DDL.
|
|
163
|
-
*
|
|
164
|
-
* Idempotent (`CREATE TABLE IF NOT EXISTS` + `createIndexIfNotExists`).
|
|
165
|
-
*/
|
|
166
|
-
declare const runSqlRankMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
167
134
|
/** Create the `__cdc_log` table. Idempotent; only run when CDC is enabled. */
|
|
168
135
|
declare const runSqlCdcMigration: (exec: SqlCtxExec, dialect: SqlDialect) => Promise<void>;
|
|
169
136
|
/**
|
|
@@ -238,6 +205,39 @@ declare const readSqlCdcChangedTables: (exec: SqlCtxExec, sinceSeq: number, dial
|
|
|
238
205
|
tables: string[];
|
|
239
206
|
}>;
|
|
240
207
|
declare const createSqlCtxDb: (options: SqlCtxDbOptions) => DatabaseWriterLike;
|
|
208
|
+
/**
|
|
209
|
+
* Auto-provision every `.global()` table from the schema: `CREATE TABLE IF NOT
|
|
210
|
+
* EXISTS` with the physical `id`/`_creationTime` columns plus a typed column per
|
|
211
|
+
* declared field, then its secondary and `.unique()` indexes. This is the D1
|
|
212
|
+
* twin of `@lunora/do`'s `runShardMigrations` (which self-creates shard-local
|
|
213
|
+
* tables) — it makes the schema the single source of truth for global tables
|
|
214
|
+
* too, so a fresh database serves them without a hand-applied migration. The
|
|
215
|
+
* column set and dialect match exactly what this module reads and writes
|
|
216
|
+
* (`columnRef`, `serializeColumnValue`, `decodeGlobalRow`).
|
|
217
|
+
*
|
|
218
|
+
* Idempotent (`CREATE TABLE/INDEX IF NOT EXISTS`); additive only — it never
|
|
219
|
+
* drops or retypes an existing column, so destructive schema changes still need
|
|
220
|
+
* an explicit migration.
|
|
221
|
+
*/
|
|
222
|
+
declare const runSqlGlobalTableMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
223
|
+
/**
|
|
224
|
+
* Materialize the `__agg_<index>` companion tables for every declared
|
|
225
|
+
* `aggregateIndex` on a global table. Global tables in Lunora ship their own
|
|
226
|
+
* DDL — counter tables are opt-in so production hosts can decide where they
|
|
227
|
+
* live. Tests and dev hosts can call this once after their schema migration to
|
|
228
|
+
* unlock O(1) counts.
|
|
229
|
+
*
|
|
230
|
+
* Idempotent (`CREATE TABLE IF NOT EXISTS`).
|
|
231
|
+
*/
|
|
232
|
+
declare const runSqlAggregateMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
233
|
+
/**
|
|
234
|
+
* Materialize the `__rank_<index>` companion tables for every declared
|
|
235
|
+
* `rankIndex` on a global table. Mirrors `runSqlAggregateMigrations` — same
|
|
236
|
+
* opt-in pattern so production hosts decide whether to spend the DDL.
|
|
237
|
+
*
|
|
238
|
+
* Idempotent (`CREATE TABLE IF NOT EXISTS` + `createIndexIfNotExists`).
|
|
239
|
+
*/
|
|
240
|
+
declare const runSqlRankMigrations: (exec: SqlCtxExec, schema: SchemaLike, dialect: SqlDialect) => Promise<void>;
|
|
241
241
|
/** Reserved table holding one backfill-progress row per search companion. */
|
|
242
242
|
declare const SEARCH_STATE_TABLE = "__lunora_search_state";
|
|
243
243
|
/** Create the progress table. Idempotent; runs alongside the companion DDL. */
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,
|
|
1
|
+
import{createSqlCtxDb as a,readSqlCdcChangedTables as o,readSqlCdcChanges as t,readSqlCdcFloor as l,runSqlCdcMigration as s,sweepSqlCdcRetention as n}from"./packem_shared/createSqlCtxDb-B13OX97F.mjs";import{runSqlAggregateMigrations as d,runSqlGlobalTableMigrations as S,runSqlRankMigrations as c}from"./packem_shared/runSqlAggregateMigrations-B8Gv9CX6.mjs";import{d as g,r as C}from"./packem_shared/ctx-db-search-Df3kW2QZ.mjs";import{S as m,m as x}from"./packem_shared/ctx-db-search-state-D3Cz0jkq.mjs";import{c as b,e as u,a as h,s as M,t as T}from"./packem_shared/value-codec-CkEe2gLC.mjs";import{decodeGlobalRow as E}from"./packem_shared/decodeGlobalRow-BNt0QNvu.mjs";export{m as SEARCH_STATE_TABLE,g as backfillSqlSearchIndexes,a as createSqlCtxDb,b 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,C as runSqlSearchMigrations,h as sqliteDecode,M as sqliteEncode,n as sweepSqlCdcRetention,T as tryJsonParse};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o="_version";export{o as OCC_VERSION_COLUMN};
|
|
@@ -0,0 +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-D3Cz0jkq.mjs";import"./decodeGlobalRow-BNt0QNvu.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-D3Cz0jkq.mjs";import{d as S,c as s,a as i,r as l}from"./ctx-db-search-Df3kW2QZ.mjs";import"./decodeGlobalRow-BNt0QNvu.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{LunoraError as g}from"@lunora/errors";import{m as bt,D as Ct}from"./ctx-db-search-state-D3Cz0jkq.mjs";import{c as At,r as Lt,A as kt,C as Nt,R as Mt,a as Dt,T as qt,x as Bt,b as Ot}from"./ctx-db-search-Df3kW2QZ.mjs";import{d as ai}from"./ctx-db-search-Df3kW2QZ.mjs";import{literalInList as Wt,throwingScheduler as Ft,CDC_LOG_TABLE as V,cursorBelowRetainedFloor as Ut,cdcTrimmedError as xt,assertNoExplicitUndefined as Qe,hasTrigger as Pt,runRowValidators as Ne,assertFlatPredicate as ze,mergeWhere as q,rankTableName as le,sortColumnName as $e,resolveRankPartition as Je,encodePartitionKey as Ie,resolveRankSeekTuple as Ht,RANK_TIEBREAK as _e,CountRlsUnsupportedError as Ze,normalizeIdStructurally as Kt,assertValidClientId as jt,aggregateSqlFunction as fe,softDeleteScope as ue,compileWhereSql as we,normalizeOrderKeys as Gt,buildSeekWhere as Vt,decodeCursor as Yt,resolveRelationPredicates as et,resolveWith as tt,relationHooks as nt,applySelect as it,encodeCursor as Xt,NotFoundError as Qt,applyOnDelete as zt,ConflictError as be,normalizeCountArgument as Jt,selectIndexForCount as Zt,encodeAggregateKey as X,aggregateTableName as J,selectIndexForAggregate as en,readAggregateValue as Me,runTriggers as tn,matchesRankStaticWhere as ot,CURSOR_PREFIX as nn,selectIndexForGroupBy as on,tiebreakDirectionFor as rn,fanOutScalarCounts as sn,matchesStaticWhere as De,foldAggregateTally as an,coerceAggregateNumber as qe,CDC_LOG_TABLE_SEQ_INDEX as cn,NotUniqueError as dn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{d as wt,e as ln,n as fn,b as un}from"./value-codec-CkEe2gLC.mjs";import{runSqlGlobalTableMigrations as wn,runSqlAggregateMigrations as $n,runSqlRankMigrations as _n}from"./runSqlAggregateMigrations-B8Gv9CX6.mjs";import{queryAll as I,queryRun as k,createIndexIfNotExists as hn,decodeRow as ee,serializeColumnValue as G,columnRefSql as W,decodeRows as En,tableColumns as $t,forEachRowPaged as rt,queryBatch as st}from"./decodeGlobalRow-BNt0QNvu.mjs";import{decodeGlobalRow as di}from"./decodeGlobalRow-BNt0QNvu.mjs";import{OCC_VERSION_COLUMN as at}from"./OCC_VERSION_COLUMN-ByC64Jgx.mjs";const yn=(a,c)=>{if(a.size<c)return;const $=a.keys().next().value;$!==void 0&&a.delete($)},ct=50,pn=(a,c={})=>{const $=c.maxBatch??ct,r=Number.isInteger($)&&$>0?$:ct,p=new Map;let w=!1;const l=async(S,m)=>{const v=[...m.keys()];for(let N=0;N<v.length;N+=r){const B=v.slice(N,N+r);try{const F=await a(S,B);for(const Y of B){const P=F.get(Y);for(const Ce of m.get(Y)??[])Ce.resolve(P)}}catch(F){for(const Y of B)for(const P of m.get(Y)??[])P.reject(F)}}},b=()=>{w=!1;const S=[...p.entries()];p.clear();for(const[m,v]of S)l(m,v).catch(()=>{})};return{async load(S,m){return new Promise((v,N)=>{let B=p.get(S);B||(B=new Map,p.set(S,B));const F=B.get(m);F?F.push({reject:N,resolve:v}):B.set(m,[{reject:N,resolve:v}]),w||(w=!0,queueMicrotask(b))})}}},Rn=new Set(["_id","id"]),We=(a,c,$)=>a==="postgres"?e`${c} IS NOT DISTINCT FROM ${$}`:a==="mysql"?e`${c} <=> ${$}`:e`${c} IS ${$}`,Sn=(a,c)=>a.name!=="postgres"||c.nullable!==!0?"":c.direction==="desc"?" NULLS LAST":" NULLS FIRST",Tn=(a,c)=>{const $=a.map(r=>e`${W(r.field)} ${e.raw(`${r.direction==="desc"?"DESC":"ASC"}${Sn(c,r)}`)}`);if(!a.some(r=>Rn.has(r.field))){const r=rn(a);$.push(e`${W("id")} ${e.raw(r==="desc"?"DESC":"ASC")}`)}return e.join($,e`, `)},dt=50,gn=(a,c,$)=>{const r={...c};for(const[p,w]of $t(a)){if(w.serverDefault){r[p]=w.serverDefault({auth:$});continue}r[p]===void 0&&(w.defaultFn?r[p]=w.defaultFn():"defaultValue"in w&&(r[p]=w.defaultValue))}return r},lt=(a,c,$,r)=>{for(const[p,w]of $t(a)){if(w.serverDefault){p in c&&($[p]=w.serverDefault({auth:r}));continue}w.onUpdateFn&&!(p in c)&&($[p]=w.onUpdateFn())}},vn=128,mn=()=>{const a=new Map;return{delete:c=>{a.delete(c)},get:c=>{const $=a.get(c);if($!==void 0)return a.delete(c),a.set(c,$),$},set:(c,$)=>{a.has(c)?a.delete(c):yn(a,vn),a.set(c,$)}}},In=async(a,c,$,r,p)=>{const w=p.get(r);if(w!==void 0)return w;const l=Object.entries($.tables).filter(([,S])=>S.shardMode===void 0||S.shardMode.kind==="global").map(([S])=>S),b=await Promise.all(l.map(async S=>({found:(await I(a,c,e`SELECT 1 FROM ${e.identifier(S)} WHERE ${e.identifier("id")} = ${r} LIMIT 1`)).length>0,tableName:S})));for(const S of b)if(S.found)return p.set(r,S.tableName),S.tableName},te=a=>a==null?null:Number(a),bn=(a,c)=>c.map($=>{const r={};for(const p of a)r[p]=$[p]??null;return{key:r,value:te($.value)}}),Cn=(a,c,$)=>[...a.partitionBy??[],...a.sortBy.map(p=>p.field),...a.where?Object.keys(a.where):[]].every(p=>c[p]===$[p]),_t=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`, `),An=(a,c,$,r,p)=>{const w=[];for(let l=0;l<$.length+1;l+=1){const b=$.slice(0,l).map(v=>We(a,e`${e.identifier(v)}`,r[v])),S=$[l],m=c.sortBy[l];l<$.length&&S!==void 0&&m!==void 0?b.push(e`${e.identifier(S)} ${e.raw(m.direction==="desc"?">":"<")} ${r[S]}`):b.push(e`${e.identifier(_e)} < ${p}`),w.push(_t(b))}return w.length>0?e.join(w,e` OR `):void 0},Ln=(a,c,$)=>{if($.length!==c.length)return;const r=[];for(const[p,w]of c.entries()){const l=[];for(let b=0;b<p;b+=1){const S=c[b];S!==void 0&&l.push(We(a,e`${e.identifier(S.column)}`,$[b]))}l.push(e`${e.identifier(w.column)} ${e.raw(w.direction==="desc"?"<":">")} ${$[p]}`),r.push(_t(l))}return e`(${e.join(r,e` OR `)})`},kn=(a,c)=>{if(a.sortBy.length===0)throw new g("INTERNAL",`rankIndex "${a.name}" requires at least one "sortBy" column for stable pagination`);const $=[{column:"__partition__",direction:"asc"}];for(const[r,p]of a.sortBy.entries())$.push({column:c[r]??$e(r),direction:p.direction});return $.push({column:_e,direction:"asc"}),$},Nn=async(a,c,$,r,p)=>{const l=[];for(let v=0;v<p.length;v+=50)l.push(p.slice(v,v+50));const b=await Promise.all(l.map(async v=>I(a,c,e`SELECT * FROM ${e.identifier(r)} WHERE ${e.identifier("id")} IN (${ne(v)})`))),S=new Map;for(const v of b)for(const N of v)S.set(N.id,N);const m=[];for(const v of p){const N=ee($,S.get(v));N&&m.push(N)}return m},Mn=a=>{const c=JSON.stringify(a),$=new TextEncoder().encode(c);let r="";for(const p of $)r+=String.fromCodePoint(p);return nn+btoa(r)},Be=(a,c,$)=>{const r=a.shape[c];if(r!==void 0&&ln(r)==="bigint")throw new g("BAD_REQUEST",`${$}: "${c}" is stored as an order-preserving key, which SQL cannot 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)`)},Dn=(a,c,$,r)=>{for(const p of $)Be(a,p,`groupBy(${c}, { by: [..."${p}"] })`);r.field!==void 0&&Be(a,r.field,`groupBy(${c}, { agg: { op: "${r.op}", field: "${r.field}" } })`)},Oe="__cdc_sweep",ht="global",qn=6e4,Bn=1e4,On=3e4;let ft=0;const Wn=async(a,c)=>{const{autoincrementPrimaryKey:$,key:r,real:p,text:w}=c.companionTypes;await k(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(V)} (${e.identifier("seq")} ${e.raw($)}, ${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 l=c.indexKeyPrefix?.("string");await hn(a,c,{columns:e`${l===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(l))})`}, ${e.identifier("seq")}`,name:cn,table:V,unique:!1}),await k(a,c,e`CREATE TABLE IF NOT EXISTS ${e.identifier(Oe)} (${e.identifier("id")} ${e.raw(r)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(p)} NOT NULL)`),await k(a,c,e`INSERT INTO ${e.identifier(Oe)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${ht}, ${0}) ${c.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},Fn=async(a,c,$)=>{const r=e`UPDATE ${e.identifier(Oe)} SET ${e.identifier("lease_until")} = ${$+qn} WHERE ${e.identifier("id")} = ${ht} AND ${e.identifier("lease_until")} <= ${$}`;if(c.supportsReturning)return(await I(a,c,e`${r} RETURNING ${e.identifier("id")}`)).length>0;const p=await k(a,c,r);return(c.affectedRows?c.affectedRows(p??{rowsAffected:0}):0)>0},Un=async(a,c,$,r)=>{if(!await Fn(a,c,r))return;const p=r-$;await k(a,c,e`
|
|
2
|
+
DELETE FROM ${e.identifier(V)} WHERE ${e.identifier("seq")} IN (
|
|
3
|
+
SELECT ${e.identifier("seq")} FROM (
|
|
4
|
+
SELECT ${e.identifier("seq")} FROM ${e.identifier(V)} WHERE ${e.identifier("ts")} <= ${p} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(Bn))}
|
|
5
|
+
) AS ${e.identifier("expired")}
|
|
6
|
+
)
|
|
7
|
+
`)},Et=async(a,c)=>{const $=await I(a,c,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(V)}`),r=Number($[0]?.seq??Number.NaN);return Number.isFinite(r)?r:void 0},xn=a=>JSON.stringify(fn(a)?un(a):a),Pn=async(a,c,$,r,p,w,l)=>{await k(a,l,e`INSERT INTO ${e.identifier(V)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${c}, ${$}, ${r}, ${p}, ${w===void 0?null:xn(w)})`)},ii=async(a,c,$)=>{const r=c.sinceSeq??0,p=Math.max(1,Math.min(c.limit??1e3,1e4)),w=await Et(a,$);if(w!==void 0&&Ut(w,r))throw xt(w,r,"global");const b=(await I(a,$,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(V)} WHERE seq > ${r} ORDER BY seq ASC LIMIT ${e.raw(String(p))}`)).map(S=>{const{doc:m}=S,v={id:String(S.id),op:String(S.op),seq:Number(S.seq),table:String(S.table),ts:Number(S.ts)};return typeof m=="string"?{...v,doc:wt(JSON.parse(m))}:v});return{changes:b,cursor:b.at(-1)?.seq??r}},Hn=async(a,c,$,r={})=>{if(r.cursorOnly){const S=await I(a,$,e`SELECT MAX(seq) AS seq FROM ${e.identifier(V)}`),m=Number(S[0]?.seq??c);return{cursor:Number.isFinite(m)?m:c,tables:[]}}const p=await I(a,$,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(V)} WHERE seq > ${c} GROUP BY ${e.identifier("table")}`);let w=c;const l=[];for(const S of p){const m=Number(S.seq);Number.isFinite(m)&&m>w&&(w=m),l.push(String(S.table))}const b=r.retained===!0?await Et(a,$):void 0;return{cursor:w,tables:l,...b===void 0?{}:{floor:b}}},Kn=/string or blob too big/iu,jn=/row is too big/iu,Gn=(a,c)=>{const{code:$,errno:r}=c,p=c instanceof Error?c.message:"";switch(a.name){case"mysql":return r===1118||$==="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 jn.test(p)?"the 8 KB heap page a tuple must fit once its wide columns have been TOASTed out":void 0;default:return Kn.test(p)?"the storage engine's per-row ceiling (2 MB on D1)":void 0}},Vn=(a,c,$)=>{const r=Gn(a,c);if(r!==void 0)throw new g("PAYLOAD_TOO_LARGE",`document is too large to store in "${$}": 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.`)},ut=(a,c,$)=>{throw a.isUniqueViolation(c)?new be(`unique constraint violation on "${$}"`,"unique"):(Vn(a,c,$),c)},oi=a=>{const{crossShardCounter:c,crossShardReader:$,exec:r,maxRelationKeys:p,schema:w}=a,{dialect:l}=a,b={fieldRef:W,serialize:G,...l.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...l.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...l.name==="sqlite"?{}:{inList:Wt}},S=(t,n)=>We(l.name,t,n),m=t=>{const n=Z(t.columns),i=ne(t.values),o=f=>l.name==="mysql"?e`VALUES(${e.identifier(f)})`:e`excluded.${e.identifier(f)}`,s=f=>l.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(f)}`:e`${e.identifier(f)}`,u=e.join(Object.entries(t.set(o,s)).map(([f,h])=>e`${e.identifier(f)} = ${h}`),e`, `),E=l.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${u}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${u}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${i}) ${E}`},v=a.clock??(()=>Date.now()),N=a.idGenerator??(()=>crypto.randomUUID()),B=a.cdc??!1,F=typeof a.cdcRetentionMs=="number"&&Number.isFinite(a.cdcRetentionMs)&&a.cdcRetentionMs>0?a.cdcRetentionMs:void 0,Y=a.auth??{identity:null,userId:null},P=async(t,n,i,o)=>{if(!B||(await Pn(r,v(),t,n,i,o,l),F===void 0))return;const s=v();if(!(s-ft<On)){ft=s;try{await Un(r,l,F,s)}catch{}}},Ce=a.scheduler??Ft,Ae=mn();let he=0,Le;const U=async()=>(Le??=(async()=>{await wn(r,w,l),await $n(r,w,l),await _n(r,w,l),await bt(r,l),await Lt(r,w,l),B&&await Wn(r,l)})().catch(t=>{throw Le=void 0,t}),Le),ie=async(t,n)=>{await U();const i=await In(r,l,w,t,Ae);if(!(n!==void 0&&i!==n))return i},oe=new Map,Fe=async(t,n)=>{const i=J(t,n);return(await I(r,l,l.tableExists(i))).length>0},Ee=async(t,n)=>{const i=`${t}::${n.name}`,o=oe.get(i);if(o!==void 0)return o;if(!await Fe(t,n.name))return oe.set(i,!1),!1;const u=w.tables[t];if(!u)return oe.set(i,!1),!1;const E=n.by??[],f=new Map;await rt(r,l,u,t,_=>{if(n.where&&!De(_,n.where))return;const y=X(E,_);an(f,y,n,_)});const h=J(t,n.name);await k(r,l,e`DELETE FROM ${e.identifier(h)}`);const d=[];for(const[_,y]of f)d.push(e`INSERT INTO ${e.identifier(h)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${_}, ${y.value}, ${y.count})`);return await st(r,l,d),oe.set(i,!0),!0},yt=async(t,n,i)=>{const o=fe(n.op),s=n.field??"",u=[];for(const h of n.by??[]){const d=G(i[h]??null);u.push(d===null?e`${W(h)} IS NULL`:e`${W(h)} = ${d}`)}for(const[h,d]of Object.entries(n.where??{})){const _=d!==null&&typeof d=="object"&&!Array.isArray(d)?d.eq:d,y=G(_);u.push(y===null?e`${W(h)} IS NULL`:e`${W(h)} = ${y}`)}const E=e`SELECT ${e.raw(o)}(${W(s)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}`,f=await I(r,l,u.length>0?e`${E} WHERE ${e.join(u,e` AND `)}`:E);return te(f[0]?.value)},pt=async(t,n)=>{await k(r,l,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},Rt=async(t,n,i,o)=>{const s=J(t,n.name),{op:u}=n,E=n.field??"",f=i&&(!n.where||De(i,n.where))?i:void 0,h=o&&(!n.where||De(o,n.where))?o:void 0;if(!(!f&&!h)){if(u==="count"||u==="sum"||u==="avg"){const d=new Set;for(const[_,y]of[[f,-1],[h,1]]){if(!_)continue;const T=u==="count"?1:qe(_[E]);if(T===void 0)continue;const R=X(n.by??[],_);d.add(R),await k(r,l,m({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(C,A)=>({__count__:e`${A("__count__")} + ${C("__count__")}`,__value__:u==="count"?e`${A("__value__")} + ${C("__value__")}`:e`COALESCE(${A("__value__")}, 0) + ${C("__value__")}`}),table:s,values:[R,y*T,y]}))}for(const _ of d)await pt(s,_);return}if(f){const d=X(n.by??[],f),_=qe(f[E]),T=(await I(r,l,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${d}`))[0],R=te(T?.value),C=(T?.count??0)-1;if(C<=0)await k(r,l,e`DELETE FROM ${e.identifier(s)} WHERE ${e.identifier("__key__")} = ${d}`);else if(T&&_!==void 0&&R!==null&&_===R){const A=await yt(t,n,f);await k(r,l,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__value__")} = ${A}, ${e.identifier("__count__")} = ${C} WHERE ${e.identifier("__key__")} = ${d}`)}else await k(r,l,e`UPDATE ${e.identifier(s)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${d}`)}if(h){const d=X(n.by??[],h),_=qe(h[E]);if(_===void 0)await k(r,l,m({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(y,T)=>({__count__:e`${T("__count__")} + 1`}),table:s,values:[d,null,1]}));else{const y=u==="min"?"MIN":"MAX";await k(r,l,m({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(T,R)=>({__count__:e`${R("__count__")} + 1`,__value__:e`${e.raw(y)}(COALESCE(${R("__value__")}, ${T("__value__")}), ${T("__value__")})`}),table:s,values:[d,_,1]}))}}}},ye=async t=>{const n=w.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const i of n)await Ee(t,i)},re=async(t,n,i)=>{const o=w.tables[t]?.aggregateIndexes;if(!(!o||o.length===0))for(const s of o){const u=`${t}::${s.name}`;(oe.get(u)??await Fe(t,s.name))&&await Rt(t,s,n,i)}},se=new Map,Ue=async(t,n)=>{const i=le(t,n);return(await I(r,l,l.tableExists(i))).length>0},ke=async(t,n)=>{const i=`${t}::rank::${n.name}`,o=se.get(i);if(o!==void 0)return o;if(!await Ue(t,n.name))return se.set(i,!1),!1;const u=w.tables[t];if(!u)return se.set(i,!1),!1;const E=le(t,n.name);await k(r,l,e`DELETE FROM ${e.identifier(E)}`);const f=n.sortBy.map((y,T)=>$e(T)),h=Z(["__id__","__partition__",...f]),d=[];await rt(r,l,u,t,y=>{if(n.where&&!ot(y,n.where))return;const T=Ie(n.partitionBy??[],y),R=n.sortBy.map(C=>G(y[C.field]??null));d.push([y._id,T,...R])});const _=d.map(y=>e`INSERT INTO ${e.identifier(E)} (${h}) VALUES (${ne(y)})`);return await st(r,l,_),se.set(i,!0),!0},pe=async t=>{const n=w.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const i of n)await ke(t,i)},Q=async(t,n,i,o)=>{const s=w.tables[t],u=s?.rankIndexes;if(!u||u.length===0)return;const E=s?.softDeleteMode?.field,f=E===void 0||o===void 0?void 0:o[E],h=f!=null;for(const d of u){if(i!==void 0&&o!==void 0&&Cn(d,i,o))continue;const _=`${t}::rank::${d.name}`;if(!(se.get(_)??await Ue(t,d.name)))continue;const R=le(t,d.name);if(i&&await k(r,l,e`DELETE FROM ${e.identifier(R)} WHERE ${e.identifier("__id__")} = ${n}`),o&&!h){if(d.where&&!ot(o,d.where))continue;const C=d.sortBy.map((M,j)=>$e(j)),A=Z(["__id__","__partition__",...C]),O=Ie(d.partitionBy??[],o),L=d.sortBy.map(M=>G(o[M.field]??null));await k(r,l,e`INSERT INTO ${e.identifier(R)} (${A}) VALUES (${ne([n,O,...L])})`)}}},ae=At({dialect:l,exec:r,schema:w}),xe=new Set;for(const[t,n]of Object.entries(w.tables))for(const i of Object.values(n.triggerMap??{}))xe.add(`${t} ${i.timing} ${i.op}`);const H=(t,n,i)=>xe.has(`${t} ${n} ${i}`);let Pe;const K=async(t,n,i)=>{if(he+=1,he>dt)throw he-=1,new be(`trigger recursion exceeded ${String(dt)} levels on "${i.table}" — check for a self-triggering write`,"trigger");try{await tn({ctx:Pe,event:i,op:n,schema:w,tableName:i.table,timing:t})}finally{he-=1}},St=async(t,n)=>{try{await k(r,l,n)}catch(i){ut(l,i,t)}},Re=async(t,n)=>(await I(r,l,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],Se=async(t,n,i,o)=>{if(o===void 0)return;const s=e`${e.identifier(at)}`,u=e.join([S(e`${e.identifier("id")}`,o.id),S(s,o[at]??null)],e` AND `),E=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${i}, ${s} = COALESCE(${s}, 0) + 1 WHERE ${u}`:e`DELETE FROM ${e.identifier(t)} WHERE ${u}`,f=()=>{throw new be(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(l.supportsReturning)(await I(r,l,e`${E} RETURNING ${e.identifier("id")}`)).length===0&&f();else{const h=await k(r,l,E);(l.affectedRows?l.affectedRows(h??{rowsAffected:0}):0)===0&&f()}}catch(h){ut(l,h,t)}},Tt=(t,n,i,o)=>{const s=Object.keys(t.shape);return{columns:["id","_creationTime",...s],values:[n,i,...s.map(u=>G(o[u]??null))]}},gt=async(t,n,i,o)=>{const s=on(n,i.op,i.field,o.by,o.where);if(!s||!await Ee(t,s.index))return;const E=J(t,s.index.name),f=Object.keys(s.partial);if(f.length===(s.index.by??[]).length&&f.length>0){const d=X(s.index.by??[],s.partial),_=await I(r,l,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(E)} WHERE ${e.identifier("__key__")} = ${d}`);if(_.length===0)return[];const y=_[0];return[{key:{...s.partial},value:Me(i.op,{count:y.count,value:te(y.value)})}]}return f.length>0?void 0:(await I(r,l,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(d=>{const _=d;return{key:wt(JSON.parse(_.key)),value:Me(i.op,{count:_.count,value:te(_.value)})}})},He=t=>{const n=w.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},Ke=t=>{throw new g("INTERNAL",`cross-backend relation: a global table cannot load the shard-local relation '${t}' (it spans every shard) — wire a cross-shard reader to support it`)},vt=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new g("MASK_UNSUPPORTED",`masking cannot follow a nested \`with\` across the cross-shard relation hop to "${t}" — the nested rows are hydrated on the serving shard, where the mask policy does not exist. Read the nested relation at its own (masked) call site instead.`);const 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:q(n?.baseWhere,n?.where),with:n?.with}},je=(t,n)=>He(t)?$?$(t,vt(t,n)):Ke(t):x.findMany(t,n),Te=(t,n,i)=>et(t,{fetcher:je,maxRelationKeys:p,relationBaseWhere:i,schema:w,tableName:n}),mt=pn(async(t,n)=>{const i=await I(r,l,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${ne(n)})`),o=new Map;for(const s of i){const{id:u}=s;typeof u=="string"&&o.set(u,s)}return o}),x={async cdcChangedTables(t,n){if(B)try{return await U(),await Hn(r,t,l,{...n,retained:F!==void 0})}catch{return}},async aggregate(t,n){const i=w.tables[t];if(!i)throw new g("INTERNAL",`unknown table: ${t}`);if(await U(),fe(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 g("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const o=ue(i.softDeleteMode,void 0),s=q(q(n.baseWhere,n.where),o),u=await Te(s,t,n.relationBaseWhere),E=u!==s;if(i.aggregateIndexes&&!n.baseWhere&&!E&&!o){const T=en(i.aggregateIndexes,n.op,n.field,n.where);if(T&&await Ee(t,T.index)){const C=X(T.index.by??[],T.key),A=J(t,T.index.name),L=(await I(r,l,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")}, ${e.identifier("__count__")} AS ${e.identifier("count")} FROM ${e.identifier(A)} WHERE ${e.identifier("__key__")} = ${C}`))[0];return Me(n.op,L===void 0?void 0:{count:L.count,value:te(L.value)})}}Be(i,n.field,`aggregate(${t}, { op: "${n.op}", field: "${n.field}" })`);const f=we(u,b),h=e.raw(fe(n.op)),d=e`SELECT ${h}(${W(n.field)}) AS ${e.identifier("value")} FROM ${e.identifier(t)}`,y=(await I(r,l,f?e`${d} WHERE ${f}`:d))[0]?.value;return y==null?null:Number(y)},async count(t,n){const i=w.tables[t];if(!i)throw new g("INTERNAL",`unknown table: ${t}`);await U();const o=Jt(n);if(o.restrictsCounts)throw new Ze(t);const s=ue(i.softDeleteMode,void 0),u=q(q(o.baseWhere,o.where),s),E=await Te(u,t,o.relationBaseWhere),f=E!==u;if(i.aggregateIndexes&&!o.baseWhere&&!f&&!s){const y=Zt(i.aggregateIndexes,o.where);if(y&&await Ee(t,y.index)){const R=X(y.index.by??[],y.key),C=J(t,y.index.name),A=await I(r,l,e`SELECT ${e.identifier("__value__")} AS ${e.identifier("value")} FROM ${e.identifier(C)} WHERE ${e.identifier("__key__")} = ${R}`);return Number(A[0]?.value??0)}}const h=we(E,b),d=e`SELECT COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(t)}`,_=await I(r,l,h?e`${d} WHERE ${h}`:d);return Number(_[0]?.count??0)},async delete(t,n,i){const o=await ie(t,n);if(!o)return;const s=w.tables[o];if(!s)return;const u=await Re(o,t),E=ee(s,u),f=i?.hard===!0,h=!f&&s.softDeleteMode?s.softDeleteMode.field:void 0;if(!(h&&(!E||E[h]!==null&&E[h]!==void 0))){if(H(o,"before","delete")&&await K("before","delete",{id:t,op:"delete",previous:E??void 0,table:o}),await zt({deletedId:t,deletedReference:d=>E?.[d],findHolders:async(d,_,y)=>{if(w.tables[d]?.shardMode?.kind==="shardBy")throw new g("INTERNAL",`cross-backend cascade from global '${o}' into shardBy '${d}' is not supported — would require Query Coordinator fan-out across shards`);return(await x.findMany(d,{includeDeleted:f,where:{[_]:y}})).page},onCascade:(d,_)=>x.delete(_,void 0,i),onRestrict:d=>{throw new be(d,"restrict")},onSetNull:(d,_,y)=>x.patch(_,{[y]:null}),schema:w,tableName:o}),await ye(o),await pe(o),h&&E){const d={...E,[h]:v()},_=e.join(Object.keys(s.shape).map(y=>e`${e.identifier(y)} = ${G(d[y]??null)}`),e`, `);await Se(o,"UPDATE",_,u),await re(o,E,d),await Q(o,t,E,void 0),await ae(o,t,d,E),await P(o,t,"update",d),H(o,"after","delete")&&await K("after","delete",{id:t,op:"delete",previous:E,table:o});return}await Se(o,"DELETE",void 0,u),Ae.delete(t),await re(o,E??void 0,void 0),await Q(o,t,E??void 0,void 0),await ae(o,t,void 0),await P(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 Qt(`findFirstOrThrow: no "${t}" document matched`);return i},async findMany(t,n={}){const i=w.tables[t];if(!i)throw new g("INTERNAL",`unknown table: ${t}`);await U();const o=Gt(n.orderBy,i.shape),s=n.cursor?Vt(o,Yt(n.cursor)):void 0,u=je,E=async(L,M,j,ge)=>{if(He(L))return c?sn(c,L,M,j,ge):Ke(L);const ve=w.tables[L];if(!ve)throw new g("INTERNAL",`unknown table: ${L}`);const me=ue(ve.softDeleteMode,void 0),z={[M]:{in:j}},D=q(q(z,ge),me),ce=await Te(D,L,void 0),Ge=we(ce,b),Ve=W(M);let de=e`SELECT ${Ve} AS __fk__, COUNT(*) AS ${e.identifier("count")} FROM ${e.identifier(L)}`;Ge&&(de=e`${de} WHERE ${Ge}`),de=e`${de} GROUP BY ${Ve}`;const It=await I(r,l,de),Ye=new Map;for(const Xe of It)Ye.set(Xe.__fk__,Number(Xe.count??0));return Ye};let f=q(n.baseWhere,n.where);f=q(f,ue(i.softDeleteMode,n.includeDeleted)),f=await et(f,{fetcher:u,maxRelationKeys:p,relationBaseWhere:n.relationBaseWhere,schema:w,tableName:t}),s&&(f=f?{AND:[f,s]}:s);const h=we(f,b),d=Tn(o,l);let _=e`SELECT * FROM ${e.identifier(t)}`;h&&(_=e`${_} WHERE ${h}`),_=e`${_} ORDER BY ${d}`;const y=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;y!==void 0&&(_=e`${_} LIMIT ${e.raw(String(y+1))}`);const T=await I(r,l,_),R=En(i,T);if(y===void 0)return n.with&&await tt({fetcher:u,groupedCounter:E,parents:R,...nt(n),schema:w,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:it(R,n.select,n.with)};const C=R.length>y,A=C?R.slice(0,y):R,O=A.at(-1);return n.with&&await tt({fetcher:u,groupedCounter:E,parents:A,...nt(n),schema:w,tableName:t,with:n.with}),{continueCursor:C&&O?Xt(O,o):null,isDone:!C,page:it(A,n.select,n.with)}},async get(t,n){const i=await ie(t,n);if(!i)return null;const o=w.tables[i];return o?ee(o,await mt.load(i,t)):null},async groupBy(t,n){const i=w.tables[t];if(!i)throw new g("INTERNAL",`unknown table: ${t}`);await U();const o=n.agg??{op:"count"};if(fe(o.op),o.op!=="count"&&!o.field)throw new g("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);const s=ue(i.softDeleteMode,void 0),u=q(q(n.baseWhere,n.where),s),E=await Te(u,t,n.relationBaseWhere),f=E!==u;if(i.aggregateIndexes&&!n.baseWhere&&!f&&!s){const R=await gt(t,i.aggregateIndexes,o,n);if(R!==void 0)return R}Dn(i,t,n.by,o);const h=we(E,b),d=n.by.map(R=>e`${W(R)} AS ${e.identifier(R)}`);if(o.op==="count")d.push(e`COUNT(*) AS ${e.identifier("value")}`);else{if(!o.field)throw new g("INTERNAL",`groupBy(${t}, { agg: { op: "${o.op}" } }): "field" is required for non-count reducers`);d.push(e`${e.raw(fe(o.op))}(${W(o.field)}) AS ${e.identifier("value")}`)}const _=e.join(n.by.map(R=>W(R)),e`, `);let y=e`SELECT ${e.join(d,e`, `)} FROM ${e.identifier(t)}`;h&&(y=e`${y} WHERE ${h}`),y=e`${y} GROUP BY ${_}`;const T=await I(r,l,y);return bn(n.by,T)},async insert(t,n,i){const o=w.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);await U();const s=gn(o,n,Y);Ne(o,s);let u,E=!0;i?.clientId!==void 0?(jt(i.clientId),u=i.clientId):i?.allowExplicitId&&typeof s._id=="string"?u=s._id:(u=N(),E=!1);const f=i?.allowExplicitId&&typeof s._creationTime=="number"?s._creationTime:v(),h={...s,_creationTime:f,_id:u};H(t,"before","insert")&&await K("before","insert",{doc:{...h},id:u,op:"insert",table:t}),await ye(t),await pe(t);const{columns:d,values:_}=Tt(o,u,f,s);return await St(t,e`INSERT INTO ${e.identifier(t)} (${Z(d)}) VALUES (${ne(_)})`),E&&Ae.set(u,t),await re(t,void 0,h),await Q(t,u,void 0,h),await ae(t,u,h),await P(t,u,"insert",h),H(t,"after","insert")&&await K("after","insert",{doc:h,id:u,op:"insert",table:t}),u},normalizeId(t,n){return Kt(w,t,n)},async patch(t,n,i){Qe("patch",n);const o=await ie(t,i);if(!o)throw new g("INTERNAL",`document not found: ${t}`);const s=w.tables[o];if(!s)throw new g("INTERNAL",`document not found: ${t}`);const u=await Re(o,t),E=ee(s,u);if(!E)throw new g("INTERNAL",`document not found: ${t}`);const f={...E,...n,_id:t};lt(s,n,f,Y),Ne(s,f,!0),H(o,"before","update")&&await K("before","update",{doc:{...f},id:t,op:"update",previous:E,table:o}),await ye(o),await pe(o);const h=Object.keys(s.shape),d=e.join(h.map(_=>e`${e.identifier(_)} = ${G(f[_]??null)}`),e`, `);await Se(o,"UPDATE",d,u),await re(o,E,f),await Q(o,t,E,f),await ae(o,t,f,E),await P(o,t,"update",f),H(o,"after","update")&&await K("after","update",{doc:f,id:t,op:"update",previous:E,table:o})},async restore(t,n){const i=await ie(t,n);if(!i)throw new g("INTERNAL",`document not found: ${t}`);const o=w.tables[i],s=o?.softDeleteMode?.field;if(!o||!s)throw new g("INTERNAL",`ctx.db.restore: table "${i}" is not a .softDelete() table`);const u=await Re(i,t),E=u?.[s]!==null&&u?.[s]!==void 0;if(await x.patch(t,{[s]:null},n),E){const f=ee(o,u);f!==null&&await Q(i,t,void 0,{...f,[s]:null})}},query(t){const n=w.tables[t];if(!n)throw new g("INTERNAL",`unknown table: ${t}`);const i="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",o=[],s=f=>o.every(h=>h(f)),u=async(f,h)=>{await U();const d=o.length>0,_=await Dt(r,l,n,t,f,qt(d?void 0:h));if(!d)return h===void 0&&Bt(_),_;const y=_.filter(T=>s(T));return h===void 0?y:y.slice(0,h)},E=f=>{const h={async*[Symbol.asyncIterator](){if(!f)throw new g("INTERNAL",i);yield*await u(f,void 0)},async collect(){if(!f)throw new g("INTERNAL",i);return u(f,void 0)},async collectWithScores(){throw new g("GLOBAL_SEARCH_SCORES_UNSUPPORTED",`collectWithScores() is not supported on \`.global()\` tables (table "${t}") — relevance scores are not yet surfaced on this backend; use .collect() instead`)},filter(d){return o.push(d),h},async first(){if(!f)throw new g("INTERNAL",i);return(await u(f,1))[0]??null},order(){return h},async paginate(d){if(!f)throw new g("INTERNAL",i);const _=Nt(d);return Mt(await u(f,Ot(_)),_)},async take(d){if(!f)throw new g("INTERNAL",i);return u(f,d)},async unique(){if(!f)throw new g("INTERNAL",i);const d=await u(f,2);if(d.length>1)throw new dn(`unique() on table "${t}" matched ${String(d.length)} documents; expected at most one`);return d[0]??null},withGeoIndex(){throw new g("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new g("INTERNAL",i)},withSearchIndex(d,_){const y=(n.searchIndexes??[]).find(R=>R.name===d);if(!y)throw new g("INTERNAL",`unknown search index "${d}" on table "${t}"`);const T={definition:y,field:y.field,filters:[],hasQuery:!1,indexName:d,query:""};if(_(kt(T,t,Ct(y.language))),!T.hasQuery)throw new g("INTERNAL",`search index "${d}" on table "${t}" requires a .search(field, query) call`);return E(T)}};return h};return E(void 0)},async rank(t,n,i){const o=w.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(M=>M.name===n);if(!s)throw new g("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(i.restrictsCounts)throw new Ze(t);if(await U(),!await ke(t,s))return null;const E=typeof i.row=="string"?i.row:i.row._id;if(!E)return null;const f=le(t,s.name),h=s.sortBy.map((M,j)=>$e(j)),d=Z(["__partition__",...h]),y=(await I(r,l,e`SELECT ${d} FROM ${e.identifier(f)} WHERE ${e.identifier("__id__")} = ${E}`))[0];if(!y)return null;const T=y.__partition__,R=q(i.baseWhere,i.where);ze(R,w,t,"rank");const C=Je(s,R);if(C&&Ie(s.partitionBy??[],C)!==T)return null;const A=An(l.name,s,h,y,E),O=await I(r,l,e`SELECT COUNT(*) AS c FROM ${e.identifier(f)} WHERE ${e.identifier("__partition__")} = ${T}${A?e` AND (${A})`:e``}`),L=await I(r,l,e`SELECT COUNT(*) AS c FROM ${e.identifier(f)} WHERE ${e.identifier("__partition__")} = ${T}`);return{position:Number(O[0]?.c??0)+1,total:Number(L[0]?.c??0)}},async rankPage(t,n,i={}){ze(q(i.baseWhere,i.where),w,t,"rankPage");const o=w.tables[t];if(!o)throw new g("INTERNAL",`unknown table: ${t}`);const s=o.rankIndexes?.find(D=>D.name===n);if(!s)throw new g("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await U(),!await ke(t,s))return{continueCursor:null,isDone:!0,page:[]};const E=le(t,s.name),f=s.sortBy.map((D,ce)=>$e(ce)),h=Math.max(1,Math.min(1e3,Math.floor(i.take??100))),d=q(i.baseWhere,i.where),_=Je(s,d),y=kn(s,f),T=e.join(y.map(D=>e`${e.identifier(D.column)} ${e.raw(D.direction==="desc"?"DESC":"ASC")}`),e`, `),R=[];typeof i.partitionKey=="string"?R.push(e`${e.identifier("__partition__")} = ${i.partitionKey}`):_&&R.push(e`${e.identifier("__partition__")} = ${Ie(s.partitionBy??[],_)}`);const C=Ht(i);if(C!==void 0){const D=Ln(l.name,y,C);D!==void 0&&R.push(D)}const A=Z([_e,"__partition__",...f]);let O=e`SELECT ${A} FROM ${e.identifier(E)}`;R.length>0&&(O=e`${O} WHERE ${e.join(R,e` AND `)}`),O=e`${O} ORDER BY ${T} LIMIT ${e.raw(String(h+1))}`;const L=await I(r,l,O),M=L.length>h,j=M?L.slice(0,h):L,ge=j.map(D=>D[_e]),ve=await Nn(r,l,o,t,ge);let me=null;const z=j.at(-1);if(M&&z!==void 0){const D=[z.__partition__,...f.map(ce=>z[ce]),z[_e]];me=Mn(D)}return{continueCursor:me,isDone:!M,page:ve}},async replace(t,n,i,o){Qe("replace",n);const s=await ie(t,i);if(!s)throw new g("INTERNAL",`document not found: ${t}`);const u=w.tables[s];if(!u)throw new g("INTERNAL",`document not found: ${t}`);const E=await Re(s,t);if(E===void 0)throw new g("INTERNAL",`document not found: ${t}`);const h=Pt(w,s,"update")||(u.aggregateIndexes??[]).length>0||(u.rankIndexes??[]).length>0?ee(u,E)??void 0:void 0,d=o?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:v(),_={...n,_creationTime:d,_id:t};lt(u,n,_,Y),Ne(u,_),H(s,"before","update")&&await K("before","update",{doc:{..._},id:t,op:"update",previous:h,table:s}),await ye(s),await pe(s);const y=Object.keys(u.shape),T=e.join([e`${e.identifier("_creationTime")} = ${d}`,...y.map(R=>e`${e.identifier(R)} = ${G(_[R]??null)}`)],e`, `);await Se(s,"UPDATE",T,E),await re(s,h,_),await Q(s,t,h,_),await ae(s,t,_,h),await P(s,t,"update",_),H(s,"after","update")&&await K("after","update",{doc:_,id:t,op:"update",previous:h,table:s})}};return Pe={db:x,scheduler:Ce},x};export{ai as backfillSqlSearchIndexes,oi as createSqlCtxDb,di as decodeGlobalRow,Hn as readSqlCdcChangedTables,ii as readSqlCdcChanges,Et as readSqlCdcFloor,Wn as runSqlCdcMigration,Lt as runSqlSearchMigrations,Un as sweepSqlCdcRetention};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as l}from"@lunora/errors";import{D as y,c as Z,m as tt,r as R,a as nt,l as W,w as N,b as et}from"./ctx-db-search-state-D3Cz0jkq.mjs";import{sql as e}from"drizzle-orm";import{unionAll as it}from"@lunora/shard-engine";import{queryRun as E,decodeRows as Q,queryAll as A,queryBatch as rt,createIndexIfNotExists as q,columnRefSql as M,serializeColumnValue as ot,forEachRowPaged as G}from"./decodeGlobalRow-BNt0QNvu.mjs";const st=t=>{const n=atob(t),i=Uint8Array.from(n,r=>r.codePointAt(0)??0);return new TextDecoder().decode(i)},at=()=>new l("BAD_REQUEST","invalid cursor"),F=16,k=8,h=1024,v=(t,n)=>n.query(t),ft=(t,n)=>{if(!n)return{exact:!0,lower:t,upper:t};const i=[...t].at(-1)??"",r=(i.codePointAt(0)??0)+1;if(r>=55296&&r<=57343||r>1114111)return{exact:!0,lower:t,upper:t};const o=t.slice(0,t.length-i.length);return{exact:!1,lower:t,upper:o+String.fromCodePoint(r)}},Lt=(t,n,i)=>{const r={eq:(o,s)=>{if(!t.definition.filterFields?.includes(o))throw new l("INTERNAL",`field "${o}" is not a filter field of search index "${t.indexName}" on table "${n}"`);if(t.filters.length>=k)throw new l("BAD_REQUEST",`search index "${t.indexName}" on table "${n}": at most ${String(k)} .eq() filters are supported per search query`);return t.filters.push({field:o,value:s}),r},search:(o,s)=>{const a=t;if(o!==a.definition.field)throw new l("INTERNAL",`search index "${a.indexName}" on table "${n}" indexes "${a.definition.field}", not "${o}"`);const f=v(s,i).length;if(f>F)throw new l("BAD_REQUEST",`search index "${a.indexName}" on table "${n}": at most ${String(F)} search terms are supported (got ${String(f)})`);return a.field=o,a.query=s,a.hasQuery=!0,r}};return r},Ot=t=>{if(t.length>h)throw new l("BAD_REQUEST",`more than ${String(h)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},xt=t=>Math.min(t.offset+t.numItems+1,h),ct=t=>btoa(`search:${String(t)}`),ut=t=>{let n;try{n=st(t)}catch{return}if(!n.startsWith("search:"))return;const i=Number(n.slice(7));return Number.isInteger(i)&&i>=0?i:void 0},Ut=t=>{if(typeof t.endCursor=="string")throw new l("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(t.numItems))throw new l("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(t.numItems)}`);const n=Math.max(0,Math.floor(t.numItems)),i=t.cursor?ut(t.cursor):0;if(i===void 0)throw at();if(i+n>=h)throw new l("BAD_REQUEST",`search pagination reaches the ${String(h)}-document limit (offset ${String(i)} + ${String(n)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,h-i-1))} or fewer, or narrow the query or the filters instead`);return{numItems:n,offset:i}},Bt=(t,n)=>{const i=n.offset+n.numItems,r=n.numItems>0&&t.length>i;return{continueCursor:r?ct(i):null,isDone:!r,page:t.slice(n.offset,i)}},qt=t=>{if(t===void 0)return h+1;if(!Number.isFinite(t))return h;const n=Math.max(0,Math.floor(t));if(n>h)throw new l("BAD_REQUEST",`search returns at most ${String(h)} documents (asked for ${String(n)}) — narrow the query or paginate instead`);return n},dt=(t,n)=>{if(!n.includes("."))return t[n];let i=t;for(const r of n.split(".")){if(i===null||typeof i!="object"||Array.isArray(i))return;i=i[r]}return i},b=(t,n)=>`${t}__fts_${n}`,$t="__text__",$="__id__",g="__token__",O="__n__",mt=1e3,V=(t,n)=>n.document(t),x=(t,n)=>dt(t,n),lt=t=>typeof t=="string"?t:t==null?"":typeof t=="number"||typeof t=="bigint"||typeof t=="boolean"?String(t):JSON.stringify(t)??"",St=(t,n,i)=>t!==void 0&&n!==void 0&&x(t,i.field)===x(n,i.field),ht=(t,n)=>V(lt(x(t,n.field)),y(n.language)).slice(0,mt),U=(t,n)=>ht(t,n).join(" "),wt=(t,n)=>{const i=new Map;for(const r of V(t,n))i.set(r,(i.get(r)??0)+1);return i},C=async(t,n,i,r)=>{await E(t,n,e`DELETE FROM ${e.identifier(i)} WHERE ${e.identifier($)} = ${r}`)},L=(t,n)=>t.name==="mysql"?e`${e.identifier(n)}(191)`:t.textPatternOperatorClass===void 0?e`${e.identifier(n)}`:e`${e.identifier(n)} ${e.raw(t.textPatternOperatorClass)}`,H=50,Et=(t,n)=>n?e`${e.identifier(g)} LIKE ${`${t}%`}`:e`${e.identifier(g)} = ${t}`,X=(t,n)=>{const i=n.filters.map(r=>e`m.${M(r.field)} = ${ot(r.value)}`);return t.softDeleteMode&&i.push(e`m.${M(t.softDeleteMode.field)} IS NULL`),i},J=async(t,n,i,r,o,s,a)=>{const f=X(i,o);let c=e`SELECT m.* FROM (${a}) s JOIN ${e.identifier(r)} m ON m.${e.identifier("id")} = s.${e.identifier($)}`;return f.length>0&&(c=e`${c} WHERE ${e.join(f,e` AND `)}`),c=e`${c} ORDER BY s.${e.identifier("__score__")} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`,Q(i,await A(t,n,c))},pt=async(t,n,i,r,o,s)=>{const a=v(o.query,y(o.definition.language));if(a.length===0)return[];const f=b(r,o.indexName),c=a.length-1,u=a.map((d,_)=>Et(d,_===c)),m=e.join(u,e` OR `),S=u.map(d=>e`SUM(CASE WHEN ${d} THEN ${e.identifier(O)} ELSE 0 END)`),p=e.join(S.map(d=>e`${d} > 0`),e` AND `),w=e`SELECT ${e.identifier($)}, ${e.join(S,e` + `)} AS ${e.identifier("__score__")} FROM ${e.identifier(f)} WHERE ${m} GROUP BY ${e.identifier($)} HAVING ${p}`;return J(t,n,i,r,o,s,w)},_t=async(t,n,i,r,o,s)=>{const a=v(o.query,y(o.definition.language));if(a.length===0)return[];const f=b(r,o.indexName),c=`${f}__vocab`,u=a.length-1,m=a.map((w,d)=>{const _=ft(w,d===u),z=_.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(d))} AS ${e.identifier("__term__")}, COUNT(*) AS ${e.identifier("__n__")} FROM ${e.identifier(c)} WHERE ${z} GROUP BY ${e.identifier("doc")}`}),S=a.map((w,d)=>e`SUM(CASE WHEN u.${e.identifier("__term__")} = ${e.raw(String(d))} THEN u.${e.identifier("__n__")} ELSE 0 END)`),p=e`SELECT f.${e.identifier($)} AS ${e.identifier($)}, ${e.join(S,e` + `)} AS ${e.identifier("__score__")} FROM (${it(m)}) u JOIN ${e.identifier(f)} f ON f.rowid = u.${e.identifier("doc")} GROUP BY f.${e.identifier($)} HAVING ${e.join(S.map(w=>e`${w} > 0`),e` AND `)}`;return J(t,n,i,r,o,s,p)},gt=async(t,n,i,r,o,s)=>{const a=n.nativeTextSearch,f=v(o.query,y(o.definition.language));if(!a||f.length===0)return[];const c=b(r,o.indexName),u=[a.matches(c,f),...X(i,o)],m=e`SELECT m.* FROM ${e.identifier(c)} JOIN ${e.identifier(r)} m ON m.${e.identifier("id")} = ${e.identifier(c)}.${e.identifier($)} WHERE ${e.join(u,e` AND `)} ORDER BY ${a.rank(c,f)} DESC, m.${e.identifier("_creationTime")} DESC, m.${e.identifier("id")} ASC LIMIT ${e.raw(String(s))}`;return Q(i,await A(t,n,m))},yt={ensureCompanion:async(t,n,i)=>{const{integer:r,key:o}=n.companionTypes;await E(t,n,e`CREATE TABLE IF NOT EXISTS ${e.identifier(i)} (${e.identifier(g)} ${e.raw(o)} NOT NULL, ${e.identifier($)} ${e.raw(o)} NOT NULL, ${e.identifier(O)} ${e.raw(r)} NOT NULL)`),await q(t,n,{columns:e`${L(n,g)}, ${L(n,$)}`,name:`${i}__btree`,table:i,unique:!1}),await q(t,n,{columns:L(n,$),name:`${i}__by_id`,table:i,unique:!1})},indexDocument:async(t,n,i,r,o,s)=>{await C(t,n,i,r);const a=[...wt(U(o,s),y(s.language))],f=e.join([g,$,O].map(u=>e.identifier(u)),e`, `),c=[];for(let u=0;u<a.length;u+=H){const m=e.join(a.slice(u,u+H).map(([S,p])=>e`(${S}, ${r}, ${p})`),e`, `);c.push(e`INSERT INTO ${e.identifier(i)} (${f}) VALUES ${m}`)}await rt(t,n,c)},name:"inverted",runSearch:pt},Tt={ensureCompanion:async(t,n,i)=>{await E(t,n,e`CREATE VIRTUAL TABLE IF NOT EXISTS ${e.identifier(i)} USING fts5(${e.identifier($t)}, ${e.identifier($)} UNINDEXED)`),await E(t,n,e`CREATE VIRTUAL TABLE IF NOT EXISTS ${e.identifier(`${i}__vocab`)} USING fts5vocab(${e.identifier(i)}, ${e.raw("instance")})`)},indexDocument:async(t,n,i,r,o,s)=>{await C(t,n,i,r),await E(t,n,e`INSERT INTO ${e.identifier(i)} (${e.identifier("__text__")}, ${e.identifier($)}) VALUES (${U(o,s)}, ${r})`)},name:"fts5",runSearch:_t},It={ensureCompanion:async(t,n,i)=>{const r=n.nativeTextSearch;if(r){await E(t,n,r.createCompanion(i,n.companionTypes.key));for(const o of r.createIndexes(i))await E(t,n,o)}},indexDocument:async(t,n,i,r,o,s)=>{const a=n.nativeTextSearch;a&&(await C(t,n,i,r),await E(t,n,a.indexDocument(i,r,U(o,s))))},name:"native",runSearch:gt},T=(t,n)=>t.strategy==="native"&&n.nativeTextSearch!==void 0?It:n.supportsFts5?Tt:yt,D=(t,n)=>`${Z(t)}/${T(t,n).name}`,B=function*(t){for(const[n,i]of Object.entries(t.tables)){const r=i.searchIndexes;if(!(i.shardMode!==void 0&&i.shardMode.kind!=="global"||!r))for(const o of r)yield[n,i,o]}},I=(t,n)=>b(t,n.name),Nt=async(t,n,i,r)=>{const o=I(i,r);return W(await R(t,n,o),D(r,n)).finished?!0:et(t,n,o)},Mt=async(t,n,i,r,o,s)=>{if(!await Nt(t,n,r,o.definition))throw new l("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, or run the backfillSearch admin operation to complete it now`);return T(o.definition,n).runSearch(t,n,i,r,o,s)},P=t=>t.slice(t.lastIndexOf("/")+1),j=200,Y=async(t,n,i,r,o)=>{const s=I(r,o),a=T(o,n),f=D(o,n),c=W(await R(t,n,s),f);if(c.finished)return!0;if(c.wipe&&await N(t,n,s,void 0,!1,f),(await A(t,n,n.tableExists(r))).length===0)return await N(t,n,s,void 0,!0,f),!0;let m=0,S=c.cursor;await G(t,n,i,r,async w=>{m+=1;const d=w._id;typeof d=="string"&&(S=d,await a.indexDocument(t,n,s,d,w,o))},{after:c.cursor,limit:j});const p=m<j;return await N(t,n,s,S,p,f),p},K=async(t,n,i)=>{await tt(t,i);for(const[r,,o]of B(n)){const s=I(r,o),a=D(o,i),f=await R(t,i,s);f.profile!==void 0&&P(f.profile)!==P(a)&&(await E(t,i,e`DROP TABLE IF EXISTS ${e.identifier(s)}`),await nt(t,i,s)),await T(o,i).ensureCompanion(t,i,s)}},Rt=async(t,n,i,r,o)=>{const s=I(r,o);if((await R(t,n,s)).profile!==void 0)return;let f=0;(await A(t,n,n.tableExists(r))).length>0&&await G(t,n,i,r,()=>{f+=1},{limit:1}),await N(t,n,s,void 0,f===0,D(o,n))},Ft=async(t,n,i)=>{await K(t,n,i);for(const[r,o,s]of B(n)){if(s.staged){await Rt(t,i,o,r,s);continue}await Y(t,i,o,r,s)}},kt=async(t,n,i)=>{await K(t,n,i);for(const[r,o,s]of B(n)){let a=!1;for(;!a;)a=await Y(t,i,o,r,s)}},Ht=t=>{const{dialect:n,exec:i,schema:r}=t;return async(o,s,a,f)=>{const c=r.tables[o]?.searchIndexes;if(!(!c||c.length===0))for(const u of c){if(St(f,a,u))continue;const m=I(o,u);if(a){await T(u,n).indexDocument(i,n,m,s,a,u);continue}await C(i,n,m,s)}}};export{Lt as A,Ut as C,Bt as R,qt as T,Mt as a,xt as b,Ht as c,kt as d,Ft as r,Ot as x};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{sql as e}from"drizzle-orm";import{queryRun as p,queryAll as m}from"./decodeGlobalRow-BNt0QNvu.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 +1 @@
|
|
|
1
|
-
import{bigintSqlKey as o}from"@lunora/shard-engine";import{B as a,c as i,e as n,a as r,s as c,t as d}from"./value-codec-
|
|
1
|
+
import{bigintSqlKey as o}from"@lunora/shard-engine";import{B as a,c as i,e as n,a as r,s as c,t as d}from"./value-codec-CkEe2gLC.mjs";export{a as BIGINT_KEY_LENGTH,o as bigintSqlKey,i as decodeBigint,n as effectiveColumnKind,r as sqliteDecode,c as sqliteEncode,d as tryJsonParse};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{renderSql as d}from"@lunora/shard-engine";import{sql as i}from"drizzle-orm";import{s as I,a as N,e as _}from"./value-codec-CkEe2gLC.mjs";import{OCC_VERSION_COLUMN as F}from"./OCC_VERSION_COLUMN-ByC64Jgx.mjs";const q=n=>n==="_id"||n==="id"?"id":n,M=n=>i`${i.identifier(q(n))}`,v=n=>{const t=[];for(const[e,o]of Object.entries(n.shape)){const r=o._meta?.column;r&&t.push([e,r])}return t},O=(n,t,e)=>{const{params:o,sql:r}=d(t.name,e);return n.all(r,o)},u=(n,t,e)=>{const{params:o,sql:r}=d(t.name,e);return n.run(r,o)},k=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=>d(t.name,o)))}},D=async(n,t,e)=>{const o=e.unique?i`UNIQUE `:i``;if(t.name==="mysql"){try{await u(n,t,i`CREATE ${o}INDEX ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)}catch(r){const s=r;if(s.errno!==1061&&s.code!=="ER_DUP_KEYNAME"&&s.code!==1061)throw r}return}await u(n,t,i`CREATE ${o}INDEX IF NOT EXISTS ${i.identifier(e.name)} ON ${i.identifier(e.table)} (${e.columns})`)},K=I,h=n=>n?._meta?.column?.notNull===!1,b=n=>{if(n.kind!=="optional"||h(n))return!1;const t=n._meta?.inner;return!h(t)},w=new WeakMap,y=n=>{let t=w.get(n);return t===void 0&&(t=Object.entries(n.shape).map(([e,o])=>[e,_(o),b(o)]),w.set(n,t)),t},S=(n,t)=>{const e={};for(const[o,r,s]of y(n)){const c=t[o];c===void 0||s&&c===null||(e[o]=N(c,r))}return e._id=t.id,e._creationTime=t._creationTime,e},$=(n,t)=>t?S(n,t):null,L=(n,t)=>{const e=[];for(const o of t){const r=$(n,o);r&&e.push(r)}return e},R=500,B=async(n,t,e,o,r,s={})=>{let c=s.after,a=s.limit,m=!0;for(;m&&(a===void 0||a>0);){const f=a===void 0?R:Math.min(R,a),C=c===void 0?i``:i` WHERE ${i.identifier("id")} > ${c}`,l=await O(n,t,i`SELECT * FROM ${i.identifier(o)}${C} ORDER BY ${i.identifier("id")} ASC LIMIT ${i.raw(String(f))}`);for(const p of l){const E=$(e,p);E&&await r(E)}c=l.at(-1)?.id,m=l.length===f,a=a===void 0?void 0:a-l.length}};export{R as BACKFILL_BATCH_SIZE,F as OCC_VERSION_COLUMN,M as columnRefSql,D as createIndexIfNotExists,S as decodeGlobalRow,$ as decodeRow,L as decodeRows,B as forEachRowPaged,q as physicalColumn,O as queryAll,k as queryBatch,u as queryRun,K as serializeColumnValue,v as tableColumns};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as R}from"@lunora/errors";import{aggregateTableName as C,rankTableName as q,sortColumnName as A,renderSql as v,bigintSqlKey as D}from"@lunora/shard-engine";import{sql as n}from"drizzle-orm";import{queryRun as d,queryAll as w,createIndexIfNotExists as E,tableColumns as M,columnRefSql as m,queryBatch as B}from"./decodeGlobalRow-BNt0QNvu.mjs";import{B as N,e as T}from"./value-codec-CkEe2gLC.mjs";import{OCC_VERSION_COLUMN as p}from"./OCC_VERSION_COLUMN-ByC64Jgx.mjs";const S=(t,i)=>i.columnType(T(t)),k=(t,i,e)=>{const o=[];for(const[f,l]of Object.entries(i.shape)){if(!l._meta?.column)continue;const u=l._meta.column.notNull&&l.kind!=="optional"?" NOT NULL":"";o.push(n`${n.identifier(f)} ${n.raw(`${S(l,e)}${u}`)}`)}const s=[...e.frameworkColumns().map(f=>n`${n.identifier(f.name)} ${n.raw(f.type)}`),n`${n.identifier(p)} ${n.raw(e.companionTypes.integer)}`],a=s.length+o.length,r=e.maxTableColumns;if(r!==void 0&&a>r){const f=a-1===r,l="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 R("VALIDATION_ERROR",`@lunora/sql-store: global table "${t}" needs ${String(a)} columns, over this engine's ${String(r)}-column limit. ${f?`One of them is "${p}", the row version every guarded write reads, which caps declared fields at ${String(r-s.length)}. A table provisioned at ${String(r)} columns before that column existed cannot be widened to hold it. `:""}${l}`)}return n.join([...s,...o],n`, `)},x=t=>{if(t.indexKeyPrefix?.("string")===void 0)return n`${m("_creationTime")}, ${m("id")}`},U=async(t,i,e)=>{if(i.name!=="sqlite")return;const s=(await w(t,i,n`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${e.name} AND tbl_name = ${e.table}`))[0]?.sql;if(typeof s!="string")return;const a=l=>{const u=l.indexOf("(");return u===-1?void 0:l.slice(u,l.lastIndexOf(")")+1)},r=e.unique?n`UNIQUE `:n``,f=a(v(i.name,n`CREATE ${r}INDEX ${n.identifier(e.name)} ON ${n.identifier(e.table)} (${e.columns})`).sql);if(!(f===void 0||f===a(s))){if(e.unique){const l=n.join(e.refs.map(c=>n`${c} IS NOT NULL`),n` AND `);if((await w(t,i,n`SELECT ${e.columns} FROM ${n.identifier(e.table)} WHERE ${l} GROUP BY ${e.columns} HAVING COUNT(*) > 1 LIMIT 1`)).length>0)throw new R("INTERNAL",`unique index "${e.name}" on "${e.table}" cannot be re-created with its new column list: existing rows are duplicates under it. De-duplicate the table with a data migration first; the previous index is left in place.`)}await d(t,i,n`DROP INDEX IF EXISTS ${n.identifier(e.name)}`)}},j=async(t,i,e,o)=>{const s=r=>{const f=m(r),l=e.shape[r],u=l&&o.indexKeyPrefix?o.indexKeyPrefix(T(l)):void 0;return u===void 0?f:n`${f}(${n.raw(String(u))})`},a=x(o);for(const r of e.indexes){const f=r.fields.map($=>s($)),l=n.join(f,n`, `),u=r.unique??!1,c={columns:u||a===void 0?l:n`${l}, ${a}`,name:`${i}_${r.name}`,refs:f,table:i,unique:u};await U(t,o,c),await E(t,o,c)}a!==void 0&&await E(t,o,{columns:a,name:`${i}__by_creation`,table:i,unique:!1});for(const[r,f]of M(e))f.unique&&await E(t,o,{columns:s(r),name:`${i}_unique_${r}`,table:i,unique:!0})},y="__lunora_migration_state",P=async(t,i)=>{await d(t,i,n`CREATE TABLE IF NOT EXISTS ${n.identifier(y)} (${n.identifier("name")} ${n.raw(i.companionTypes.key)} PRIMARY KEY)`)},F=async(t,i,e)=>(await w(t,i,n`SELECT ${n.identifier("name")} FROM ${n.identifier(y)} WHERE ${n.identifier("name")} = ${e}`)).length>0,K=async(t,i,e,o,s)=>{s>0&&console.warn(`[@lunora/sql-store] bigint storage migration on "${o}": ${String(s)} row(s) hold a value the order-preserving key cannot represent (non-numeric text, or a magnitude past 39 digits) and were left as stored — range filters and ORDER BY over them stay wrong until they are corrected by hand.`);try{await d(t,i,n`INSERT INTO ${n.identifier(y)} (${n.identifier("name")}) VALUES (${e})`)}catch(a){if(!i.isUniqueViolation(a))throw a}},G=100,Y=t=>Object.entries(t.shape).filter(([,i])=>i._meta?.column!==void 0&&T(i)==="bigint").map(([i])=>i),H=(t,i)=>{const e=[],o=[];for(const s of i){const a=t[s];if(!(typeof a!="string"||a.length===N))try{const r=D(BigInt(a));e.push(n`${m(s)} = ${r}`),o.push(n`${m(s)} = ${a}`)}catch{}}return{assignments:e,guards:o}},X=async(t,i,e,o)=>{const s=Y(e);if(s.length===0)return;await P(t,o);const a=`bigint-key:${i}`;if(await F(t,o,a))return;const r=n.join(s.map(c=>n`(${m(c)} IS NOT NULL AND LENGTH(${m(c)}) <> ${N})`),n` OR `),f=n.join([m("id"),...s.map(c=>m(c))],n`, `);let l="",u=0;for(;;){const c=await w(t,o,n`SELECT ${f} FROM ${n.identifier(i)} WHERE (${r}) AND ${m("id")} > ${l} ORDER BY ${m("id")} LIMIT ${n.raw(String(G))}`);if(c.length===0){await K(t,o,a,i,u);return}const $=[];for(const h of c){const{id:b}=h,{assignments:I,guards:O}=typeof b=="string"?H(h,s):{assignments:[],guards:[]};if(I.length===0){u+=1;continue}$.push(n`UPDATE ${n.identifier(i)} SET ${n.join(I,n`, `)} WHERE ${m("id")} = ${b} AND ${n.join(O,n` AND `)}`)}await B(t,o,$);const g=c.at(-1)?.id;if(typeof g!="string")return;l=g}},V=async(t,i,e,o)=>{const s=[[p,o.companionTypes.integer],...Object.entries(e.shape).filter(([,r])=>r._meta?.column!==void 0).map(([r,f])=>[r,S(f,o)])],a=async r=>{try{return await w(t,o,n`SELECT ${n.join(r.map(f=>m(f)),n`, `)} FROM ${n.identifier(i)} LIMIT 0`),!0}catch{return!1}};if(!await a(s.map(([r])=>r)))for(const[r,f]of s)await a([r])||await d(t,o,n`ALTER TABLE ${n.identifier(i)} ADD COLUMN ${n.identifier(r)} ${n.raw(f)}`)},on=async(t,i,e)=>{for(const[o,s]of Object.entries(i.tables)){if(s.shardMode?.kind!=="global")continue;const a=k(o,s,e);await d(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(o)} (${a})`),await V(t,o,s,e),await j(t,o,s,e),await X(t,o,s,e)}},L=t=>t.shardMode===void 0||t.shardMode.kind==="global",rn=async(t,i,e)=>{const{integer:o,key:s,real:a}=e.companionTypes;for(const[r,f]of Object.entries(i.tables)){const l=f.aggregateIndexes;if(!(!l||l.length===0||!L(f)))for(const u of l){const c=C(r,u.name);await d(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(c)} (${n.identifier("__key__")} ${n.raw(s)} PRIMARY KEY, ${n.identifier("__value__")} ${n.raw(a)}, ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0)`),e.name==="sqlite"&&((await w(t,e,n`PRAGMA table_info(${n.identifier(c)})`)).some(g=>g.name==="__count__")||await d(t,e,n`ALTER TABLE ${n.identifier(c)} ADD COLUMN ${n.identifier("__count__")} ${n.raw(o)} NOT NULL DEFAULT 0`))}}},_=(t,i,e,o)=>{const s=t.name==="mysql"&&o?n`${n.identifier(i)}(191)`:n`${n.identifier(i)}`;return n`${s} ${n.raw(e)}`},W=(t,i,e)=>{const o=[_(t,"__partition__","ASC",!0)];for(const[s,a]of i.sortBy.entries()){const r=e.shape[a.field],f=r!==void 0&&t.indexKeyPrefix?.(T(r))!==void 0;o.push(_(t,A(s),a.direction==="desc"?"DESC":"ASC",f))}return o.push(_(t,"__id__","ASC",!0)),o},Q=(t,i,e)=>i.sortBy.map((o,s)=>{const a=e.shape[o.field],r=t.columnType(a?T(a):void 0);return n`${n.identifier(A(s))} ${n.raw(r)}`}),sn=async(t,i,e)=>{const{key:o}=e.companionTypes;for(const[s,a]of Object.entries(i.tables)){const r=a.rankIndexes;if(!(!r||r.length===0||!L(a)))for(const f of r){const l=q(s,f.name),u=Q(e,f,a),c=u.length>0?n`, ${n.join(u,n`, `)}`:n``;await d(t,e,n`CREATE TABLE IF NOT EXISTS ${n.identifier(l)} (${n.identifier("__id__")} ${n.raw(o)} PRIMARY KEY, ${n.identifier("__partition__")} ${n.raw(o)} NOT NULL${c})`);const $=W(e,f,a),g=`${s}__rank_${f.name}__btree`;await E(t,e,{columns:n.join($,n`, `),name:g,table:l,unique:!1})}}};export{rn as runSqlAggregateMigrations,on as runSqlGlobalTableMigrations,sn as runSqlRankMigrations};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraError as w}from"@lunora/errors";import{decodeBigintSqlKey as R,bigintSqlKey as U,BIGINT_KEY_DIGITS as S}from"@lunora/shard-engine";const B=r=>{if(r.kind!=="optional")return r.kind;const t=r._meta?.inner;return t?B(t):r.kind},p=r=>{let t="";for(let o=0;o<r.length;o+=32768)t+=String.fromCharCode(...r.subarray(o,o+32768));return btoa(t)},T=r=>{const t=atob(r),s=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)s[o]=t.codePointAt(o)??0;return s},i="$lunora.wire$",g=64,l=1024,m="__proto__",O={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},h={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},k=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},E=(r,t=0)=>{if(t>g)return!0;if(r===null)return!1;const s=typeof r;if(s==="string"||s==="boolean")return!1;if(s==="number")return!Number.isFinite(r);if(s!=="object")return!0;if(Array.isArray(r))return r.length>0&&r[0]===i?!0:r.some(o=>o===void 0||E(o,t+1));if(!k(r)||Object.hasOwn(r,m))return!0;for(const o of Object.keys(r)){const c=r[o];if(c!==void 0&&E(c,t+1))return!0}return!1},u=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===void 0)return[i,"undefined"];if(r===null)return null;const s=typeof r;if(s==="bigint")return[i,"bigint",r.toString()];if(s==="number"){const e=r;return Number.isNaN(e)?[i,"nan"]:e===1/0?[i,"inf"]:e===-1/0?[i,"-inf"]:e}if(s!=="object")return r;if(r instanceof Date)return[i,"date",u(r.getTime(),t+1)];if(r instanceof Error){const e=r,n={};for(const a of Object.keys(e))e[a]!==void 0&&(n[a]=u(e[a],t+1));const f=[i,"error",e.name,e.message,n];return e.cause!==void 0&&f.push(u(e.cause,t+1)),f}if(r instanceof URL)return[i,"url",r.href];if(r instanceof Map)return[i,"map",[...r.entries()].map(([e,n])=>[u(e,t+1),u(n,t+1)])];if(r instanceof Set)return[i,"set",[...r].map(e=>u(e,t+1))];if(r instanceof ArrayBuffer)return[i,"bytes",p(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,n=e.constructor.name,f=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return n==="Uint8Array"?[i,"bytes",p(f)]:[i,"bytes",p(f),n]}if(Array.isArray(r)){const e=r.map(n=>u(n,t+1));return e.length>0&&e[0]===i?[i,"arr",e]:e}if(!k(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const o=r,c={};for(const e of Object.keys(o)){const n=o[e];if(n===void 0)continue;const f=u(n,t+1);e===m?Object.defineProperty(c,e,{configurable:!0,enumerable:!0,value:f,writable:!0}):c[e]=f}return c},y=(r,t=0)=>{if(t>g)throw new RangeError(`wire-codec: value nesting exceeds the ${g}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===i)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(e=>y(e,t+1));case"bigint":{const e=r[2];if(typeof e!="string"||e.length>l||!/^-?\d+$/.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${l} digits)`);return BigInt(e)}case"date":{if(r.length<3)throw new TypeError("wire-codec: malformed date — missing payload");return new Date(y(r[2],t+1))}case"map":{const e=r[2];return new Map(e.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[y(n[0],t+1),y(n[1],t+1)]}))}case"set":return new Set(r[2].map(e=>y(e,t+1)));case"url":return new URL(r[2]);case"error":{const e=r[2],n=r[3],f=(Object.hasOwn(h,e)?h[e]:void 0)??Error,a=new f(n);a.name!==e&&Object.defineProperty(a,"name",{configurable:!0,value:e,writable:!0});const b=y(r[4],t+1);if(b===null||typeof b!="object"||Array.isArray(b))throw new TypeError("wire-codec: malformed error — props must be an object");for(const d of Object.keys(b))d===m?Object.defineProperty(a,d,{configurable:!0,enumerable:!0,value:b[d],writable:!0}):a[d]=b[d];return r.length>5&&Object.defineProperty(a,"cause",{configurable:!0,value:y(r[5],t+1),writable:!0}),a}case"bytes":{const e=T(r[2]),n=r[3]??"Uint8Array";if(n==="ArrayBuffer")return e.buffer.byteLength===e.byteLength?e.buffer:e.slice().buffer;const f=Object.hasOwn(O,n)?O[n]:void 0;return f?new f(e.slice().buffer):e}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(e=>y(e,t+1))}return r.map(c=>y(c,t+1))}const s=r,o={};for(const c of Object.keys(s)){const e=y(s[c],t+1);c===m?Object.defineProperty(o,c,{configurable:!0,enumerable:!0,value:e,writable:!0}):o[c]=e}return o},A=i,j=(r,t)=>r.startsWith(A)?y(t(r.slice(A.length))):t(r),L=r=>{if(typeof r=="boolean")return r?1:0;if(r===null||typeof r=="string"||typeof r=="number")return r;if(typeof r=="bigint")return U(r);if(r instanceof Uint8Array)return r;if(r instanceof ArrayBuffer)return new Uint8Array(r);try{return E(r)?A+JSON.stringify(u(r)):JSON.stringify(r)}catch(t){throw new w("BAD_REQUEST",`this value cannot be stored: ${t instanceof Error?t.message:String(t)}`)}},I=r=>{try{return JSON.parse(r)}catch{return r}},_=r=>{if(typeof r!="string")return r;const t=R(r);if(t!==void 0)return t;try{return BigInt(r)}catch{return r}},C=r=>B(r),D=(r,t)=>{if(r===null)return r;switch(t){case"any":case"from":case"union":return typeof r=="string"&&(r.startsWith("{")||r.startsWith("[")||r.startsWith(A))?j(r,I):r;case"array":case"geoPoint":case"object":case"record":return typeof r=="string"?j(r,I):r;case"bigint":return _(r);case"boolean":return r===0||r===1?r===1:r;case"bytes":return r instanceof ArrayBuffer?r:ArrayBuffer.isView(r)?new Uint8Array(r.buffer,r.byteOffset,r.byteLength).slice().buffer:r;default:return r}},x=S+1;export{x as B,D as a,u as b,_ as c,y as d,C as e,E as n,L as s,I as t};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/sql-store",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.106",
|
|
4
4
|
"description": "Internal dialect-parameterized SQL store core for Lunora .global() backends (D1, PlanetScale)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
54
|
-
"@lunora/shard-engine": "1.0.0-alpha.
|
|
53
|
+
"@lunora/errors": "1.0.0-alpha.30",
|
|
54
|
+
"@lunora/shard-engine": "1.0.0-alpha.53",
|
|
55
55
|
"drizzle-orm": "^0.45.2"
|
|
56
56
|
},
|
|
57
57
|
"engines": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{sql as i}from"drizzle-orm";import{queryRun as f,queryAll as c}from"./decodeGlobalRow-DtOXIcLj.mjs";const a="__lunora_search_state",L=async(e,r)=>{const{integer:n,key:o}=r.companionTypes,t=async($,d)=>{try{await f(e,r,i`ALTER TABLE ${i.identifier(a)} ADD COLUMN ${i.identifier($)} ${i.raw(d)}`)}catch{}};await f(e,r,i`CREATE TABLE IF NOT EXISTS ${i.identifier(a)} (${i.identifier("companion")} ${i.raw(o)} PRIMARY KEY, ${i.identifier("cursor")} ${i.raw(o)}, ${i.identifier("done")} ${i.raw(n)} NOT NULL DEFAULT 0, ${i.identifier("profile")} ${i.raw(o)}, ${i.identifier("covered")} ${i.raw(n)} NOT NULL DEFAULT 0)`),await t("profile",o),await t("covered",`${n} NOT NULL DEFAULT 0`),await f(e,r,i`UPDATE ${i.identifier(a)} SET ${i.identifier("covered")} = 1 WHERE ${i.identifier("done")} = 1 AND ${i.identifier("covered")} = 0`)},T=e=>e===1||e===!0||e==="1",A=async(e,r,n)=>{const o=await c(e,r,i`SELECT ${i.identifier("covered")} FROM ${i.identifier(a)} WHERE ${i.identifier("companion")} = ${n}`);return T(o[0]?.covered)},R=async(e,r,n)=>{await f(e,r,i`DELETE FROM ${i.identifier(a)} WHERE ${i.identifier("companion")} = ${n}`)},l=async(e,r,n)=>{const t=(await c(e,r,i`SELECT ${i.identifier("cursor")}, ${i.identifier("done")}, ${i.identifier("profile")} FROM ${i.identifier(a)} WHERE ${i.identifier("companion")} = ${n}`))[0];if(!t)return{cursor:void 0,done:!1,profile:void 0};const{cursor:$,profile:d}=t;return{cursor:typeof $=="string"?$:void 0,done:T(t.done),profile:typeof d=="string"?d:void 0}},v=async(e,r,n,o,t,$)=>{const d=o??null,w=t?i`${i.identifier("covered")} = 1`:i`${i.identifier("covered")} = ${i.identifier("covered")}`,s=i`UPDATE ${i.identifier(a)} SET ${i.identifier("cursor")} = ${d}, ${i.identifier("done")} = ${t?1:0}, ${i.identifier("profile")} = ${$}, ${w} WHERE ${i.identifier("companion")} = ${n}`;if((await c(e,r,i`SELECT ${i.identifier("companion")} FROM ${i.identifier(a)} WHERE ${i.identifier("companion")} = ${n}`)).length>0){await f(e,r,s);return}try{await f(e,r,i`INSERT INTO ${i.identifier(a)} (${i.identifier("companion")}, ${i.identifier("cursor")}, ${i.identifier("done")}, ${i.identifier("profile")}, ${i.identifier("covered")}) VALUES (${n}, ${d}, ${t?1:0}, ${$}, ${t?1:0})`)}catch(E){if(!r.isUniqueViolation(E))throw E;await f(e,r,s)}};export{a as SEARCH_STATE_TABLE,R as clearSearchBackfillState,L as migrateSearchState,l as readSearchBackfillState,A as readSearchIndexCoverage,v as writeSearchBackfillState};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{d as S,c as s,a as i,r as l}from"./ctx-db-search-BmDhXVpE.mjs";import"./SEARCH_STATE_TABLE-CZxjE5CH.mjs";import"./decodeGlobalRow-DtOXIcLj.mjs";export{S as backfillSqlSearchIndexes,s as createSearchSync,i as runSqlSearch,l as runSqlSearchMigrations};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import{LunoraError as b}from"@lunora/errors";import{c as Mt,r as Dt,A as qt,q as Ot,C as Bt,R as Ft,a as Wt,T as Ut,x as xt,b as Pt}from"./ctx-db-search-BmDhXVpE.mjs";import{d as mi}from"./ctx-db-search-BmDhXVpE.mjs";import{literalInList as jt,throwingScheduler as Kt,CDC_LOG_TABLE as G,cursorBelowRetainedFloor as Ht,cdcTrimmedError as Gt,aggregateTableName as z,rankTableName as ne,assertNoExplicitUndefined as nt,hasTrigger as Vt,runRowValidators as qe,assertFlatPredicate as it,mergeWhere as B,sortColumnName as J,resolveRankPartition as ot,encodePartitionKey as Le,resolveRankSeekTuple as Yt,RANK_TIEBREAK as ye,CountRlsUnsupportedError as rt,normalizeIdStructurally as Xt,assertValidClientId as Qt,aggregateSqlFunction as $e,softDeleteScope as _e,compileWhereSql as he,normalizeOrderKeys as zt,buildSeekWhere as Jt,decodeCursor as Zt,resolveRelationPredicates as st,resolveWith as at,relationHooks as ct,applySelect as dt,encodeCursor as en,NotFoundError as tn,applyOnDelete as nn,ConflictError as Ee,normalizeCountArgument as on,selectIndexForCount as rn,encodeAggregateKey as Q,selectIndexForAggregate as sn,readAggregateValue as Oe,runTriggers as an,matchesRankStaticWhere as lt,CURSOR_PREFIX as cn,selectIndexForGroupBy as dn,tiebreakDirectionFor as ln,fanOutScalarCounts as un,matchesStaticWhere as Be,foldAggregateTally as fn,renderSql as wn,coerceAggregateNumber as Fe,bigintSqlKey as $n,CDC_LOG_TABLE_SEQ_INDEX as _n,NotUniqueError as hn}from"@lunora/shard-engine";import{sql as e}from"drizzle-orm";import{d as Et,e as se,B as Ne,n as En,b as yn}from"./value-codec-CPoo8vyF.mjs";import{migrateSearchState as yt,readSearchBackfillState as pn,writeSearchBackfillState as Rn}from"./SEARCH_STATE_TABLE-CZxjE5CH.mjs";import{queryAll as I,queryRun as L,createIndexIfNotExists as pe,decodeRow as ie,serializeColumnValue as H,columnRefSql as A,decodeRows as Tn,queryBatch as Ue,forEachRowPaged as ut}from"./decodeGlobalRow-DtOXIcLj.mjs";import{decodeGlobalRow as gi}from"./decodeGlobalRow-DtOXIcLj.mjs";const mn=(o,r)=>{if(o.size<r)return;const d=o.keys().next().value;d!==void 0&&o.delete(d)},ft=50,Sn=(o,r={})=>{const d=r.maxBatch??ft,i=Number.isInteger(d)&&d>0?d:ft,f=new Map;let u=!1;const a=async(R,m)=>{const g=[...m.keys()];for(let C=0;C<g.length;C+=i){const D=g.slice(C,C+i);try{const W=await o(R,D);for(const V of D){const Y=W.get(V);for(const X of m.get(V)??[])X.resolve(Y)}}catch(W){for(const V of D)for(const Y of m.get(V)??[])Y.reject(W)}}},T=()=>{u=!1;const R=[...f.entries()];f.clear();for(const[m,g]of R)a(m,g).catch(()=>{})};return{async load(R,m){return new Promise((g,C)=>{let D=f.get(R);D||(D=new Map,f.set(R,D));const W=D.get(m);W?W.push({reject:C,resolve:g}):D.set(m,[{reject:C,resolve:g}]),u||(u=!0,queueMicrotask(T))})}}},gn=new Set(["_id","id"]),je=(o,r,d)=>o==="postgres"?e`${r} IS NOT DISTINCT FROM ${d}`:o==="mysql"?e`${r} <=> ${d}`:e`${r} IS ${d}`,vn=(o,r)=>o.name!=="postgres"||r.nullable!==!0?"":r.direction==="desc"?" NULLS LAST":" NULLS FIRST",bn=(o,r)=>{const d=o.map(i=>e`${A(i.field)} ${e.raw(`${i.direction==="desc"?"DESC":"ASC"}${vn(r,i)}`)}`);if(!o.some(i=>gn.has(i.field))){const i=ln(o);d.push(e`${A("id")} ${e.raw(i==="desc"?"DESC":"ASC")}`)}return e.join(d,e`, `)},wt=50,Ke=o=>{const r=[];for(const[d,i]of Object.entries(o.shape)){const f=i._meta?.column;f&&r.push([d,f])}return r},In=(o,r,d)=>{const i={...r};for(const[f,u]of Ke(o)){if(u.serverDefault){i[f]=u.serverDefault({auth:d});continue}i[f]===void 0&&(u.defaultFn?i[f]=u.defaultFn():"defaultValue"in u&&(i[f]=u.defaultValue))}return i},$t=(o,r,d,i)=>{for(const[f,u]of Ke(o)){if(u.serverDefault){f in r&&(d[f]=u.serverDefault({auth:i}));continue}u.onUpdateFn&&!(f in r)&&(d[f]=u.onUpdateFn())}},An=128,Cn=()=>{const o=new Map;return{delete:r=>{o.delete(r)},get:r=>{const d=o.get(r);if(d!==void 0)return o.delete(r),o.set(r,d),d},set:(r,d)=>{o.has(r)?o.delete(r):mn(o,An),o.set(r,d)}}},Ln=async(o,r,d,i,f)=>{const u=f.get(i);if(u!==void 0)return u;const a=Object.entries(d.tables).filter(([,R])=>R.shardMode===void 0||R.shardMode.kind==="global").map(([R])=>R),T=await Promise.all(a.map(async R=>({found:(await I(o,r,e`SELECT 1 FROM ${e.identifier(R)} WHERE ${e.identifier("id")} = ${i} LIMIT 1`)).length>0,tableName:R})));for(const R of T)if(R.found)return f.set(i,R.tableName),R.tableName},oe=o=>o==null?null:Number(o),Nn=(o,r)=>r.map(d=>{const i={};for(const f of o)i[f]=d[f]??null;return{key:i,value:oe(d.value)}}),kn=(o,r,d)=>[...o.partitionBy??[],...o.sortBy.map(f=>f.field),...o.where?Object.keys(o.where):[]].every(f=>r[f]===d[f]),pt=o=>o.length===1?o[0]:e`(${e.join(o,e` AND `)})`,te=o=>e.join(o.map(r=>e`${e.identifier(r)}`),e`, `),re=o=>e.join(o.map(r=>e`${r}`),e`, `),Mn=(o,r,d,i,f)=>{const u=[];for(let a=0;a<d.length+1;a+=1){const T=d.slice(0,a).map(g=>je(o,e`${e.identifier(g)}`,i[g])),R=d[a],m=r.sortBy[a];a<d.length&&R!==void 0&&m!==void 0?T.push(e`${e.identifier(R)} ${e.raw(m.direction==="desc"?">":"<")} ${i[R]}`):T.push(e`${e.identifier(ye)} < ${f}`),u.push(pt(T))}return u.length>0?e.join(u,e` OR `):void 0},Dn=(o,r,d)=>{if(d.length!==r.length)return;const i=[];for(const[f,u]of r.entries()){const a=[];for(let T=0;T<f;T+=1){const R=r[T];R!==void 0&&a.push(je(o,e`${e.identifier(R.column)}`,d[T]))}a.push(e`${e.identifier(u.column)} ${e.raw(u.direction==="desc"?"<":">")} ${d[f]}`),i.push(pt(a))}return e`(${e.join(i,e` OR `)})`},qn=(o,r)=>{if(o.sortBy.length===0)throw new b("INTERNAL",`rankIndex "${o.name}" requires at least one "sortBy" column for stable pagination`);const d=[{column:"__partition__",direction:"asc"}];for(const[i,f]of o.sortBy.entries())d.push({column:r[i]??J(i),direction:f.direction});return d.push({column:ye,direction:"asc"}),d},On=async(o,r,d,i,f)=>{const a=[];for(let g=0;g<f.length;g+=50)a.push(f.slice(g,g+50));const T=await Promise.all(a.map(async g=>I(o,r,e`SELECT * FROM ${e.identifier(i)} WHERE ${e.identifier("id")} IN (${re(g)})`))),R=new Map;for(const g of T)for(const C of g)R.set(C.id,C);const m=[];for(const g of f){const C=ie(d,R.get(g));C&&m.push(C)}return m},Bn=o=>{const r=JSON.stringify(o),d=new TextEncoder().encode(r);let i="";for(const f of d)i+=String.fromCodePoint(f);return cn+btoa(i)},Rt=(o,r)=>r.columnType(se(o)),Fn=(o,r,d)=>{const i=[];for(const[a,T]of Object.entries(r.shape)){if(!T._meta?.column)continue;const R=T._meta.column.notNull&&T.kind!=="optional"?" NOT NULL":"";i.push(e`${e.identifier(a)} ${e.raw(`${Rt(T,d)}${R}`)}`)}const f=d.frameworkColumns().map(a=>e`${e.identifier(a.name)} ${e.raw(a.type)}`),u=f.length+i.length;if(d.maxTableColumns!==void 0&&u>d.maxTableColumns)throw new b("VALIDATION_ERROR",`@lunora/sql-store: global table "${o}" needs ${String(u)} columns, over this engine's ${String(d.maxTableColumns)}-column limit — split the table, or move the extra fields into one object field`);return e.join([...f,...i],e`, `)},Wn=o=>{if(o.indexKeyPrefix?.("string")===void 0)return e`${A("_creationTime")}, ${A("id")}`},Un=async(o,r,d)=>{if(r.name!=="sqlite")return;const f=(await I(o,r,e`SELECT sql FROM sqlite_master WHERE type = 'index' AND name = ${d.name} AND tbl_name = ${d.table}`))[0]?.sql;if(typeof f!="string")return;const u=R=>{const m=R.indexOf("(");return m===-1?void 0:R.slice(m,R.lastIndexOf(")")+1)},a=d.unique?e`UNIQUE `:e``,T=u(wn(r.name,e`CREATE ${a}INDEX ${e.identifier(d.name)} ON ${e.identifier(d.table)} (${d.columns})`).sql);if(!(T===void 0||T===u(f))){if(d.unique&&(await I(o,r,e`SELECT ${d.columns} FROM ${e.identifier(d.table)} GROUP BY ${d.columns} HAVING COUNT(*) > 1 LIMIT 1`)).length>0)throw new b("INTERNAL",`unique index "${d.name}" on "${d.table}" cannot be re-created with its new column list: existing rows are duplicates under it. De-duplicate the table with a data migration first; the previous index is left in place.`);await L(o,r,e`DROP INDEX IF EXISTS ${e.identifier(d.name)}`)}},xn=async(o,r,d,i)=>{const f=a=>{const T=A(a),R=d.shape[a],m=R&&i.indexKeyPrefix?i.indexKeyPrefix(se(R)):void 0;return m===void 0?T:e`${T}(${e.raw(String(m))})`},u=Wn(i);for(const a of d.indexes){const T=e.join(a.fields.map(g=>f(g)),e`, `),R=a.unique??!1,m={columns:R||u===void 0?T:e`${T}, ${u}`,name:`${r}_${a.name}`,table:r,unique:R};await Un(o,i,m),await pe(o,i,m)}u!==void 0&&await pe(o,i,{columns:u,name:`${r}__by_creation`,table:r,unique:!1});for(const[a,T]of Ke(d))T.unique&&await pe(o,i,{columns:f(a),name:`${r}_unique_${a}`,table:r,unique:!0})},xe=(o,r,d)=>{const i=o.shape[r];if(i!==void 0&&se(i)==="bigint")throw new b("BAD_REQUEST",`${d}: "${r}" is stored as an order-preserving key, which SQL cannot reduce or group — declare an aggregateIndex covering this (by, field, op) so the maintained companion answers it`)},Pn=(o,r,d,i)=>{for(const f of d)xe(o,f,`groupBy(${r}, { by: [..."${f}"] })`);i.field!==void 0&&xe(o,i.field,`groupBy(${r}, { agg: { op: "${i.op}", field: "${i.field}" } })`)},jn=100,Kn=o=>`bigint-rewrite:${o}`,_t=`bigint-key/${String(Ne)}`,Hn=o=>Object.entries(o.shape).filter(([,r])=>r._meta?.column!==void 0&&se(r)==="bigint").map(([r])=>r),Gn=(o,r)=>{const d=[];for(const i of r){const f=o[i];if(!(typeof f!="string"||f.length===Ne&&!f.startsWith("-")))try{d.push(e`${A(i)} = ${$n(BigInt(f))}`)}catch{}}return d},Vn=o=>e.join(o.map(r=>e`(${A(r)} IS NOT NULL AND (LENGTH(${A(r)}) < ${Ne} OR (LENGTH(${A(r)}) = ${Ne} AND SUBSTR(${A(r)}, 1, 1) = ${"-"})))`),e` OR `),Yn=(o,r,d)=>{const i=[];for(const f of o){const{id:u}=f,a=typeof u=="string"?Gn(f,r):[];a.length>0&&i.push(e`UPDATE ${e.identifier(d)} SET ${e.join(a,e`, `)} WHERE ${A("id")} = ${u}`)}return i},Xn=async(o,r,d,i)=>{const f=Hn(d);if(f.length===0)return;const u=Kn(r),a=await pn(o,i,u);if(a.done&&a.profile===_t)return;const T=Vn(f),R=e.join([A("id"),...f.map(g=>A(g))],e`, `);let m="";for(;;){const g=await I(o,i,e`SELECT ${R} FROM ${e.identifier(r)} WHERE (${T}) AND ${A("id")} > ${m} ORDER BY ${A("id")} LIMIT ${e.raw(String(jn))}`);if(g.length===0)break;await Ue(o,i,Yn(g,f,r));const C=g.at(-1)?.id;if(typeof C!="string")return;m=C}await Rn(o,i,u,void 0,!0,_t)},Qn=async(o,r,d,i)=>{const f=Object.entries(d.shape).filter(([,a])=>a._meta?.column!==void 0);if(f.length===0)return;const u=async a=>{try{return await I(o,i,e`SELECT ${e.join(a.map(T=>A(T)),e`, `)} FROM ${e.identifier(r)} LIMIT 0`),!0}catch{return!1}};if(!await u(f.map(([a])=>a)))for(const[a,T]of f)await u([a])||await L(o,i,e`ALTER TABLE ${e.identifier(r)} ADD COLUMN ${e.identifier(a)} ${e.raw(Rt(T,i))}`)},zn=async(o,r,d)=>{await yt(o,d);for(const[i,f]of Object.entries(r.tables)){if(f.shardMode?.kind!=="global")continue;const u=Fn(i,f,d);await L(o,d,e`CREATE TABLE IF NOT EXISTS ${e.identifier(i)} (${u})`),await Qn(o,i,f,d),await xn(o,i,f,d),await Xn(o,i,f,d)}},Jn=async(o,r,d)=>{const{integer:i,key:f,real:u}=d.companionTypes;for(const[a,T]of Object.entries(r.tables)){const R=T.aggregateIndexes;if(!(!R||R.length===0))for(const m of R){const g=z(a,m.name);await L(o,d,e`CREATE TABLE IF NOT EXISTS ${e.identifier(g)} (${e.identifier("__key__")} ${e.raw(f)} PRIMARY KEY, ${e.identifier("__value__")} ${e.raw(u)}, ${e.identifier("__count__")} ${e.raw(i)} NOT NULL DEFAULT 0)`),d.name==="sqlite"&&((await I(o,d,e`PRAGMA table_info(${e.identifier(g)})`)).some(D=>D.name==="__count__")||await L(o,d,e`ALTER TABLE ${e.identifier(g)} ADD COLUMN ${e.identifier("__count__")} ${e.raw(i)} NOT NULL DEFAULT 0`))}}},We=(o,r,d,i)=>{const f=o.name==="mysql"&&i?e`${e.identifier(r)}(191)`:e`${e.identifier(r)}`;return e`${f} ${e.raw(d)}`},Zn=(o,r,d)=>{const i=[We(o,"__partition__","ASC",!0)];for(const[f,u]of r.sortBy.entries()){const a=d.shape[u.field],T=a!==void 0&&o.indexKeyPrefix?.(se(a))!==void 0;i.push(We(o,J(f),u.direction==="desc"?"DESC":"ASC",T))}return i.push(We(o,"__id__","ASC",!0)),i},ei=(o,r,d)=>r.sortBy.map((i,f)=>{const u=d.shape[i.field],a=o.columnType(u?se(u):void 0);return e`${e.identifier(J(f))} ${e.raw(a)}`}),ti=async(o,r,d)=>{const{key:i}=d.companionTypes;for(const[f,u]of Object.entries(r.tables)){const a=u.rankIndexes;if(!(!a||a.length===0))for(const T of a){const R=ne(f,T.name),m=ei(d,T,u),g=m.length>0?e`, ${e.join(m,e`, `)}`:e``;await L(o,d,e`CREATE TABLE IF NOT EXISTS ${e.identifier(R)} (${e.identifier("__id__")} ${e.raw(i)} PRIMARY KEY, ${e.identifier("__partition__")} ${e.raw(i)} NOT NULL${g})`);const C=Zn(d,T,u),D=`${f}__rank_${T.name}__btree`;await pe(o,d,{columns:e.join(C,e`, `),name:D,table:R,unique:!1})}}},Pe="__cdc_sweep",Tt="global",ni=6e4,ii=1e4,oi=3e4;let ht=0;const ri=async(o,r)=>{const{autoincrementPrimaryKey:d,key:i,real:f,text:u}=r.companionTypes;await L(o,r,e`CREATE TABLE IF NOT EXISTS ${e.identifier(G)} (${e.identifier("seq")} ${e.raw(d)}, ${e.identifier("ts")} ${e.raw(f)} NOT NULL, ${e.identifier("table")} ${e.raw(i)} NOT NULL, ${e.identifier("id")} ${e.raw(i)} NOT NULL, ${e.identifier("op")} ${e.raw(i)} NOT NULL, ${e.identifier("doc")} ${e.raw(u)})`);const a=r.indexKeyPrefix?.("string");await pe(o,r,{columns:e`${a===void 0?e`${e.identifier("table")}`:e`${e.identifier("table")}(${e.raw(String(a))})`}, ${e.identifier("seq")}`,name:_n,table:G,unique:!1}),await L(o,r,e`CREATE TABLE IF NOT EXISTS ${e.identifier(Pe)} (${e.identifier("id")} ${e.raw(i)} NOT NULL PRIMARY KEY, ${e.identifier("lease_until")} ${e.raw(f)} NOT NULL)`),await L(o,r,e`INSERT INTO ${e.identifier(Pe)} (${e.identifier("id")}, ${e.identifier("lease_until")}) VALUES (${Tt}, ${0}) ${r.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${e.identifier("id")} = ${e.identifier("id")}`:e`ON CONFLICT(${e.identifier("id")}) DO NOTHING`}`)},si=async(o,r,d)=>{const i=e`UPDATE ${e.identifier(Pe)} SET ${e.identifier("lease_until")} = ${d+ni} WHERE ${e.identifier("id")} = ${Tt} AND ${e.identifier("lease_until")} <= ${d}`;if(r.supportsReturning)return(await I(o,r,e`${i} RETURNING ${e.identifier("id")}`)).length>0;const f=await L(o,r,i);return(r.affectedRows?r.affectedRows(f??{rowsAffected:0}):0)>0},ai=async(o,r,d,i)=>{if(!await si(o,r,i))return;const f=i-d;await L(o,r,e`
|
|
2
|
-
DELETE FROM ${e.identifier(G)} WHERE ${e.identifier("seq")} IN (
|
|
3
|
-
SELECT ${e.identifier("seq")} FROM (
|
|
4
|
-
SELECT ${e.identifier("seq")} FROM ${e.identifier(G)} WHERE ${e.identifier("ts")} <= ${f} ORDER BY ${e.identifier("seq")} ASC LIMIT ${e.raw(String(ii))}
|
|
5
|
-
) AS ${e.identifier("expired")}
|
|
6
|
-
)
|
|
7
|
-
`)},mt=async(o,r)=>{const d=await I(o,r,e`SELECT MIN(${e.identifier("seq")}) AS ${e.identifier("seq")} FROM ${e.identifier(G)}`),i=Number(d[0]?.seq??Number.NaN);return Number.isFinite(i)?i:void 0},ci=o=>JSON.stringify(En(o)?yn(o):o),di=async(o,r,d,i,f,u,a)=>{await L(o,a,e`INSERT INTO ${e.identifier(G)} (${e.identifier("ts")}, ${e.identifier("table")}, ${e.identifier("id")}, ${e.identifier("op")}, ${e.identifier("doc")}) VALUES (${r}, ${d}, ${i}, ${f}, ${u===void 0?null:ci(u)})`)},yi=async(o,r,d)=>{const i=r.sinceSeq??0,f=Math.max(1,Math.min(r.limit??1e3,1e4)),u=await mt(o,d);if(u!==void 0&&Ht(u,i))throw Gt(u,i,"global");const T=(await I(o,d,e`SELECT seq, ts, ${e.identifier("table")}, id, op, doc FROM ${e.identifier(G)} WHERE seq > ${i} ORDER BY seq ASC LIMIT ${e.raw(String(f))}`)).map(R=>{const{doc:m}=R,g={id:String(R.id),op:String(R.op),seq:Number(R.seq),table:String(R.table),ts:Number(R.ts)};return typeof m=="string"?{...g,doc:Et(JSON.parse(m))}:g});return{changes:T,cursor:T.at(-1)?.seq??i}},li=async(o,r,d,i={})=>{if(i.cursorOnly){const R=await I(o,d,e`SELECT MAX(seq) AS seq FROM ${e.identifier(G)}`),m=Number(R[0]?.seq??r);return{cursor:Number.isFinite(m)?m:r,tables:[]}}const f=await I(o,d,e`SELECT ${e.identifier("table")} AS ${e.identifier("table")}, MAX(seq) AS seq FROM ${e.identifier(G)} WHERE seq > ${r} GROUP BY ${e.identifier("table")}`);let u=r;const a=[];for(const R of f){const m=Number(R.seq);Number.isFinite(m)&&m>u&&(u=m),a.push(String(R.table))}const T=i.retained===!0?await mt(o,d):void 0;return{cursor:u,tables:a,...T===void 0?{}:{floor:T}}},pi=o=>{const{crossShardCounter:r,crossShardReader:d,exec:i,maxRelationKeys:f,schema:u}=o,{dialect:a}=o,{isUniqueViolation:T}=a,R={fieldRef:A,serialize:H,...a.name==="mysql"?{containsExpr:(t,n)=>e`LOCATE(${n}, ${t}) > 0`}:{},...a.name==="postgres"?{containsExpr:(t,n)=>e`strpos(${t}, ${n}) > 0`}:{},...a.name==="sqlite"?{}:{inList:jt}},m=(t,n)=>je(a.name,t,n),g=t=>{const n=te(t.columns),s=re(t.values),c=w=>a.name==="mysql"?e`VALUES(${e.identifier(w)})`:e`excluded.${e.identifier(w)}`,l=w=>a.name==="postgres"?e`${e.identifier(t.table)}.${e.identifier(w)}`:e`${e.identifier(w)}`,_=e.join(Object.entries(t.set(c,l)).map(([w,y])=>e`${e.identifier(w)} = ${y}`),e`, `),E=a.name==="mysql"?e`ON DUPLICATE KEY UPDATE ${_}`:e`ON CONFLICT(${e.identifier(t.conflictKey)}) DO UPDATE SET ${_}`;return e`INSERT INTO ${e.identifier(t.table)} (${n}) VALUES (${s}) ${E}`},C=o.clock??(()=>Date.now()),D=o.idGenerator??(()=>crypto.randomUUID()),W=o.cdc??!1,V=typeof o.cdcRetentionMs=="number"&&Number.isFinite(o.cdcRetentionMs)&&o.cdcRetentionMs>0?o.cdcRetentionMs:void 0,Y=o.auth??{identity:null,userId:null},X=async(t,n,s,c)=>{if(!W||(await di(i,C(),t,n,s,c,a),V===void 0))return;const l=C();if(!(l-ht<oi)){ht=l;try{await ai(i,a,V,l)}catch{}}},St=o.scheduler??Kt,ke=Cn();let Re=0,Me;const U=async()=>(Me??=(async()=>{await zn(i,u,a),await Jn(i,u,a),await ti(i,u,a),await yt(i,a),await Dt(i,u,a),W&&await ri(i,a)})().catch(t=>{throw Me=void 0,t}),Me),ae=async(t,n)=>{await U();const s=await Ln(i,a,u,t,ke);if(!(n!==void 0&&s!==n))return s},ce=new Map,He=async(t,n)=>{const s=z(t,n);return(await I(i,a,a.tableExists(s))).length>0},Te=async(t,n)=>{const s=`${t}::${n.name}`,c=ce.get(s);if(c!==void 0)return c;if(!await He(t,n.name))return ce.set(s,!1),!1;const _=u.tables[t];if(!_)return ce.set(s,!1),!1;const E=n.by??[],w=new Map;await ut(i,a,_,t,h=>{if(n.where&&!Be(h,n.where))return;const p=Q(E,h);fn(w,p,n,h)});const y=z(t,n.name);await L(i,a,e`DELETE FROM ${e.identifier(y)}`);const $=[];for(const[h,p]of w)$.push(e`INSERT INTO ${e.identifier(y)} (${e.identifier("__key__")}, ${e.identifier("__value__")}, ${e.identifier("__count__")}) VALUES (${h}, ${p.value}, ${p.count})`);return await Ue(i,a,$),ce.set(s,!0),!0},gt=async(t,n,s)=>{const c=$e(n.op),l=n.field??"",_=[];for(const y of n.by??[]){const $=H(s[y]??null);_.push($===null?e`${A(y)} IS NULL`:e`${A(y)} = ${$}`)}for(const[y,$]of Object.entries(n.where??{})){const h=$!==null&&typeof $=="object"&&!Array.isArray($)?$.eq:$,p=H(h);_.push(p===null?e`${A(y)} IS NULL`:e`${A(y)} = ${p}`)}const E=e`SELECT ${e.raw(c)}(${A(l)}) AS value FROM ${e.identifier(t)}`,w=await I(i,a,_.length>0?e`${E} WHERE ${e.join(_,e` AND `)}`:E);return oe(w[0]?.value)},vt=async(t,n)=>{await L(i,a,e`DELETE FROM ${e.identifier(t)} WHERE ${e.identifier("__key__")} = ${n} AND ${e.identifier("__count__")} <= 0`)},bt=async(t,n,s,c)=>{const l=z(t,n.name),{op:_}=n,E=n.field??"",w=s&&(!n.where||Be(s,n.where))?s:void 0,y=c&&(!n.where||Be(c,n.where))?c:void 0;if(!(!w&&!y)){if(_==="count"||_==="sum"||_==="avg"){const $=new Set;for(const[h,p]of[[w,-1],[y,1]]){if(!h)continue;const v=_==="count"?1:Fe(h[E]);if(v===void 0)continue;const S=Q(n.by??[],h);$.add(S),await L(i,a,g({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(N,k)=>({__count__:e`${k("__count__")} + ${N("__count__")}`,__value__:_==="count"?e`${k("__value__")} + ${N("__value__")}`:e`COALESCE(${k("__value__")}, 0) + ${N("__value__")}`}),table:l,values:[S,p*v,p]}))}for(const h of $)await vt(l,h);return}if(w){const $=Q(n.by??[],w),h=Fe(w[E]),v=(await I(i,a,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(l)} WHERE ${e.identifier("__key__")} = ${$}`))[0],S=oe(v?.value),N=(v?.count??0)-1;if(N<=0)await L(i,a,e`DELETE FROM ${e.identifier(l)} WHERE ${e.identifier("__key__")} = ${$}`);else if(v&&h!==void 0&&S!==null&&h===S){const k=await gt(t,n,w);await L(i,a,e`UPDATE ${e.identifier(l)} SET ${e.identifier("__value__")} = ${k}, ${e.identifier("__count__")} = ${N} WHERE ${e.identifier("__key__")} = ${$}`)}else await L(i,a,e`UPDATE ${e.identifier(l)} SET ${e.identifier("__count__")} = ${e.identifier("__count__")} - 1 WHERE ${e.identifier("__key__")} = ${$}`)}if(y){const $=Q(n.by??[],y),h=Fe(y[E]);if(h===void 0)await L(i,a,g({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(p,v)=>({__count__:e`${v("__count__")} + 1`}),table:l,values:[$,null,1]}));else{const p=_==="min"?"MIN":"MAX";await L(i,a,g({columns:["__key__","__value__","__count__"],conflictKey:"__key__",set:(v,S)=>({__count__:e`${S("__count__")} + 1`,__value__:e`${e.raw(p)}(COALESCE(${S("__value__")}, ${v("__value__")}), ${v("__value__")})`}),table:l,values:[$,h,1]}))}}}},me=async t=>{const n=u.tables[t]?.aggregateIndexes;if(!(!n||n.length===0))for(const s of n)await Te(t,s)},de=async(t,n,s)=>{const c=u.tables[t]?.aggregateIndexes;if(!(!c||c.length===0))for(const l of c){const _=`${t}::${l.name}`;(ce.get(_)??await He(t,l.name))&&await bt(t,l,n,s)}},le=new Map,Ge=async(t,n)=>{const s=ne(t,n);return(await I(i,a,a.tableExists(s))).length>0},De=async(t,n)=>{const s=`${t}::rank::${n.name}`,c=le.get(s);if(c!==void 0)return c;if(!await Ge(t,n.name))return le.set(s,!1),!1;const _=u.tables[t];if(!_)return le.set(s,!1),!1;const E=ne(t,n.name);await L(i,a,e`DELETE FROM ${e.identifier(E)}`);const w=n.sortBy.map((p,v)=>J(v)),y=te(["__id__","__partition__",...w]),$=[];await ut(i,a,_,t,p=>{if(n.where&&!lt(p,n.where))return;const v=Le(n.partitionBy??[],p),S=n.sortBy.map(N=>H(p[N.field]??null));$.push([p._id,v,...S])});const h=$.map(p=>e`INSERT INTO ${e.identifier(E)} (${y}) VALUES (${re(p)})`);return await Ue(i,a,h),le.set(s,!0),!0},Se=async t=>{const n=u.tables[t]?.rankIndexes;if(!(!n||n.length===0))for(const s of n)await De(t,s)},Z=async(t,n,s,c)=>{const l=u.tables[t],_=l?.rankIndexes;if(!_||_.length===0)return;const E=l?.softDeleteMode?.field,w=E===void 0||c===void 0?void 0:c[E],y=w!=null;for(const $ of _){if(s!==void 0&&c!==void 0&&kn($,s,c))continue;const h=`${t}::rank::${$.name}`;if(!(le.get(h)??await Ge(t,$.name)))continue;const S=ne(t,$.name);if(s&&await L(i,a,e`DELETE FROM ${e.identifier(S)} WHERE ${e.identifier("__id__")} = ${n}`),c&&!y){if($.where&&!lt(c,$.where))continue;const N=$.sortBy.map((q,K)=>J(K)),k=te(["__id__","__partition__",...N]),F=Le($.partitionBy??[],c),M=$.sortBy.map(q=>H(c[q.field]??null));await L(i,a,e`INSERT INTO ${e.identifier(S)} (${k}) VALUES (${re([n,F,...M])})`)}}},ue=Mt({dialect:a,exec:i,schema:u}),Ve=new Set;for(const[t,n]of Object.entries(u.tables))for(const s of Object.values(n.triggerMap??{}))Ve.add(`${t} ${s.timing} ${s.op}`);const P=(t,n,s)=>Ve.has(`${t} ${n} ${s}`);let Ye;const j=async(t,n,s)=>{if(Re+=1,Re>wt)throw Re-=1,new Ee(`trigger recursion exceeded ${String(wt)} levels on "${s.table}" — check for a self-triggering write`,"trigger");try{await an({ctx:Ye,event:s,op:n,schema:u,tableName:s.table,timing:t})}finally{Re-=1}},It=async(t,n)=>{try{await L(i,a,n)}catch(s){throw T(s)?new Ee(`unique constraint violation on "${t}"`,"unique"):s}},ge=async(t,n)=>(await I(i,a,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} = ${n}`))[0],ve=async(t,n,s,c)=>{if(c===void 0)return;const l=e.join(Object.keys(c).map(w=>m(e`${e.identifier(w)}`,c[w])),e` AND `),_=n==="UPDATE"?e`UPDATE ${e.identifier(t)} SET ${s} WHERE ${l}`:e`DELETE FROM ${e.identifier(t)} WHERE ${l}`,E=()=>{throw new Ee(`optimistic concurrency conflict on "${t}" — the row changed during this mutation; refetch and retry`,"occ")};try{if(a.supportsReturning)(await I(i,a,e`${_} RETURNING ${e.identifier("id")}`)).length===0&&E();else{const w=await L(i,a,_);(a.affectedRows?a.affectedRows(w??{rowsAffected:0}):0)===0&&E()}}catch(w){throw T(w)?new Ee(`unique constraint violation on "${t}"`,"unique"):w}},At=(t,n,s,c)=>{const l=Object.keys(t.shape);return{columns:["id","_creationTime",...l],values:[n,s,...l.map(_=>H(c[_]??null))]}},Ct=async(t,n,s,c)=>{const l=dn(n,s.op,s.field,c.by,c.where);if(!l||!await Te(t,l.index))return;const E=z(t,l.index.name),w=Object.keys(l.partial);if(w.length===(l.index.by??[]).length&&w.length>0){const $=Q(l.index.by??[],l.partial),h=await I(i,a,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(E)} WHERE ${e.identifier("__key__")} = ${$}`);if(h.length===0)return[];const p=h[0];return[{key:{...l.partial},value:Oe(s.op,{count:p.count,value:oe(p.value)})}]}return w.length>0?void 0:(await I(i,a,e`SELECT ${e.identifier("__key__")} AS key, ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(E)}`)).map($=>{const h=$;return{key:Et(JSON.parse(h.key)),value:Oe(s.op,{count:h.count,value:oe(h.value)})}})},Xe=t=>{const n=u.tables[t]?.shardMode?.kind;return n==="shardBy"||n==="root"},Qe=t=>{throw new b("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`)},Lt=(t,n)=>{if(n?.relationMask!==void 0&&n.with!==void 0&&Object.keys(n.with).length>0)throw new b("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 s={};if(n?.relationBaseWhere)for(const c of Object.keys(u.tables)){const l=n.relationBaseWhere(c);l!==void 0&&(s[c]=l)}return{orderBy:n?.orderBy,relationPolicies:s,where:B(n?.baseWhere,n?.where),with:n?.with}},ze=(t,n)=>Xe(t)?d?d(t,Lt(t,n)):Qe(t):x.findMany(t,n),be=(t,n,s)=>st(t,{fetcher:ze,maxRelationKeys:f,relationBaseWhere:s,schema:u,tableName:n}),Nt=Sn(async(t,n)=>{const s=await I(i,a,e`SELECT * FROM ${e.identifier(t)} WHERE ${e.identifier("id")} IN (${re(n)})`),c=new Map;for(const l of s){const{id:_}=l;typeof _=="string"&&c.set(_,l)}return c}),x={async cdcChangedTables(t,n){if(W)try{return await U(),await li(i,t,a,{...n,retained:V!==void 0})}catch{return}},async aggregate(t,n){const s=u.tables[t];if(!s)throw new b("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 b("INTERNAL",`aggregate(${t}, { op: "${n.op}" }): "field" is required for non-count reducers`);const c=_e(s.softDeleteMode,void 0),l=B(B(n.baseWhere,n.where),c),_=await be(l,t,n.relationBaseWhere),E=_!==l;if(s.aggregateIndexes&&!n.baseWhere&&!E&&!c){const v=sn(s.aggregateIndexes,n.op,n.field,n.where);if(v&&await Te(t,v.index)){const N=Q(v.index.by??[],v.key),k=z(t,v.index.name),M=(await I(i,a,e`SELECT ${e.identifier("__value__")} AS value, ${e.identifier("__count__")} AS count FROM ${e.identifier(k)} WHERE ${e.identifier("__key__")} = ${N}`))[0];return Oe(n.op,M===void 0?void 0:{count:M.count,value:oe(M.value)})}}xe(s,n.field,`aggregate(${t}, { op: "${n.op}", field: "${n.field}" })`);const w=he(_,R),y=e.raw($e(n.op)),$=e`SELECT ${y}(${A(n.field)}) AS value FROM ${e.identifier(t)}`,p=(await I(i,a,w?e`${$} WHERE ${w}`:$))[0]?.value;return p==null?null:Number(p)},async count(t,n){const s=u.tables[t];if(!s)throw new b("INTERNAL",`unknown table: ${t}`);await U();const c=on(n);if(c.restrictsCounts)throw new rt(t);const l=_e(s.softDeleteMode,void 0),_=B(B(c.baseWhere,c.where),l),E=await be(_,t,c.relationBaseWhere),w=E!==_;if(s.aggregateIndexes&&!c.baseWhere&&!w&&!l){const p=rn(s.aggregateIndexes,c.where);if(p&&await Te(t,p.index)){const S=Q(p.index.by??[],p.key),N=z(t,p.index.name),k=await I(i,a,e`SELECT ${e.identifier("__value__")} AS value FROM ${e.identifier(N)} WHERE ${e.identifier("__key__")} = ${S}`);return Number(k[0]?.value??0)}}const y=he(E,R),$=e`SELECT COUNT(*) AS count FROM ${e.identifier(t)}`,h=await I(i,a,y?e`${$} WHERE ${y}`:$);return Number(h[0]?.count??0)},async delete(t,n,s){const c=await ae(t,n);if(!c)return;const l=u.tables[c];if(!l)return;const _=await ge(c,t),E=ie(l,_),w=s?.hard===!0,y=!w&&l.softDeleteMode?l.softDeleteMode.field:void 0;if(!(y&&(!E||E[y]!==null&&E[y]!==void 0))){if(P(c,"before","delete")&&await j("before","delete",{id:t,op:"delete",previous:E??void 0,table:c}),await nn({deletedId:t,deletedReference:$=>E?.[$],findHolders:async($,h,p)=>{if(u.tables[$]?.shardMode?.kind==="shardBy")throw new b("INTERNAL",`cross-backend cascade from global '${c}' into shardBy '${$}' is not supported — would require Query Coordinator fan-out across shards`);return(await x.findMany($,{includeDeleted:w,where:{[h]:p}})).page},onCascade:($,h)=>x.delete(h,void 0,s),onRestrict:$=>{throw new Ee($,"restrict")},onSetNull:($,h,p)=>x.patch(h,{[p]:null}),schema:u,tableName:c}),await me(c),await Se(c),y&&E){const $={...E,[y]:C()},h=e.join(Object.keys(l.shape).map(p=>e`${e.identifier(p)} = ${H($[p]??null)}`),e`, `);await ve(c,"UPDATE",h,_),await de(c,E,$),await Z(c,t,E,void 0),await ue(c,t,$,E),await X(c,t,"update",$),P(c,"after","delete")&&await j("after","delete",{id:t,op:"delete",previous:E,table:c});return}await ve(c,"DELETE",void 0,_),ke.delete(t),await de(c,E??void 0,void 0),await Z(c,t,E??void 0,void 0),await ue(c,t,void 0),await X(c,t,"delete"),P(c,"after","delete")&&await j("after","delete",{id:t,op:"delete",previous:E??void 0,table:c})}},async findFirst(t,n={}){return(await x.findMany(t,{...n,limit:1})).page[0]??null},async findFirstOrThrow(t,n={}){const s=await x.findFirst(t,n);if(s===null)throw new tn(`findFirstOrThrow: no "${t}" document matched`);return s},async findMany(t,n={}){const s=u.tables[t];if(!s)throw new b("INTERNAL",`unknown table: ${t}`);await U();const c=zt(n.orderBy,s.shape),l=n.cursor?Jt(c,Zt(n.cursor)):void 0,_=ze,E=async(M,q,K,Ie)=>{if(Xe(M))return r?un(r,M,q,K,Ie):Qe(M);const Ae=u.tables[M];if(!Ae)throw new b("INTERNAL",`unknown table: ${M}`);const Ce=_e(Ae.softDeleteMode,void 0),ee={[q]:{in:K}},O=B(B(ee,Ie),Ce),fe=await be(O,M,void 0),Je=he(fe,R),Ze=A(q);let we=e`SELECT ${Ze} AS __fk__, COUNT(*) AS count FROM ${e.identifier(M)}`;Je&&(we=e`${we} WHERE ${Je}`),we=e`${we} GROUP BY ${Ze}`;const kt=await I(i,a,we),et=new Map;for(const tt of kt)et.set(tt.__fk__,Number(tt.count??0));return et};let w=B(n.baseWhere,n.where);w=B(w,_e(s.softDeleteMode,n.includeDeleted)),w=await st(w,{fetcher:_,maxRelationKeys:f,relationBaseWhere:n.relationBaseWhere,schema:u,tableName:t}),l&&(w=w?{AND:[w,l]}:l);const y=he(w,R),$=bn(c,a);let h=e`SELECT * FROM ${e.identifier(t)}`;y&&(h=e`${h} WHERE ${y}`),h=e`${h} ORDER BY ${$}`;const p=typeof n.limit=="number"?Math.max(0,Math.floor(n.limit)):void 0;p!==void 0&&(h=e`${h} LIMIT ${e.raw(String(p+1))}`);const v=await I(i,a,h),S=Tn(s,v);if(p===void 0)return n.with&&await at({fetcher:_,groupedCounter:E,parents:S,...ct(n),schema:u,tableName:t,with:n.with}),{continueCursor:null,isDone:!0,page:dt(S,n.select,n.with)};const N=S.length>p,k=N?S.slice(0,p):S,F=k.at(-1);return n.with&&await at({fetcher:_,groupedCounter:E,parents:k,...ct(n),schema:u,tableName:t,with:n.with}),{continueCursor:N&&F?en(F,c):null,isDone:!N,page:dt(k,n.select,n.with)}},async get(t,n){const s=await ae(t,n);if(!s)return null;const c=u.tables[s];return c?ie(c,await Nt.load(s,t)):null},async groupBy(t,n){const s=u.tables[t];if(!s)throw new b("INTERNAL",`unknown table: ${t}`);await U();const c=n.agg??{op:"count"};if($e(c.op),c.op!=="count"&&!c.field)throw new b("INTERNAL",`groupBy(${t}, { agg: { op: "${c.op}" } }): "field" is required for non-count reducers`);const l=_e(s.softDeleteMode,void 0),_=B(B(n.baseWhere,n.where),l),E=await be(_,t,n.relationBaseWhere),w=E!==_;if(s.aggregateIndexes&&!n.baseWhere&&!w&&!l){const S=await Ct(t,s.aggregateIndexes,c,n);if(S!==void 0)return S}Pn(s,t,n.by,c);const y=he(E,R),$=n.by.map(S=>e`${A(S)} AS ${e.identifier(S)}`);if(c.op==="count")$.push(e`COUNT(*) AS value`);else{if(!c.field)throw new b("INTERNAL",`groupBy(${t}, { agg: { op: "${c.op}" } }): "field" is required for non-count reducers`);$.push(e`${e.raw($e(c.op))}(${A(c.field)}) AS value`)}const h=e.join(n.by.map(S=>A(S)),e`, `);let p=e`SELECT ${e.join($,e`, `)} FROM ${e.identifier(t)}`;y&&(p=e`${p} WHERE ${y}`),p=e`${p} GROUP BY ${h}`;const v=await I(i,a,p);return Nn(n.by,v)},async insert(t,n,s){const c=u.tables[t];if(!c)throw new b("INTERNAL",`unknown table: ${t}`);await U();const l=In(c,n,Y);qe(c,l);let _,E=!0;s?.clientId!==void 0?(Qt(s.clientId),_=s.clientId):s?.allowExplicitId&&typeof l._id=="string"?_=l._id:(_=D(),E=!1);const w=s?.allowExplicitId&&typeof l._creationTime=="number"?l._creationTime:C(),y={...l,_creationTime:w,_id:_};P(t,"before","insert")&&await j("before","insert",{doc:{...y},id:_,op:"insert",table:t}),await me(t),await Se(t);const{columns:$,values:h}=At(c,_,w,l);return await It(t,e`INSERT INTO ${e.identifier(t)} (${te($)}) VALUES (${re(h)})`),E&&ke.set(_,t),await de(t,void 0,y),await Z(t,_,void 0,y),await ue(t,_,y),await X(t,_,"insert",y),P(t,"after","insert")&&await j("after","insert",{doc:y,id:_,op:"insert",table:t}),_},normalizeId(t,n){return Xt(u,t,n)},async patch(t,n,s){nt("patch",n);const c=await ae(t,s);if(!c)throw new b("INTERNAL",`document not found: ${t}`);const l=u.tables[c];if(!l)throw new b("INTERNAL",`document not found: ${t}`);const _=await ge(c,t),E=ie(l,_);if(!E)throw new b("INTERNAL",`document not found: ${t}`);const w={...E,...n,_id:t};$t(l,n,w,Y),qe(l,w,!0),P(c,"before","update")&&await j("before","update",{doc:{...w},id:t,op:"update",previous:E,table:c}),await me(c),await Se(c);const y=Object.keys(l.shape),$=e.join(y.map(h=>e`${e.identifier(h)} = ${H(w[h]??null)}`),e`, `);await ve(c,"UPDATE",$,_),await de(c,E,w),await Z(c,t,E,w),await ue(c,t,w,E),await X(c,t,"update",w),P(c,"after","update")&&await j("after","update",{doc:w,id:t,op:"update",previous:E,table:c})},async restore(t,n){const s=await ae(t,n);if(!s)throw new b("INTERNAL",`document not found: ${t}`);const c=u.tables[s],l=c?.softDeleteMode?.field;if(!c||!l)throw new b("INTERNAL",`ctx.db.restore: table "${s}" is not a .softDelete() table`);const _=await ge(s,t),E=_?.[l]!==null&&_?.[l]!==void 0;if(await x.patch(t,{[l]:null},n),E){const w=ie(c,_);w!==null&&await Z(s,t,void 0,{...w,[l]:null})}},query(t){const n=u.tables[t];if(!n)throw new b("INTERNAL",`unknown table: ${t}`);const s="the legacy query()/withIndex() reader is not available on the D1 (global) backend; use findMany",c=[],l=w=>c.every(y=>y(w)),_=async(w,y)=>{await U();const $=c.length>0,h=await Wt(i,a,n,t,w,Ut($?void 0:y));if(!$)return y===void 0&&xt(h),h;const p=h.filter(v=>l(v));return y===void 0?p:p.slice(0,y)},E=w=>{const y={async*[Symbol.asyncIterator](){if(!w)throw new b("INTERNAL",s);yield*await _(w,void 0)},async collect(){if(!w)throw new b("INTERNAL",s);return _(w,void 0)},async collectWithScores(){throw new b("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($){return c.push($),y},async first(){if(!w)throw new b("INTERNAL",s);return(await _(w,1))[0]??null},order(){return y},async paginate($){if(!w)throw new b("INTERNAL",s);const h=Bt($);return Ft(await _(w,Pt(h)),h)},async take($){if(!w)throw new b("INTERNAL",s);return _(w,$)},async unique(){if(!w)throw new b("INTERNAL",s);const $=await _(w,2);if($.length>1)throw new hn(`unique() on table "${t}" matched ${String($.length)} documents; expected at most one`);return $[0]??null},withGeoIndex(){throw new b("INTERNAL",`geo indexes are not supported on \`.global()\` tables (table "${t}") — geospatial queries run only on sharded tables`)},withIndex(){throw new b("INTERNAL",s)},withSearchIndex($,h){const p=(n.searchIndexes??[]).find(S=>S.name===$);if(!p)throw new b("INTERNAL",`unknown search index "${$}" on table "${t}"`);const v={definition:p,field:p.field,filters:[],hasQuery:!1,indexName:$,query:""};if(h(qt(v,t,Ot(p.language))),!v.hasQuery)throw new b("INTERNAL",`search index "${$}" on table "${t}" requires a .search(field, query) call`);return E(v)}};return y};return E(void 0)},async rank(t,n,s){const c=u.tables[t];if(!c)throw new b("INTERNAL",`unknown table: ${t}`);const l=c.rankIndexes?.find(q=>q.name===n);if(!l)throw new b("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(s.restrictsCounts)throw new rt(t);if(await U(),!await De(t,l))return null;const E=typeof s.row=="string"?s.row:s.row._id;if(!E)return null;const w=ne(t,l.name),y=l.sortBy.map((q,K)=>J(K)),$=te(["__partition__",...y]),p=(await I(i,a,e`SELECT ${$} FROM ${e.identifier(w)} WHERE ${e.identifier("__id__")} = ${E}`))[0];if(!p)return null;const v=p.__partition__,S=B(s.baseWhere,s.where);it(S,u,t,"rank");const N=ot(l,S);if(N&&Le(l.partitionBy??[],N)!==v)return null;const k=Mn(a.name,l,y,p,E),F=await I(i,a,e`SELECT COUNT(*) AS c FROM ${e.identifier(w)} WHERE ${e.identifier("__partition__")} = ${v}${k?e` AND (${k})`:e``}`),M=await I(i,a,e`SELECT COUNT(*) AS c FROM ${e.identifier(w)} WHERE ${e.identifier("__partition__")} = ${v}`);return{position:Number(F[0]?.c??0)+1,total:Number(M[0]?.c??0)}},async rankPage(t,n,s={}){it(B(s.baseWhere,s.where),u,t,"rankPage");const c=u.tables[t];if(!c)throw new b("INTERNAL",`unknown table: ${t}`);const l=c.rankIndexes?.find(O=>O.name===n);if(!l)throw new b("INTERNAL",`unknown rankIndex "${n}" on table "${t}"`);if(await U(),!await De(t,l))return{continueCursor:null,isDone:!0,page:[]};const E=ne(t,l.name),w=l.sortBy.map((O,fe)=>J(fe)),y=Math.max(1,Math.min(1e3,Math.floor(s.take??100))),$=B(s.baseWhere,s.where),h=ot(l,$),p=qn(l,w),v=e.join(p.map(O=>e`${e.identifier(O.column)} ${e.raw(O.direction==="desc"?"DESC":"ASC")}`),e`, `),S=[];typeof s.partitionKey=="string"?S.push(e`${e.identifier("__partition__")} = ${s.partitionKey}`):h&&S.push(e`${e.identifier("__partition__")} = ${Le(l.partitionBy??[],h)}`);const N=Yt(s);if(N!==void 0){const O=Dn(a.name,p,N);O!==void 0&&S.push(O)}const k=te([ye,"__partition__",...w]);let F=e`SELECT ${k} FROM ${e.identifier(E)}`;S.length>0&&(F=e`${F} WHERE ${e.join(S,e` AND `)}`),F=e`${F} ORDER BY ${v} LIMIT ${e.raw(String(y+1))}`;const M=await I(i,a,F),q=M.length>y,K=q?M.slice(0,y):M,Ie=K.map(O=>O[ye]),Ae=await On(i,a,c,t,Ie);let Ce=null;const ee=K.at(-1);if(q&&ee!==void 0){const O=[ee.__partition__,...w.map(fe=>ee[fe]),ee[ye]];Ce=Bn(O)}return{continueCursor:Ce,isDone:!q,page:Ae}},async replace(t,n,s,c){nt("replace",n);const l=await ae(t,s);if(!l)throw new b("INTERNAL",`document not found: ${t}`);const _=u.tables[l];if(!_)throw new b("INTERNAL",`document not found: ${t}`);const E=await ge(l,t);if(E===void 0)throw new b("INTERNAL",`document not found: ${t}`);const y=Vt(u,l,"update")||(_.aggregateIndexes??[]).length>0||(_.rankIndexes??[]).length>0?ie(_,E)??void 0:void 0,$=c?.allowExplicitId&&typeof n._creationTime=="number"?n._creationTime:C(),h={...n,_creationTime:$,_id:t};$t(_,n,h,Y),qe(_,h),P(l,"before","update")&&await j("before","update",{doc:{...h},id:t,op:"update",previous:y,table:l}),await me(l),await Se(l);const p=Object.keys(_.shape),v=e.join([e`${e.identifier("_creationTime")} = ${$}`,...p.map(S=>e`${e.identifier(S)} = ${H(h[S]??null)}`)],e`, `);await ve(l,"UPDATE",v,E),await de(l,y,h),await Z(l,t,y,h),await ue(l,t,h,y),await X(l,t,"update",h),P(l,"after","update")&&await j("after","update",{doc:h,id:t,op:"update",previous:y,table:l})}};return Ye={db:x,scheduler:St},x};export{mi as backfillSqlSearchIndexes,pi as createSqlCtxDb,gi as decodeGlobalRow,li as readSqlCdcChangedTables,yi as readSqlCdcChanges,mt as readSqlCdcFloor,Jn as runSqlAggregateMigrations,ri as runSqlCdcMigration,zn as runSqlGlobalTableMigrations,ti as runSqlRankMigrations,Dt as runSqlSearchMigrations,ai as sweepSqlCdcRetention};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as $}from"@lunora/errors";import{sql as t}from"drizzle-orm";import{migrateSearchState as te,readSearchBackfillState as R,clearSearchBackfillState as ie,writeSearchBackfillState as v,readSearchIndexCoverage as oe}from"./SEARCH_STATE_TABLE-CZxjE5CH.mjs";import{unionAll as re}from"@lunora/shard-engine";import{queryRun as p,decodeRows as Q,queryAll as b,queryBatch as se,createIndexIfNotExists as F,columnRefSql as M,serializeColumnValue as ae,forEachRowPaged as G}from"./decodeGlobalRow-DtOXIcLj.mjs";const ce=["de","en","es","fr","it","nl","none","pt"],ue=e=>ce.includes(e),fe="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",de="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",le="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",me="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",$e="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",he="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",we="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ê",Se=/[\u0300-\u036F]/gu,pe=/[\u0080-\u{10FFFF}]/u,Ee=/[\p{L}\p{N}]+/gu,V=e=>pe.test(e)?e.normalize("NFD").replaceAll(Se,"").normalize("NFC").toLowerCase():e.toLowerCase(),g=e=>new Set(V(e).split(" ")),ge={de:g(de),en:g(fe),es:g(le),fr:g(me),it:g($e),nl:g(he),none:new Set,pt:g(we)},_e=2,ye=256,j=new Map,y=e=>{const n=e!==void 0&&ue(e)?e:"none",i=j.get(n);if(i)return i;const o=ge[n],r=a=>{const c=(V(a).match(Ee)??[]).filter(u=>u.length<=ye);return o.size===0?c:c.filter(u=>!o.has(u))},s={document:r,profile:`${n}-v${String(_e)}`,query:a=>{const c=r(a);return c.filter((u,f)=>c.lastIndexOf(u)===f)}};return j.set(n,s),s},Te=e=>`${y(e.language).profile}:${e.field}`,X=(e,n)=>e.profile!==n?{cursor:void 0,finished:!1,wipe:e.cursor!==void 0||e.done}:{cursor:e.cursor,finished:e.done,wipe:!1},Ie=e=>{const n=atob(e),i=Uint8Array.from(n,o=>o.codePointAt(0)??0);return new TextDecoder().decode(i)},Ne=()=>new $("BAD_REQUEST","invalid cursor"),k=16,H=8,w=1024,A=(e,n)=>n.query(e),ve=(e,n)=>{if(!n)return{exact:!0,lower:e,upper:e};const i=[...e].at(-1)??"",o=(i.codePointAt(0)??0)+1;if(o>=55296&&o<=57343||o>1114111)return{exact:!0,lower:e,upper:e};const r=e.slice(0,e.length-i.length);return{exact:!1,lower:e,upper:r+String.fromCodePoint(o)}},Je=(e,n,i)=>{const o={eq:(r,s)=>{if(!e.definition.filterFields?.includes(r))throw new $("INTERNAL",`field "${r}" is not a filter field of search index "${e.indexName}" on table "${n}"`);if(e.filters.length>=H)throw new $("BAD_REQUEST",`search index "${e.indexName}" on table "${n}": at most ${String(H)} .eq() filters are supported per search query`);return e.filters.push({field:r,value:s}),o},search:(r,s)=>{const a=e;if(r!==a.definition.field)throw new $("INTERNAL",`search index "${a.indexName}" on table "${n}" indexes "${a.definition.field}", not "${r}"`);const c=A(s,i).length;if(c>k)throw new $("BAD_REQUEST",`search index "${a.indexName}" on table "${n}": at most ${String(k)} search terms are supported (got ${String(c)})`);return a.field=r,a.query=s,a.hasQuery=!0,o}};return o},Ye=e=>{if(e.length>w)throw new $("BAD_REQUEST",`more than ${String(w)} documents match this search — narrow it with filters or read it a page at a time with .paginate()`)},Ke=e=>Math.min(e.offset+e.numItems+1,w),Re=e=>btoa(`search:${String(e)}`),be=e=>{let n;try{n=Ie(e)}catch{return}if(!n.startsWith("search:"))return;const i=Number(n.slice(7));return Number.isInteger(i)&&i>=0?i:void 0},Ze=e=>{if(typeof e.endCursor=="string")throw new $("BAD_REQUEST","bounded (endCursor) pagination is not supported on search queries — relevance order has no stable range boundary");if(!Number.isFinite(e.numItems))throw new $("BAD_REQUEST",`search pagination needs a finite numItems, got ${String(e.numItems)}`);const n=Math.max(0,Math.floor(e.numItems)),i=e.cursor?be(e.cursor):0;if(i===void 0)throw Ne();if(i+n>=w)throw new $("BAD_REQUEST",`search pagination reaches the ${String(w)}-document limit (offset ${String(i)} + ${String(n)} requested) — a page must end below the cap so the probe row that answers \`hasMore\` still fits: retry with numItems ${String(Math.max(1,w-i-1))} or fewer, or narrow the query or the filters instead`);return{numItems:n,offset:i}},en=(e,n)=>{const i=n.offset+n.numItems,o=n.numItems>0&&e.length>i;return{continueCursor:o?Re(i):null,isDone:!o,page:e.slice(n.offset,i)}},nn=e=>{if(e===void 0)return w+1;if(!Number.isFinite(e))return w;const n=Math.max(0,Math.floor(e));if(n>w)throw new $("BAD_REQUEST",`search returns at most ${String(w)} documents (asked for ${String(n)}) — narrow the query or paginate instead`);return n},Ae=(e,n)=>{if(!n.includes("."))return e[n];let i=e;for(const o of n.split(".")){if(i===null||typeof i!="object"||Array.isArray(i))return;i=i[o]}return i},C=(e,n)=>`${e}__fts_${n}`,Ce="__text__",l="__id__",T="__token__",q="__n__",De=1e3,J=(e,n)=>n.document(e),x=(e,n)=>Ae(e,n),Le=e=>typeof e=="string"?e:e==null?"":typeof e=="number"||typeof e=="bigint"||typeof e=="boolean"?String(e):JSON.stringify(e)??"",Oe=(e,n,i)=>e!==void 0&&n!==void 0&&x(e,i.field)===x(n,i.field),qe=(e,n)=>J(Le(x(e,n.field)),y(n.language)).slice(0,De),U=(e,n)=>qe(e,n).join(" "),xe=(e,n)=>{const i=new Map;for(const o of J(e,n))i.set(o,(i.get(o)??0)+1);return i},D=async(e,n,i,o)=>{await p(e,n,t`DELETE FROM ${t.identifier(i)} WHERE ${t.identifier(l)} = ${o}`)},O=(e,n)=>e.name==="mysql"?t`${t.identifier(n)}(191)`:e.textPatternOperatorClass===void 0?t`${t.identifier(n)}`:t`${t.identifier(n)} ${t.raw(e.textPatternOperatorClass)}`,P=50,Ue=(e,n)=>n?t`${t.identifier(T)} LIKE ${`${e}%`}`:t`${t.identifier(T)} = ${e}`,Y=(e,n)=>{const i=n.filters.map(o=>t`m.${M(o.field)} = ${ae(o.value)}`);return e.softDeleteMode&&i.push(t`m.${M(e.softDeleteMode.field)} IS NULL`),i},K=async(e,n,i,o,r,s,a)=>{const c=Y(i,r);let u=t`SELECT m.* FROM (${a}) s JOIN ${t.identifier(o)} m ON m.${t.identifier("id")} = s.${t.identifier(l)}`;return c.length>0&&(u=t`${u} WHERE ${t.join(c,t` AND `)}`),u=t`${u} ORDER BY s.${t.identifier("__score__")} DESC, m.${t.identifier("_creationTime")} DESC, m.${t.identifier("id")} ASC LIMIT ${t.raw(String(s))}`,Q(i,await b(e,n,u))},Be=async(e,n,i,o,r,s)=>{const a=A(r.query,y(r.definition.language));if(a.length===0)return[];const c=C(o,r.indexName),u=a.length-1,f=a.map((d,_)=>Ue(d,_===u)),m=t.join(f,t` OR `),h=f.map(d=>t`SUM(CASE WHEN ${d} THEN ${t.identifier(q)} ELSE 0 END)`),E=t.join(h.map(d=>t`${d} > 0`),t` AND `),S=t`SELECT ${t.identifier(l)}, ${t.join(h,t` + `)} AS ${t.identifier("__score__")} FROM ${t.identifier(c)} WHERE ${m} GROUP BY ${t.identifier(l)} HAVING ${E}`;return K(e,n,i,o,r,s,S)},Fe=async(e,n,i,o,r,s)=>{const a=A(r.query,y(r.definition.language));if(a.length===0)return[];const c=C(o,r.indexName),u=`${c}__vocab`,f=a.length-1,m=a.map((S,d)=>{const _=ve(S,d===f),ne=_.exact?t`${t.identifier("term")} = ${_.lower}`:t`${t.identifier("term")} >= ${_.lower} AND ${t.identifier("term")} < ${_.upper}`;return t`SELECT ${t.identifier("doc")}, ${t.raw(String(d))} AS ${t.identifier("__term__")}, COUNT(*) AS ${t.identifier("__n__")} FROM ${t.identifier(u)} WHERE ${ne} GROUP BY ${t.identifier("doc")}`}),h=a.map((S,d)=>t`SUM(CASE WHEN u.${t.identifier("__term__")} = ${t.raw(String(d))} THEN u.${t.identifier("__n__")} ELSE 0 END)`),E=t`SELECT f.${t.identifier(l)} AS ${t.identifier(l)}, ${t.join(h,t` + `)} AS ${t.identifier("__score__")} FROM (${re(m)}) u JOIN ${t.identifier(c)} f ON f.rowid = u.${t.identifier("doc")} GROUP BY f.${t.identifier(l)} HAVING ${t.join(h.map(S=>t`${S} > 0`),t` AND `)}`;return K(e,n,i,o,r,s,E)},Me=async(e,n,i,o,r,s)=>{const a=n.nativeTextSearch,c=A(r.query,y(r.definition.language));if(!a||c.length===0)return[];const u=C(o,r.indexName),f=[a.matches(u,c),...Y(i,r)],m=t`SELECT m.* FROM ${t.identifier(u)} JOIN ${t.identifier(o)} m ON m.${t.identifier("id")} = ${t.identifier(u)}.${t.identifier(l)} WHERE ${t.join(f,t` AND `)} ORDER BY ${a.rank(u,c)} DESC, m.${t.identifier("_creationTime")} DESC, m.${t.identifier("id")} ASC LIMIT ${t.raw(String(s))}`;return Q(i,await b(e,n,m))},je={ensureCompanion:async(e,n,i)=>{const{integer:o,key:r}=n.companionTypes;await p(e,n,t`CREATE TABLE IF NOT EXISTS ${t.identifier(i)} (${t.identifier(T)} ${t.raw(r)} NOT NULL, ${t.identifier(l)} ${t.raw(r)} NOT NULL, ${t.identifier(q)} ${t.raw(o)} NOT NULL)`),await F(e,n,{columns:t`${O(n,T)}, ${O(n,l)}`,name:`${i}__btree`,table:i,unique:!1}),await F(e,n,{columns:O(n,l),name:`${i}__by_id`,table:i,unique:!1})},indexDocument:async(e,n,i,o,r,s)=>{await D(e,n,i,o);const a=[...xe(U(r,s),y(s.language))],c=t.join([T,l,q].map(f=>t.identifier(f)),t`, `),u=[];for(let f=0;f<a.length;f+=P){const m=t.join(a.slice(f,f+P).map(([h,E])=>t`(${h}, ${o}, ${E})`),t`, `);u.push(t`INSERT INTO ${t.identifier(i)} (${c}) VALUES ${m}`)}await se(e,n,u)},name:"inverted",runSearch:Be},ke={ensureCompanion:async(e,n,i)=>{await p(e,n,t`CREATE VIRTUAL TABLE IF NOT EXISTS ${t.identifier(i)} USING fts5(${t.identifier(Ce)}, ${t.identifier(l)} UNINDEXED)`),await p(e,n,t`CREATE VIRTUAL TABLE IF NOT EXISTS ${t.identifier(`${i}__vocab`)} USING fts5vocab(${t.identifier(i)}, ${t.raw("instance")})`)},indexDocument:async(e,n,i,o,r,s)=>{await D(e,n,i,o),await p(e,n,t`INSERT INTO ${t.identifier(i)} (${t.identifier("__text__")}, ${t.identifier(l)}) VALUES (${U(r,s)}, ${o})`)},name:"fts5",runSearch:Fe},He={ensureCompanion:async(e,n,i)=>{const o=n.nativeTextSearch;if(o){await p(e,n,o.createCompanion(i,n.companionTypes.key));for(const r of o.createIndexes(i))await p(e,n,r)}},indexDocument:async(e,n,i,o,r,s)=>{const a=n.nativeTextSearch;a&&(await D(e,n,i,o),await p(e,n,a.indexDocument(i,o,U(r,s))))},name:"native",runSearch:Me},I=(e,n)=>e.strategy==="native"&&n.nativeTextSearch!==void 0?He:n.supportsFts5?ke:je,L=(e,n)=>`${Te(e)}/${I(e,n).name}`,B=function*(e){for(const[n,i]of Object.entries(e.tables)){const o=i.searchIndexes;if(!(i.shardMode!==void 0&&i.shardMode.kind!=="global"||!o))for(const r of o)yield[n,i,r]}},N=(e,n)=>C(e,n.name),Pe=async(e,n,i,o)=>{const r=N(i,o);return X(await R(e,n,r),L(o,n)).finished?!0:oe(e,n,r)},tn=async(e,n,i,o,r,s)=>{if(!await Pe(e,n,o,r.definition))throw new $("SEARCH_INDEX_BUILDING",`search index "${r.indexName}" on table "${o}" is still backfilling and currently covers only part of the table — retry once it finishes, or run the backfillSearch admin operation to complete it now`);return I(r.definition,n).runSearch(e,n,i,o,r,s)},z=e=>e.slice(e.lastIndexOf("/")+1),W=200,Z=async(e,n,i,o,r)=>{const s=N(o,r),a=I(r,n),c=L(r,n),u=X(await R(e,n,s),c);if(u.finished)return!0;if(u.wipe&&await v(e,n,s,void 0,!1,c),(await b(e,n,n.tableExists(o))).length===0)return await v(e,n,s,void 0,!0,c),!0;let m=0,h=u.cursor;await G(e,n,i,o,async S=>{m+=1;const d=S._id;typeof d=="string"&&(h=d,await a.indexDocument(e,n,s,d,S,r))},{after:u.cursor,limit:W});const E=m<W;return await v(e,n,s,h,E,c),E},ee=async(e,n,i)=>{await te(e,i);for(const[o,,r]of B(n)){const s=N(o,r),a=L(r,i),c=await R(e,i,s);c.profile!==void 0&&z(c.profile)!==z(a)&&(await p(e,i,t`DROP TABLE IF EXISTS ${t.identifier(s)}`),await ie(e,i,s)),await I(r,i).ensureCompanion(e,i,s)}},ze=async(e,n,i,o,r)=>{const s=N(o,r);if((await R(e,n,s)).profile!==void 0)return;let c=0;(await b(e,n,n.tableExists(o))).length>0&&await G(e,n,i,o,()=>{c+=1},{limit:1}),await v(e,n,s,void 0,c===0,L(r,n))},on=async(e,n,i)=>{await ee(e,n,i);for(const[o,r,s]of B(n)){if(s.staged){await ze(e,i,r,o,s);continue}await Z(e,i,r,o,s)}},rn=async(e,n,i)=>{await ee(e,n,i);for(const[o,r,s]of B(n)){let a=!1;for(;!a;)a=await Z(e,i,r,o,s)}},sn=e=>{const{dialect:n,exec:i,schema:o}=e;return async(r,s,a,c)=>{const u=o.tables[r]?.searchIndexes;if(!(!u||u.length===0))for(const f of u){if(Oe(c,a,f))continue;const m=N(r,f);if(a){await I(f,n).indexDocument(i,n,m,s,a,f);continue}await D(i,n,m,s)}}};export{Je as A,Ze as C,en as R,nn as T,tn as a,Ke as b,sn as c,rn as d,y as q,on as r,Ye as x};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{renderSql as u}from"@lunora/shard-engine";import{sql as i}from"drizzle-orm";import{s as N,a as p,e as y}from"./value-codec-CPoo8vyF.mjs";const C=n=>n==="_id"||n==="id"?"id":n,O=n=>i`${i.identifier(C(n))}`,_=(n,e,t)=>{const{params:o,sql:r}=u(e.name,t);return n.all(r,o)},d=(n,e,t)=>{const{params:o,sql:r}=u(e.name,t);return n.run(r,o)},k=async(n,e,t)=>{if(t.length!==0){if(!n.batch){for(const o of t)await d(n,e,o);return}await n.batch(t.map(o=>u(e.name,o)))}},v=async(n,e,t)=>{const o=t.unique?i`UNIQUE `:i``;if(e.name==="mysql"){try{await d(n,e,i`CREATE ${o}INDEX ${i.identifier(t.name)} ON ${i.identifier(t.table)} (${t.columns})`)}catch(r){const s=r;if(s.errno!==1061&&s.code!=="ER_DUP_KEYNAME"&&s.code!==1061)throw r}return}await d(n,e,i`CREATE ${o}INDEX IF NOT EXISTS ${i.identifier(t.name)} ON ${i.identifier(t.table)} (${t.columns})`)},D=N,h=n=>n?._meta?.column?.notNull===!1,g=n=>{if(n.kind!=="optional"||h(n))return!1;const e=n._meta?.inner;return!h(e)},w=new WeakMap,S=n=>{let e=w.get(n);return e===void 0&&(e=Object.entries(n.shape).map(([t,o])=>[t,y(o),g(o)]),w.set(n,e)),e},T=(n,e)=>{const t={};for(const[o,r,s]of S(n)){const a=e[o];a===void 0||s&&a===null||(t[o]=p(a,r))}return t._id=e.id,t._creationTime=e._creationTime,t},R=(n,e)=>e?T(n,e):null,K=(n,e)=>{const t=[];for(const o of e){const r=R(n,o);r&&t.push(r)}return t},$=500,B=async(n,e,t,o,r,s={})=>{let a=s.after,c=s.limit,f=!0;for(;f&&(c===void 0||c>0);){const m=c===void 0?$:Math.min($,c),q=a===void 0?i``:i` WHERE ${i.identifier("id")} > ${a}`,l=await _(n,e,i`SELECT * FROM ${i.identifier(o)}${q} ORDER BY ${i.identifier("id")} ASC LIMIT ${i.raw(String(m))}`);for(const I of l){const E=R(t,I);E&&await r(E)}a=l.at(-1)?.id,f=l.length===m,c=c===void 0?void 0:c-l.length}};export{$ as BACKFILL_BATCH_SIZE,O as columnRefSql,v as createIndexIfNotExists,T as decodeGlobalRow,R as decodeRow,K as decodeRows,B as forEachRowPaged,C as physicalColumn,_ as queryAll,k as queryBatch,d as queryRun,D as serializeColumnValue};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as T}from"@lunora/errors";import{bigintSqlKey as k,BIGINT_KEY_DIGITS as _,BIGINT_KEY_NON_NEGATIVE as R,BIGINT_KEY_NEGATIVE as S}from"@lunora/shard-engine";const j=r=>{if(r.kind!=="optional")return r.kind;const t=r._meta?.inner;return t?j(t):r.kind},p=r=>{let t="";for(let o=0;o<r.length;o+=32768)t+=String.fromCharCode(...r.subarray(o,o+32768));return btoa(t)},U=r=>{const t=atob(r),i=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)i[o]=t.codePointAt(o)??0;return i},s="$lunora.wire$",d=64,I=1024,m="__proto__",l={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},O={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},N=r=>{if(r===null||typeof r!="object")return!1;const t=Object.getPrototypeOf(r);return t===null||t===Object.prototype},E=(r,t=0)=>{if(t>d)return!0;if(r===null)return!1;const i=typeof r;if(i==="string"||i==="boolean")return!1;if(i==="number")return!Number.isFinite(r);if(i!=="object")return!0;if(Array.isArray(r))return r.length>0&&r[0]===s?!0:r.some(o=>o===void 0||E(o,t+1));if(!N(r)||Object.hasOwn(r,m))return!0;for(const o of Object.keys(r)){const c=r[o];if(c!==void 0&&E(c,t+1))return!0}return!1},a=(r,t=0)=>{if(t>d)throw new RangeError(`wire-codec: value nesting exceeds the ${d}-level limit`);if(r===void 0)return[s,"undefined"];if(r===null)return null;const i=typeof r;if(i==="bigint")return[s,"bigint",r.toString()];if(i==="number"){const e=r;return Number.isNaN(e)?[s,"nan"]:e===1/0?[s,"inf"]:e===-1/0?[s,"-inf"]:e}if(i!=="object")return r;if(r instanceof Date)return[s,"date",a(r.getTime(),t+1)];if(r instanceof Error){const e=r,n={};for(const u of Object.keys(e))e[u]!==void 0&&(n[u]=a(e[u],t+1));const f=[s,"error",e.name,e.message,n];return e.cause!==void 0&&f.push(a(e.cause,t+1)),f}if(r instanceof URL)return[s,"url",r.href];if(r instanceof Map)return[s,"map",[...r.entries()].map(([e,n])=>[a(e,t+1),a(n,t+1)])];if(r instanceof Set)return[s,"set",[...r].map(e=>a(e,t+1))];if(r instanceof ArrayBuffer)return[s,"bytes",p(new Uint8Array(r)),"ArrayBuffer"];if(ArrayBuffer.isView(r)){const e=r,n=e.constructor.name,f=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return n==="Uint8Array"?[s,"bytes",p(f)]:[s,"bytes",p(f),n]}if(Array.isArray(r)){const e=r.map(n=>a(n,t+1));return e.length>0&&e[0]===s?[s,"arr",e]:e}if(!N(r)){const e=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${e} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)}const o=r,c={};for(const e of Object.keys(o)){const n=o[e];if(n===void 0)continue;const f=a(n,t+1);e===m?Object.defineProperty(c,e,{configurable:!0,enumerable:!0,value:f,writable:!0}):c[e]=f}return c},y=(r,t=0)=>{if(t>d)throw new RangeError(`wire-codec: value nesting exceeds the ${d}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){if(r[0]===s)switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(e=>y(e,t+1));case"bigint":{const e=r[2];if(typeof e!="string"||e.length>I||!/^-?\d+$/.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${I} digits)`);return BigInt(e)}case"date":{if(r.length<3)throw new TypeError("wire-codec: malformed date — missing payload");return new Date(y(r[2],t+1))}case"map":{const e=r[2];return new Map(e.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[y(n[0],t+1),y(n[1],t+1)]}))}case"set":return new Set(r[2].map(e=>y(e,t+1)));case"url":return new URL(r[2]);case"error":{const e=r[2],n=r[3],f=(Object.hasOwn(O,e)?O[e]:void 0)??Error,u=new f(n);u.name!==e&&Object.defineProperty(u,"name",{configurable:!0,value:e,writable:!0});const b=y(r[4],t+1);if(b===null||typeof b!="object"||Array.isArray(b))throw new TypeError("wire-codec: malformed error — props must be an object");for(const g of Object.keys(b))g===m?Object.defineProperty(u,g,{configurable:!0,enumerable:!0,value:b[g],writable:!0}):u[g]=b[g];return r.length>5&&Object.defineProperty(u,"cause",{configurable:!0,value:y(r[5],t+1),writable:!0}),u}case"bytes":{const e=U(r[2]),n=r[3]??"Uint8Array";if(n==="ArrayBuffer")return e.buffer.byteLength===e.byteLength?e.buffer:e.slice().buffer;const f=Object.hasOwn(l,n)?l[n]:void 0;return f?new f(e.slice().buffer):e}case"inf":return 1/0;case"nan":return Number.NaN;case"undefined":return;default:return r.map(e=>y(e,t+1))}return r.map(c=>y(c,t+1))}const i=r,o={};for(const c of Object.keys(i)){const e=y(i[c],t+1);c===m?Object.defineProperty(o,c,{configurable:!0,enumerable:!0,value:e,writable:!0}):o[c]=e}return o},A=s,h=(r,t)=>r.startsWith(A)?y(t(r.slice(A.length))):t(r),w=/^\d+$/u,G=r=>Array.from(r,t=>String(9-Number(t))).join(""),P=r=>{if(r.length!==_+1)return;const t=r.slice(0,1),i=r.slice(1);if(w.test(i))return t===R?BigInt(i):t===S?-BigInt(G(i)):void 0},L=r=>{if(typeof r=="boolean")return r?1:0;if(r===null||typeof r=="string"||typeof r=="number")return r;if(typeof r=="bigint")return k(r);if(r instanceof Uint8Array)return r;if(r instanceof ArrayBuffer)return new Uint8Array(r);try{return E(r)?A+JSON.stringify(a(r)):JSON.stringify(r)}catch(t){throw new T("BAD_REQUEST",`this value cannot be stored: ${t instanceof Error?t.message:String(t)}`)}},B=r=>{try{return JSON.parse(r)}catch{return r}},C=r=>{if(typeof r!="string")return r;const t=P(r);if(t!==void 0)return t;try{return BigInt(r)}catch{return r}},$=r=>j(r),x=(r,t)=>{if(r===null)return r;switch(t){case"any":case"from":case"union":return typeof r=="string"&&(r.startsWith("{")||r.startsWith("[")||r.startsWith(A))?h(r,B):r;case"array":case"geoPoint":case"object":case"record":return typeof r=="string"?h(r,B):r;case"bigint":return C(r);case"boolean":return r===0||r===1?r===1:r;case"bytes":return r instanceof ArrayBuffer?r:ArrayBuffer.isView(r)?new Uint8Array(r.buffer,r.byteOffset,r.byteLength).slice().buffer:r;default:return r}},W=_+1;export{W as B,x as a,a as b,C as c,y as d,$ as e,E as n,L as s,B as t};
|