Files
MetonaSqlark/dist/metona-sqlark.min.js
T
thzxx 05e6823bf1
CI / test (22.x) (push) Successful in 24m26s
CI / e2e (push) Successful in 10m0s
CI / test (18.x) (push) Successful in 27m14s
CI / test (20.x) (push) Failing after 1h19m9s
CI / test (24.x) (push) Successful in 37m49s
fix: v0.7.2 语句级原子性 + 事务 DDL 拒绝 + 约束/绑定硬化 — 6 项修复 + 43 回归 + CI 重型套件串行
- UPDATE 语句级部分提交(P1,四引擎):两阶段全量预检后执行,批内唯一互查,
  任何一行失败整句不执行(aria 场景 WAL 与内存不再错位)
- 事务内 ALTER/CREATE INDEX/DROP INDEX 残留(P1):Memory/KVStore 显式拒绝
  (对齐 Aria),createTable/dropTable 保持可回滚
- SET NULL 级联绕过 required 约束(P1):预检阶段整体拒绝 FOREIGN_KEY_VIOLATION
- bindParameters 注释误判(P2):行注释/块注释中的 ? 与引号不再参与绑定
- 未闭合字符串静默接受 → lexer 抛 PARSE_ERROR;未知 where 操作符抛 QUERY_ERROR
- UPDATE undefined 覆盖列值 → 语义化为不更新(null 仍置空)
- Hybrid 写穿透非原子(P1):磁盘失败自动重载内存对齐磁盘再抛原错误
- CI:Run tests 拆常规并行 + 重型串行(runInBand),重型测试超时余量提升,
  性能护栏 kv 120→240s / opfs 150→300s(仍拦截悬崖回归)
- 测试 1155 → 1198(74 套件),覆盖率 89.82% 保持
2026-08-13 15:31:16 +08:00

2 lines
177 KiB
JavaScript

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).MetonaSqlark={})}(this,function(e){"use strict";const t=["string","number","boolean","date","json"],s=Object.freeze({name:"metona-sqlark",mode:"hybrid",diskEngine:"opfs",version:1,maxRowsPerQuery:0,debug:!1,multiTabSync:!1,aria:void 0});class n extends Error{constructor(e,t,s){super(e),this.code=t,this.details=s,this.name="DatabaseError"}}const i="0.7.2",r=new Map;function a(e,t,s={}){for(const[n,i]of Object.entries(t))if("$caseResult"!==n){if("$exists"!==n){if("$and"===n){if(!i.every(t=>a(e,t,s)))return!1;continue}if("$or"===n){if(!i.some(t=>a(e,t,s)))return!1;continue}if("$not"!==n){if(!o(e[n],i,e,s))return!1}else if(a(e,i,s))return!1}else if(!0!==i)return!1}else if(!0!==i)return!1;return!0}function o(e,t,s,n){if("object"==typeof t&&null!==t&&"$and"in t)return t.$and.every(e=>a(s,e,n));if("object"==typeof t&&null!==t&&"$or"in t)return t.$or.some(e=>a(s,e,n));if("object"==typeof t&&null!==t&&"$not"in t)return!o(e,t.$not,s,n);if("object"!=typeof t||null===t||Array.isArray(t))return e===t;const i=t;if(n.$col&&"$col"in i&&1===Object.keys(i).length)return e===s[i.$col];for(const[t,r]of Object.entries(i)){let i=r;if(n.$col&&"object"==typeof r&&null!==r&&"$col"in r&&(i=s[r.$col]),!h(e,t,i))return!1}return!0}function h(e,t,s){switch(t){case"$eq":return e===s;case"$ne":return e!==s;case"$gt":return e>s;case"$gte":return e>=s;case"$lt":return e<s;case"$lte":return e<=s;case"$in":return Array.isArray(s)&&s.includes(e);case"$nin":return Array.isArray(s)&&!s.includes(e);case"$like":return function(e){const t=r.get(e);if(t)return t;const s=e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/%/g,".*").replace(/_/g,"."),n=new RegExp(`^${s}$`,"i");return r.set(e,n),n}(String(s)).test(String(e));default:throw new n(`Unknown where operator "${t}"`,"QUERY_ERROR")}}function c(e,t){return[...e].sort((e,s)=>{for(const{column:n,direction:i,nulls:r}of t){const t=null===e[n]||void 0===e[n],a=null===s[n]||void 0===s[n];if(r&&(t||a)){if(t&&a)continue;return"first"===r?t?-1:1:t?1:-1}const o=l(e[n],s[n]);if(0!==o)return"desc"===i?-o:o}return 0})}function l(e,t){return e===t?0:null==e?1:null==t?-1:"string"==typeof e&&"string"==typeof t?e.localeCompare(t):"number"==typeof e&&"number"==typeof t?e-t:String(e).localeCompare(String(t))}function u(e,t){const s={};for(const n of t)if(n in e)s[n]=e[n];else for(const t of Object.keys(e))if(t.endsWith(`.${n}`)||t===n){s[n]=e[t];break}return s}function f(e,s){return function(e){if(0===Object.keys(e).length)throw new n("Table must have at least one column","SCHEMA_ERROR");let s=0;for(const[i,r]of Object.entries(e)){if("__proto__"===i)throw new n('Column name "__proto__" is not allowed',"SCHEMA_ERROR");if(!t.includes(r.type))throw new n(`Invalid type "${r.type}" for column "${i}". Valid types: ${t.join(", ")}`,"SCHEMA_ERROR");r.primaryKey&&s++}if(0===s)throw new n("Table must have at least one primary key column","SCHEMA_ERROR");if(s>1)throw new n(`Composite primary keys are not supported yet: table has ${s} primary key columns. Use a single primary key column (or a unique column combination) instead.`,"SCHEMA_ERROR")}(s),{name:e,columns:s}}function d(e){const t={};for(const[s,n]of Object.entries(e))void 0!==n&&(t[s]=n);return t}function p(e){return{type:e.type,primaryKey:e.primaryKey,unique:e.unique,required:e.required,default:e.default,index:e.index,maxLength:e.maxLength,min:e.min,max:e.max,references:e.references,onDelete:e.onDelete,onUpdate:e.onUpdate}}class y{constructor(){this.name="memory",this.tables=new Map,this.schemas=new Map,this.indexes=new Map,this.opened=!1,this.metaStore=new Map,this.snapshot=null}async open(e,t){this.opened||(this.opened=!0)}async close(){this.tables.clear(),this.schemas.clear(),this.indexes.clear(),this.metaStore.clear(),this.opened=!1}isOpen(){return this.opened}async repair(){}async clearAll(){const e=Array.from(this.schemas.keys());for(const t of e)await this.dropTable(t);this.metaStore.clear()}async getMeta(e){return this.metaStore.get(e)??null}async setMeta(e,t){this.metaStore.set(e,t)}async createTable(e){if(this.schemas.has(e.name))throw new n(`Table "${e.name}" already exists`,"TABLE_EXISTS");const t={name:e.name,columns:{}};for(const[s,n]of Object.entries(e.columns))t.columns[s]={...n};this.schemas.set(e.name,t),this.tables.set(e.name,new Map);const s=new Map;for(const[e,n]of Object.entries(t.columns))(n.index||n.unique)&&s.set(e,new Map);this.indexes.set(e.name,s)}async dropTable(e){this.ensureTable(e),this.schemas.delete(e),this.tables.delete(e),this.indexes.delete(e)}async hasTable(e){return this.schemas.has(e)}async getTableNames(){return Array.from(this.schemas.keys())}async getTableSchema(e){return this.schemas.get(e)??null}async alterTable(e,t,s){if(this.snapshot)throw new n("ALTER TABLE is not supported inside a transaction (MemoryEngine DDL is not transactional)","NOT_SUPPORTED");this.ensureTable(e);const i=this.schemas.get(e);if("ADD"===t){if(i.columns[s.name])throw new n(`Column "${s.name}" already exists in table "${e}"`,"COLUMN_EXISTS");return void(i.columns[s.name]=s)}if(!i.columns[s.name])throw new n(`Column "${s.name}" does not exist in table "${e}"`,"COLUMN_NOT_FOUND");delete i.columns[s.name];const r=this.tables.get(e);for(const e of r.values())s.name in e&&delete e[s.name]}async insert(e,t){this.ensureTable(e);const s=this.schemas.get(e),i=this.tables.get(e),r=this.getPrimaryKey(s),a=[];for(const o of t){const t=this.validateRow(s,o),h=String(t[r]);if(i.has(h))throw new n(`Duplicate primary key "${h}" in table "${e}"`,"DUPLICATE_KEY");this.checkUniqueness(s,t),i.set(h,t),this.updateIndexes(e,t,h),a.push(h)}return a}async find(e,t){this.ensureTable(e);const s=this.tables.get(e);let n=this.tryIndexLookup(e,s,t);t.where&&Object.keys(t.where).length>0&&(n=n.filter(e=>a(e,t.where))),t.orderBy&&t.orderBy.length>0&&(n=c(n,t.orderBy));const i=t.offset??0,r=t.limit??n.length;return n=n.slice(i,i+r),t.columns&&t.columns.length>0&&"*"!==t.columns[0]&&(n=n.map(e=>u(e,t.columns))),n}async findStream(e,t,s){this.ensureTable(e);const n=this.tables.get(e),i=!!(t.where&&Object.keys(t.where).length>0),r=t.limit??1/0,o=t.offset??0,h=t.columns&&t.columns.length>0&&"*"!==t.columns[0]?e=>u(e,t.columns):null;let c=0,l=0;for(const e of n.values())if(!i||a(e,t.where))if(l<o)l++;else if(s(h?h(e):e),c++,c>=r)break;return c}async update(e,t,s){this.ensureTable(e);const i=this.schemas.get(e),r=this.tables.get(e),o=this.getPrimaryKey(i),h=d(s),c=[],l=new Map;for(const[s,u]of r){if(t.where&&Object.keys(t.where).length>0&&!a(u,t.where))continue;const f={...u,...h};this.validateRow(i,f),this.checkUpdateUniqueness(i,e,s,f,l);const d=String(f[o]);if(d!==s&&r.has(d))throw new n(`Duplicate primary key "${d}" in table "${e}" (cannot update key to existing value)`,"DUPLICATE_KEY");c.push({pk:s,row:u,updated:f,newPk:d})}for(const t of c)t.newPk!==t.pk&&this.checkUpdateRestrict(e,t.pk);let u=0;for(const{pk:t,row:s,updated:n,newPk:i}of c)this.removeIndexEntries(e,s,t),i!==t&&await this.applyUpdateCascade(e,t,i),r.delete(t),r.set(i,n),this.updateIndexes(e,n,i),u++;return u}checkUpdateUniqueness(e,t,s,i,r){const a=this.indexes.get(t);for(const[t,o]of Object.entries(e.columns)){if(!o.unique)continue;const h=i[t];if(null==h)continue;let c=r.get(t);if(c||(c=new Set,r.set(t,c)),c.has(h))throw new n(`Unique constraint violation on column "${t}" in table "${e.name}"`,"UNIQUE_VIOLATION");if(c.add(h),!a)continue;const l=a.get(t);if(l&&l.has(h)){const i=l.get(h);if(1!==i.size||!i.has(s))throw new n(`Unique constraint violation on column "${t}" in table "${e.name}"`,"UNIQUE_VIOLATION")}}}checkUpdateRestrict(e,t){for(const[s,i]of this.schemas)if(s!==e)for(const[r,a]of Object.entries(i.columns)){if(!a.references||!a.onUpdate)continue;const[i]=a.references.split(".");if(i!==e)continue;const o=this.tables.get(s);if(!o)continue;let h=!1;for(const[,i]of o)if(String(i[r])===t&&(h=!0,"RESTRICT"===a.onUpdate))throw new n(`Cannot update "${e}" key "${t}": foreign key "${r}" in "${s}" has dependent rows`,"FOREIGN_KEY_VIOLATION");if(h&&"SET NULL"===a.onUpdate&&a.required)throw new n(`Cannot update "${e}" key "${t}": foreign key "${r}" in "${s}" is required (SET NULL violates constraint)`,"FOREIGN_KEY_VIOLATION")}}async applyUpdateCascade(e,t,s){for(const[s,i]of this.schemas)if(s!==e)for(const[r,a]of Object.entries(i.columns)){if(!a.references||!a.onUpdate)continue;const[i]=a.references.split(".");if(i!==e)continue;const o=this.tables.get(s);if(o)for(const[,i]of o)if(String(i[r])===t&&"RESTRICT"===a.onUpdate)throw new n(`Cannot update "${e}" key "${t}": foreign key "${r}" in "${s}" has dependent rows`,"FOREIGN_KEY_VIOLATION")}for(const[n,i]of this.schemas)if(n!==e)for(const[r,a]of Object.entries(i.columns)){if(!a.references||!a.onUpdate)continue;const[i]=a.references.split(".");if(i!==e)continue;const o=this.tables.get(n);if(o&&("CASCADE"===a.onUpdate||"SET NULL"===a.onUpdate))for(const[e,i]of o)String(i[r])===t&&(this.removeIndexEntries(n,i,e),i[r]="CASCADE"===a.onUpdate?s:null,this.updateIndexes(n,i,e))}}async delete(e,t){this.ensureTable(e);const s=this.tables.get(e),n=[];for(const[i,r]of s)t.where&&0!==Object.keys(t.where).length&&!a(r,t.where)||(this.removeIndexEntries(e,r,i),n.push(i));const i=new Set;for(const t of n)s.get(t)&&this.checkCascadeRestrict(e,t,i);let r=0;for(const t of n){const n=s.get(t);n&&(r+=await this.cascadeDelete(e,t,n))}for(const e of n)s.delete(e);return n.length+r}checkCascadeRestrict(e,t,s){const i=`${e}:${t}`;if(!s.has(i)){s.add(i);for(const[i,r]of this.schemas)if(i!==e)for(const[a,o]of Object.entries(r.columns)){if(!o.references||!o.onDelete)continue;const[r]=o.references.split(".");if(r!==e)continue;const h=this.tables.get(i);if(!h)continue;const c=[];for(const[e,s]of h)String(s[a])===t&&c.push(e);if("RESTRICT"===o.onDelete&&c.length>0)throw new n(`Cannot delete from "${e}": foreign key "${a}" in "${i}" has dependent rows`,"FOREIGN_KEY_VIOLATION");if("SET NULL"===o.onDelete&&o.required&&c.length>0)throw new n(`Cannot delete from "${e}": foreign key "${a}" in "${i}" is required (SET NULL violates constraint)`,"FOREIGN_KEY_VIOLATION");if("CASCADE"===o.onDelete)for(const e of c)this.checkCascadeRestrict(i,e,s)}}}async count(e,t){this.ensureTable(e);const s=this.tables.get(e);if(!t?.where||0===Object.keys(t.where).length)return s.size;let n=0;for(const e of s.values())a(e,t.where)&&n++;return n}async clear(e){this.ensureTable(e),this.tables.get(e).clear();const t=this.indexes.get(e);if(t)for(const e of t.values())e.clear()}async createIndex(e,t,s){if(this.snapshot)throw new n("CREATE INDEX is not supported inside a transaction (MemoryEngine DDL is not transactional)","NOT_SUPPORTED");this.ensureTable(e);const i=this.schemas.get(e).columns[t];if(!i)throw new n(`Column "${t}" does not exist in table "${e}"`,"COLUMN_NOT_FOUND");if(i.index||i.unique)return;i.index=!0,s&&(i.unique=!0);const r=this.indexes.get(e);r.has(t)||r.set(t,new Map);const a=r.get(t),o=this.tables.get(e);for(const[e,s]of o){const n=s[t];null!=n&&(a.has(n)||a.set(n,new Set),a.get(n).add(e))}}async dropIndex(e,t,s){if(this.snapshot)throw new n("DROP INDEX is not supported inside a transaction (MemoryEngine DDL is not transactional)","NOT_SUPPORTED");this.ensureTable(e);const i=this.schemas.get(e).columns[t];if(!i)throw new n(`Column "${t}" does not exist in table "${e}"`,"COLUMN_NOT_FOUND");if(!i.index&&!i.unique)throw new n(`Index on column "${t}" does not exist in table "${e}"`,"INDEX_NOT_FOUND");i.index=!1,i.unique=!1;const r=this.indexes.get(e);r&&r.delete(t)}async beginTransaction(){if(this.snapshot)throw new n("Transaction already in progress","TX_ACTIVE");this.snapshot={tables:this.deepCloneMapMap(this.tables),schemas:new Map(this.schemas),indexes:this.deepCloneIndexes(this.indexes)}}async commitTransaction(){if(!this.snapshot)throw new n("No active transaction","TX_NONE");this.snapshot=null}async rollbackTransaction(){if(!this.snapshot)throw new n("No active transaction","TX_NONE");this.tables=this.snapshot.tables,this.schemas=this.snapshot.schemas,this.indexes=this.snapshot.indexes,this.snapshot=null}deepCloneMapMap(e){const t=new Map;for(const[s,n]of e){const e=new Map;for(const[t,s]of n)e.set(t,{...s});t.set(s,e)}return t}deepCloneIndexes(e){const t=new Map;for(const[s,n]of e){const e=new Map;for(const[t,s]of n){const n=new Map;for(const[e,t]of s)n.set(e,new Set(t));e.set(t,n)}t.set(s,e)}return t}ensureTable(e){if(!this.tables.has(e))throw new n(`Table "${e}" does not exist`,"TABLE_NOT_FOUND")}getPrimaryKey(e){for(const[t,s]of Object.entries(e.columns))if(s.primaryKey)return t;return Object.keys(e.columns)[0]}validateRow(e,t){const s={};for(const[i,r]of Object.entries(e.columns)){let a=t[i];if(void 0===a&&void 0!==r.default&&(a=r.default),r.required&&null==a)throw new n(`Column "${i}" is required in table "${e.name}"`,"VALIDATION_ERROR");null!=a&&this.checkType(i,r.type,a),void 0!==a&&(s[i]=a)}return s}checkType(e,t,s){const i=typeof s;switch(t){case"string":if("string"!==i)throw new n(`Column "${e}" expects string, got ${i}`,"TYPE_ERROR");break;case"number":if("number"!==i)throw new n(`Column "${e}" expects number, got ${i}`,"TYPE_ERROR");break;case"boolean":if("boolean"!==i)throw new n(`Column "${e}" expects boolean, got ${i}`,"TYPE_ERROR");break;case"date":if("string"!==i||isNaN(Date.parse(s)))throw new n(`Column "${e}" expects valid date`,"TYPE_ERROR");break;case"json":if("object"!==i)throw new n(`Column "${e}" expects object/array, got ${i}`,"TYPE_ERROR")}}checkUniqueness(e,t){const s=this.indexes.get(e.name);if(s)for(const[i,r]of Object.entries(e.columns)){if(!r.unique||void 0===t[i]||null===t[i])continue;const a=s.get(i);if(a&&a.has(t[i]))throw new n(`Unique constraint violation on column "${i}" in table "${e.name}"`,"UNIQUE_VIOLATION")}}tryIndexLookup(e,t,s){const n=this.indexes.get(e);if(!n||!s.where)return Array.from(t.values());for(const[e,i]of Object.entries(s.where)){let s;if("object"!=typeof i||null===i)s=i;else{if(!("$eq"in i)||1!==Object.keys(i).length)continue;s=i.$eq}const r=n.get(e);if(r){const e=r.get(s);if(e){const s=[];for(const n of e){const e=t.get(n);e&&s.push(e)}return s}return[]}}return Array.from(t.values())}updateIndexes(e,t,s){const n=this.indexes.get(e);if(n)for(const[e,i]of n){const n=t[e];null!=n&&(i.has(n)||i.set(n,new Set),i.get(n).add(s))}}removeIndexEntries(e,t,s){const n=this.indexes.get(e);if(n)for(const[e,i]of n){const n=t[e];if(null!=n){const e=i.get(n);e&&(e.delete(s),0===e.size&&i.delete(n))}}}async cascadeDelete(e,t,s,i=new Set){const r=`${e}:${t}`;if(i.has(r))return 0;i.add(r);let a=0;for(const[s,r]of this.schemas)if(s!==e)for(const[o,h]of Object.entries(r.columns)){if(!h.references||!h.onDelete)continue;const[r]=h.references.split(".");if(r!==e)continue;const c=this.tables.get(s);if(!c)continue;const l=[];for(const[e,s]of c)String(s[o])===t&&l.push(e);if("RESTRICT"===h.onDelete&&l.length>0)throw new n(`Cannot delete from "${e}": foreign key "${o}" in "${s}" has dependent rows`,"FOREIGN_KEY_VIOLATION");if("CASCADE"===h.onDelete)for(const e of l){const t=c.get(e);t&&(this.removeIndexEntries(s,t,e),a+=await this.cascadeDelete(s,e,t,i)),c.delete(e),a++}else if("SET NULL"===h.onDelete)for(const e of l){const t=c.get(e);t&&(this.removeIndexEntries(s,t,e),t[o]=null,this.updateIndexes(s,t,e))}}return a}}const m=[".crswap",".tmp"];class g{constructor(){this.root=null,this.dbDir=null,this.dbName="",this.writeQueue=Promise.resolve()}async open(e){this.dbName=e,this.root=await navigator.storage.getDirectory(),this.dbDir=await this.root.getDirectoryHandle(e,{create:!0}),await this.cleanupStaleFiles()}async close(){try{await this.writeQueue}catch{}this.dbDir=null,this.root=null}isOpen(){return null!==this.dbDir}async cleanupStaleFiles(){if(this.dbDir)try{const e=this.dbDir,t=[];for await(const[s]of e.entries())m.some(e=>s.endsWith(e))&&t.push(s);for(const e of t)try{await this.dbDir.removeEntry(e)}catch{}}catch{}}async read(e){if(!this.dbDir)return null;try{const t=await this.dbDir.getFileHandle(e),s=await t.getFile();return await s.arrayBuffer()}catch{return null}}async write(e,t){if(!this.dbDir)return;const s=this.writeQueue.then(async()=>{const s=await this.dbDir.getFileHandle(e,{create:!0}),n=await s.createWritable();await n.write(t),await n.close()});return this.writeQueue=s.then(()=>{},()=>{}),s}async append(e,t){if(!this.dbDir)return;const s=this.writeQueue.then(async()=>{const s=await this.dbDir.getFileHandle(e,{create:!0}),n=await s.getFile(),i=await s.createWritable({keepExistingData:!0});await i.write({type:"write",position:n.size,data:t}),await i.close()});return this.writeQueue=s.then(()=>{},()=>{}),s}async writeMany(e){if(!this.dbDir)return;const t=this.writeQueue.then(async()=>{for(const[t,s]of Object.entries(e)){const e=await this.dbDir.getFileHandle(t,{create:!0}),n=await e.createWritable();await n.write(s),await n.close()}});return this.writeQueue=t.then(()=>{},()=>{}),t}async delete(e){if(!this.dbDir)return;const t=this.writeQueue.then(async()=>{try{await this.dbDir.removeEntry(e)}catch{}});return this.writeQueue=t.then(()=>{},()=>{}),t}async deleteMany(e){if(!this.dbDir)return;const t=this.writeQueue.then(async()=>{for(const t of e)try{await this.dbDir.removeEntry(t)}catch{}});return this.writeQueue=t.then(()=>{},()=>{}),t}async listKeys(){if(!this.dbDir)return[];const e=[],t=this.dbDir;for await(const[s]of t.entries())e.push(s);return e}async exists(e){if(!this.dbDir)return!1;try{return await this.dbDir.getFileHandle(e),!0}catch{return!1}}async clear(){if(!this.dbDir)return;const e=this.dbDir;for await(const[t]of e.entries())try{await this.dbDir.removeEntry(t)}catch{}}}const w=new Map;class b{constructor(){this.dbName="",this.chunks=new Map,this.materialized=new Map}static clearRegistry(){w.clear()}async open(e){this.dbName=e,w.has(e)||w.set(e,new Map),this.chunks=w.get(e),this.materialized=new Map}async close(){this.chunks=new Map,this.materialized=new Map}isOpen(){return""!==this.dbName}async read(e){if(this.materialized.has(e))return this.materialized.get(e);const t=this.chunks.get(e);if(!t||0===t.length)return null;if(1===t.length)return this.materialized.set(e,t[0]),t[0];const s=t.reduce((e,t)=>e+t.byteLength,0),n=new Uint8Array(s);let i=0;for(const e of t)n.set(new Uint8Array(e),i),i+=e.byteLength;const r=n.buffer;return this.materialized.set(e,r),r}async write(e,t){this.chunks.set(e,[t]),this.materialized.set(e,t)}async append(e,t){const s=this.chunks.get(e);s?s.push(t):this.chunks.set(e,[t]),this.materialized.delete(e)}async writeMany(e){for(const[t,s]of Object.entries(e))this.chunks.set(t,[s]),this.materialized.set(t,s)}async delete(e){this.chunks.delete(e),this.materialized.delete(e)}async deleteMany(e){for(const t of e)this.chunks.delete(t),this.materialized.delete(t)}async listKeys(){return Array.from(this.chunks.keys())}async exists(e){return this.chunks.has(e)}async clear(){this.chunks.clear(),this.materialized.clear()}}const T=(()=>{const e=new Uint32Array(256);for(let t=0;t<256;t++){let s=t;for(let e=0;e<8;e++)s=1&s?3988292384^s>>>1:s>>>1;e[t]=s>>>0}return e})(),E=4294967295;function k(e,t=0){const s=function(e,t){let s=e>>>0;for(let e=0;e<t.byteLength;e++)s=(T[255&(s^t[e])]^s>>>8)>>>0;return s>>>0}(t^E,e);return function(e){return(e^E)>>>0}(s)}var x;!function(e){e[e.PUT=1]="PUT",e[e.DELETE=2]="DELETE",e[e.APPEND=3]="APPEND"}(x||(x={}));const S=1263948622;function I(e,t){const s=new TextEncoder,n=Array.from(t.keys()),i=[];let r=12;for(const e of n){const n=s.encode(e),a=new Uint8Array(t.get(e));i.push({key:n,value:a}),r+=4+n.byteLength+4+a.byteLength}r+=4;const a=new Uint8Array(r),o=new DataView(a.buffer);let h=0;o.setUint32(h,S,!1),h+=4,o.setUint32(h,e,!1),h+=4,o.setUint32(h,i.length,!1),h+=4;for(const e of i)o.setUint32(h,e.key.byteLength,!1),h+=4,a.set(e.key,h),h+=e.key.byteLength,o.setUint32(h,e.value.byteLength,!1),h+=4,a.set(e.value,h),h+=e.value.byteLength;const c=k(a.subarray(0,r-4));return o.setUint32(r-4,c,!1),a}function A(e){if(e.byteLength<16)return null;const t=new DataView(e.buffer,e.byteOffset,e.byteLength);if(t.getUint32(0,!1)!==S)return null;if(t.getUint32(e.byteLength-4,!1)!==k(e.subarray(0,e.byteLength-4)))return null;const s=new TextDecoder,n=new Map;let i=4;const r=t.getUint32(i,!1);i+=4;const a=t.getUint32(i,!1);i+=4;for(let r=0;r<a;r++){if(i+4>e.byteLength-4)return null;const r=t.getUint32(i,!1);if(i+=4,i+r+4>e.byteLength-4)return null;const a=s.decode(e.subarray(i,i+r));i+=r;const o=t.getUint32(i,!1);if(i+=4,i+o>e.byteLength-4)return null;const h=e.slice(i,i+o).buffer;i+=o,n.set(a,h)}return{seq:r,entries:n}}const R="__kv_log",C="__kv_snapshot",O="__kv_meta";class N{constructor(e,t=16777216){this.dbName="",this.opened=!1,this.index=new Map,this.seq=0,this.logBytes=0,this.opQueue=Promise.resolve(),this.lastBackgroundError=null,this.medium=e??function(){const e=globalThis.navigator;return void 0!==e&&e.storage&&"function"==typeof e.storage.getDirectory?new g:new b}(),this.checkpointThreshold=t}isOpen(){return this.opened}async open(e){if(this.opened)return;this.dbName=e,await this.medium.open(e),this.index=new Map,this.seq=0,this.logBytes=0;let t=0;const s=await this.medium.read(C);if(s){const e=A(new Uint8Array(s));e?(this.index=new Map(e.entries),this.seq=e.seq,t=e.seq):(this.index=new Map,this.seq=0,t=0)}const n=await this.medium.read(R);if(n&&n.byteLength>0){const e=new Uint8Array(n),s=t,i=[];(function(e,t,s){let n=0,i=0;const r=new DataView(e.buffer,e.byteOffset,e.byteLength),a=new TextDecoder;for(;n+4<=e.byteLength;){const o=r.getUint32(n,!1);if(o<12||n+4+o>e.byteLength){if(s&&!s(n))break;break}const h=n,c=n+4+o,l=e.subarray(h,c),u=new DataView(e.buffer,e.byteOffset+h,o+4);if(u.getUint32(o,!1)!==k(l.subarray(0,o))){if(s&&!s(h))break;break}let f=4;const d=u.getUint32(f,!1);f+=4;const p=u.getUint32(f,!1);f+=4;const y=[];let m=!0;for(let e=0;e<p;e++){if(f+1+4>o+4){m=!1;break}const e=u.getUint8(f);f+=1;const t=u.getUint32(f,!1);if(f+=4,f+t+4>o+4){m=!1;break}const s=a.decode(l.subarray(f,f+t));f+=t;const n=u.getUint32(f,!1);if(f+=4,f+n>o+4){m=!1;break}const i=l.slice(f,f+n).buffer;f+=n,y.push({op:e,key:s,value:i})}if(!m){if(s&&!s(h))break;break}t({seq:d,entries:y,raw:l}),i++,n=c}return i}(e,e=>{e.seq<=s||(this.applyRecord(e.entries),this.seq=e.seq)},e=>(i.push(e),!0))>0||i.length>0)&&(this.logBytes=e.byteLength),i.length>0&&await this.truncateLog()}this.opened=!0}async reload(){if(this.opened){try{await this.opQueue}catch{}this.index=new Map,this.seq=0,this.logBytes=0,this.opened=!1,await this.open(this.dbName)}}async close(){if(this.opened){try{await this.opQueue}catch{}await this.medium.close(),this.index.clear(),this.seq=0,this.logBytes=0,this.opened=!1}}async get(e){return this.index.get(e)??null}async getAll(){return Array.from(this.index.entries())}async listKeys(){return Array.from(this.index.keys())}async exists(e){return this.index.has(e)}size(){return this.index.size}async put(e,t){await this.enqueue(async()=>{await this.appendRecord({[e]:t},[])})}async putMany(e){0!==Object.keys(e).length&&await this.enqueue(async()=>{await this.appendRecord(e,[])})}async delete(e){await this.enqueue(async()=>{await this.appendRecord({},[e])})}async deleteMany(e){0!==e.length&&await this.enqueue(async()=>{await this.appendRecord({},e)})}async writeBatch(e,t){0===Object.keys(e).length&&0===t.length||await this.enqueue(async()=>{await this.appendRecord(e,t)})}async appendValue(e,t){0!==t.byteLength&&await this.enqueue(async()=>{await this.appendRecord({},[],{[e]:t})})}async checkpoint(){await this.enqueue(async()=>{if(null!==this.lastBackgroundError){const e=this.lastBackgroundError;throw this.lastBackgroundError=null,new n("KVStore background write failed","KV_BACKGROUND_ERROR",e)}if(0===this.logBytes&&0===this.index.size)return;const e=I(this.seq,this.index);await this.medium.write(C,e.buffer);const t={seq:this.seq};await this.medium.write(O,(new TextEncoder).encode(JSON.stringify(t)).buffer),await this.truncateLog()})}async clear(){await this.enqueue(async()=>{await this.medium.clear(),this.index.clear(),this.seq=0,this.logBytes=0,await this.medium.write(O,(new TextEncoder).encode(JSON.stringify({seq:0})).buffer)})}async repair(){return this.enqueue(async()=>{let e=0;const t=await this.medium.read(C);t&&!A(new Uint8Array(t))&&(await this.medium.delete(C),e++);const s=await this.medium.read(R);if(s&&s.byteLength>0){const t=new Uint8Array(s),n=this.findValidLogLength(t);if(n<t.byteLength){e+=t.byteLength-n;const s=t.subarray(0,n).slice().buffer;await this.medium.write(R,s)}}return e})}enqueue(e){const t=this.opQueue.then(e,e);return this.opQueue=t.then(()=>{},()=>{}),t}async appendRecord(e,t,s={}){this.seq++;const i=function(e,t,s=[],n={}){const i=new TextEncoder,r=[];for(const[e,s]of Object.entries(t))r.push({op:x.PUT,key:e,value:s});for(const e of s)r.push({op:x.DELETE,key:e,value:new ArrayBuffer(0)});for(const[e,t]of Object.entries(n))r.push({op:x.APPEND,key:e,value:t});const a=[];let o=12;for(const e of r){const t=i.encode(e.key),s=new Uint8Array(e.value);a.push({op:e.op,key:t,value:s}),o+=5+t.byteLength+4+s.byteLength}o+=4;const h=new Uint8Array(o),c=new DataView(h.buffer);let l=0;c.setUint32(l,o-4,!1),l+=4,c.setUint32(l,e,!1),l+=4,c.setUint32(l,a.length,!1),l+=4;for(const e of a)c.setUint8(l,e.op),l+=1,c.setUint32(l,e.key.byteLength,!1),l+=4,h.set(e.key,l),l+=e.key.byteLength,c.setUint32(l,e.value.byteLength,!1),l+=4,h.set(e.value,l),l+=e.value.byteLength;const u=k(h.subarray(0,o-4));return c.setUint32(o-4,u,!1),h}(this.seq,e,t,s);try{const e=i.buffer.slice(i.byteOffset,i.byteOffset+i.byteLength);if("function"==typeof this.medium.append)await this.medium.append(R,e);else{const t=await this.medium.read(R);if(t){const s=new Uint8Array(t.byteLength+e.byteLength);s.set(new Uint8Array(t),0),s.set(new Uint8Array(e),t.byteLength),await this.medium.write(R,s.buffer)}else await this.medium.write(R,e)}}catch(e){throw this.seq--,this.lastBackgroundError=e,new n("KVStore log append failed","KV_LOG_ERROR",e)}for(const[t,s]of Object.entries(e))this.index.set(t,s);for(const e of t)this.index.delete(e);for(const[e,t]of Object.entries(s)){const s=this.index.get(e);if(s){const n=new Uint8Array(s.byteLength+t.byteLength);n.set(new Uint8Array(s),0),n.set(new Uint8Array(t),s.byteLength),this.index.set(e,n.buffer)}else this.index.set(e,t)}if(this.logBytes+=i.byteLength,this.checkpointThreshold>0&&this.logBytes>=this.checkpointThreshold){await this.medium.write(C,I(this.seq,this.index).buffer);const e={seq:this.seq};await this.medium.write(O,(new TextEncoder).encode(JSON.stringify(e)).buffer),await this.truncateLog()}}async truncateLog(){try{await this.medium.write(R,new ArrayBuffer(0))}catch{}this.logBytes=0}applyRecord(e){for(const t of e)if(t.op===x.PUT)this.index.set(t.key,t.value);else if(t.op===x.APPEND){const e=this.index.get(t.key);if(e){const s=new Uint8Array(e.byteLength+t.value.byteLength);s.set(new Uint8Array(e),0),s.set(new Uint8Array(t.value),e.byteLength),this.index.set(t.key,s.buffer)}else this.index.set(t.key,t.value)}else this.index.delete(t.key)}findValidLogLength(e){let t=0;const s=new DataView(e.buffer,e.byteOffset,e.byteLength);for(;t+4<=e.byteLength;){const n=s.getUint32(t,!1);if(n<12||t+4+n>e.byteLength)break;const i=e.subarray(t,t+4+n),r=s.getUint32(t+n,!1);if(k(i.subarray(0,n))!==r)break;t+=4+n}return t}}const L="__schema",v="t:",$=e=>(new TextEncoder).encode(e).buffer,D=e=>(new TextDecoder).decode(e);class U{constructor(e,t){this.name="kv",this.memory=new y,this.dbName="",this.version=1,this.opened=!1,this.txActive=!1,this.txDirtyTables=new Set,this.txSchemaChanged=!1,this.txChanges=new Map,this.txFullTables=new Set,this.txClearedTables=new Set,this.kv=new N(e,t)}rowKey(e,t){return`${v}${e}:${t}`}rowPrefix(e){return`${v}${e}:`}async open(e,t){if(this.opened)return;this.dbName=e,this.version=t,await this.kv.open(e),await this.memory.open(e,t);const s=await this.kv.get(L);if(s)try{const e=JSON.parse(D(s));for(const t of Object.values(e))await this.memory.createTable(t)}catch{throw new n("Corrupted schema in KVStore","KV_SCHEMA_ERROR")}const i=await this.kv.getAll();for(const[e,t]of i){if(!e.startsWith(v))continue;const s=e.indexOf(":",2);if(s<0)continue;const n=e.slice(2,s);if(await this.memory.hasTable(n))try{const e=JSON.parse(D(t));await this.memory.insert(n,[e])}catch{}}const r=await this.memory.getTableNames();for(const e of r){const t=await this.memory.getTableSchema(e);if(t)for(const[s,n]of Object.entries(t.columns))(n.index||n.unique)&&await this.memory.createIndex(e,s,n.unique)}this.opened=!0}async close(){if(this.opened){if(this.txActive)try{await this.rollbackTransaction()}catch{}try{await this.kv.checkpoint()}catch{}await this.kv.close(),await this.memory.close(),this.opened=!1}}isOpen(){return this.opened}async reload(){this.opened&&(await this.kv.reload(),await this.memory.close(),await this.memory.open(this.dbName,this.version),this.opened=!1,await this.open(this.dbName,this.version))}async repair(){this.ensureOpen(),await this.kv.repair(),await this.memory.close(),await this.memory.open(this.dbName,this.version),this.opened=!1,await this.open(this.dbName,this.version)}async clearAll(){this.ensureOpen(),await this.kv.clear(),await this.memory.clearAll()}async getMeta(e){const t=await this.kv.get(`__meta:${e}`);return t?D(t):null}async setMeta(e,t){await this.kv.put(`__meta:${e}`,$(t))}async createTable(e){if(this.ensureOpen(),await this.memory.createTable(e),this.txActive)return this.txDirtyTables.add(e.name),void(this.txSchemaChanged=!0);await this.persistSchema()}async dropTable(e){if(this.ensureOpen(),await this.memory.dropTable(e),this.txActive)return this.txDirtyTables.add(e),void(this.txSchemaChanged=!0);await this.persistSchema();const t=await this.collectTableDiff(e);await this.kv.writeBatch(t.puts,t.deletes)}async hasTable(e){return this.ensureOpen(),this.memory.hasTable(e)}async getTableNames(){return this.ensureOpen(),this.memory.getTableNames()}async getTableSchema(e){return this.ensureOpen(),this.memory.getTableSchema(e)}async alterTable(e,t,s){if(this.ensureOpen(),this.txActive)throw new n("ALTER TABLE is not supported inside a transaction (KVStoreEngine DDL is not transactional)","NOT_SUPPORTED");if(await this.memory.alterTable(e,t,s),this.txActive)return this.txDirtyTables.add(e),void(this.txSchemaChanged=!0);if(await this.persistSchema(),"DROP"===t){const t=await this.collectTableDiff(e);await this.kv.writeBatch(t.puts,t.deletes)}}async insert(e,t){this.ensureOpen();const s=await this.memory.insert(e,t);if(this.txActive){if(this.txDirtyTables.add(e),this.txClearedTables.has(e))return this.txClearedTables.delete(e),this.txFullTables.add(e),s;let t=this.txChanges.get(e);t||(t=new Map,this.txChanges.set(e,t));for(const e of s)t.set(e,"put");return s}const i=await this.memory.getTableSchema(e);if(!i)throw new n(`Table "${e}" does not exist`,"TABLE_NOT_FOUND");const r=this.getPK(i),a={};return t.forEach((t,n)=>{a[this.rowKey(e,String(s[n]??t[r]))]=$(JSON.stringify(t))}),await this.kv.putMany(a),s}async find(e,t){return this.ensureOpen(),this.memory.find(e,t)}async findStream(e,t,s){return this.ensureOpen(),this.memory.findStream(e,t,s)}async update(e,t,s){this.ensureOpen();const i=await this.memory.getTableSchema(e);if(!i)throw new n(`Table "${e}" does not exist`,"TABLE_NOT_FOUND");const r=this.getPK(i),a=d(s),o=r in a,h=o?[]:await this.collectMatchingPks(e,t),c=await this.memory.update(e,t,a);if(this.txActive){if(this.txDirtyTables.add(e),o)for(const t of await this.affectedTables(e))this.txFullTables.add(t),this.txDirtyTables.add(t);else{let t=this.txChanges.get(e);t||(t=new Map,this.txChanges.set(e,t));for(const e of h)t.set(e,"put");for(const t of await this.affectedTables(e))t!==e&&(this.txFullTables.add(t),this.txDirtyTables.add(t))}return c}const l={},u=[];if(o)for(const t of await this.affectedTables(e)){const e=await this.collectTableDiff(t);Object.assign(l,e.puts),u.push(...e.deletes)}else{const t=new Set(h),s=await this.memory.find(e,{table:e});for(const n of s){const s=String(n[r]);t.has(s)&&(l[this.rowKey(e,s)]=$(JSON.stringify(n)),t.delete(s))}for(const s of t)u.push(this.rowKey(e,s));for(const t of await this.affectedTables(e)){if(t===e)continue;const s=await this.collectTableDiff(t);Object.assign(l,s.puts),u.push(...s.deletes)}}return await this.kv.writeBatch(l,u),c}async delete(e,t){this.ensureOpen();const s=await this.collectMatchingPks(e,t),n=await this.memory.delete(e,t);if(this.txActive){this.txDirtyTables.add(e);let t=this.txChanges.get(e);t||(t=new Map,this.txChanges.set(e,t));for(const e of s)t.set(e,"delete");for(const t of await this.affectedTables(e))t!==e&&(this.txFullTables.add(t),this.txDirtyTables.add(t));return n}const i={},r=s.map(t=>this.rowKey(e,t));for(const t of await this.affectedTables(e)){if(t===e)continue;const s=await this.collectTableDiff(t);Object.assign(i,s.puts),r.push(...s.deletes)}return await this.kv.writeBatch(i,r),n}async count(e,t){return this.ensureOpen(),this.memory.count(e,t)}async clear(e){if(this.ensureOpen(),await this.memory.clear(e),this.txActive)return this.txDirtyTables.add(e),this.txClearedTables.add(e),void this.txChanges.delete(e);const t=await this.collectTableDiff(e);await this.kv.writeBatch(t.puts,t.deletes)}async createIndex(e,t,s){if(this.ensureOpen(),this.txActive)throw new n("CREATE INDEX is not supported inside a transaction (KVStoreEngine DDL is not transactional)","NOT_SUPPORTED");if(await this.memory.createIndex(e,t,s),this.txActive)return this.txDirtyTables.add(e),void(this.txSchemaChanged=!0);await this.persistSchema()}async dropIndex(e,t,s){if(this.ensureOpen(),this.txActive)throw new n("DROP INDEX is not supported inside a transaction (KVStoreEngine DDL is not transactional)","NOT_SUPPORTED");if(await this.memory.dropIndex(e,t,s),this.txActive)return this.txDirtyTables.add(e),void(this.txSchemaChanged=!0);await this.persistSchema()}async beginTransaction(){this.ensureOpen(),await this.memory.beginTransaction(),this.txActive=!0,this.txDirtyTables=new Set,this.txSchemaChanged=!1,this.txChanges=new Map,this.txFullTables=new Set,this.txClearedTables=new Set}async commitTransaction(){if(this.ensureOpen(),!this.txActive)throw new n("No active transaction","TX_NONE");const e={},t=[];for(const s of this.txDirtyTables){if(!await this.memory.hasTable(s)){const e=await this.kv.getAll(),n=this.rowPrefix(s);for(const[s]of e)s.startsWith(n)&&t.push(s);continue}if(this.txClearedTables.has(s)){const e=await this.kv.getAll(),n=this.rowPrefix(s);for(const[s]of e)s.startsWith(n)&&t.push(s);continue}if(this.txFullTables.has(s)){const n=await this.collectTableDiff(s);Object.assign(e,n.puts),t.push(...n.deletes);continue}const n=this.txChanges.get(s);if(n&&n.size>0){const i=await this.memory.getTableSchema(s);if(!i)continue;const r=this.getPK(i),a=new Map(n),o=await this.memory.find(s,{table:s});for(const n of o){const i=String(n[r]),o=a.get(i);void 0!==o&&("put"===o?e[this.rowKey(s,i)]=$(JSON.stringify(n)):t.push(this.rowKey(s,i)),a.delete(i))}for(const[e,n]of a)"delete"===n&&t.push(this.rowKey(s,e))}}await this.kv.writeBatch(e,t),this.txSchemaChanged&&await this.persistSchema(),await this.memory.commitTransaction(),this.txActive=!1,this.txDirtyTables=new Set,this.txChanges=new Map,this.txFullTables=new Set,this.txClearedTables=new Set}async rollbackTransaction(){if(this.ensureOpen(),!this.txActive)throw new n("No active transaction","TX_NONE");await this.memory.rollbackTransaction(),this.txActive=!1,this.txDirtyTables=new Set,this.txSchemaChanged=!1,this.txChanges=new Map,this.txFullTables=new Set,this.txClearedTables=new Set}ensureOpen(){if(!this.opened)throw new n("Database not opened","DB_NOT_OPEN")}getPK(e){for(const[t,s]of Object.entries(e.columns))if(s.primaryKey)return t;return Object.keys(e.columns)[0]}async collectMatchingPks(e,t){const s=await this.memory.getTableSchema(e);if(!s)throw new n(`Table "${e}" does not exist`,"TABLE_NOT_FOUND");const i=this.getPK(s);return(await this.memory.find(e,t)).map(e=>String(e[i]))}async affectedTables(e){const t=new Set([e]);let s=!0;for(;s;){s=!1;for(const e of await this.memory.getTableNames()){if(t.has(e))continue;const n=await this.memory.getTableSchema(e);if(n)for(const i of Object.values(n.columns))if(i.references){const n=i.references.split(".")[0];if(t.has(n)){t.add(e),s=!0;break}}}}return t}async persistSchema(){const e={};for(const t of await this.memory.getTableNames()){const s=await this.memory.getTableSchema(t);s&&(e[t]=s)}await this.kv.put(L,$(JSON.stringify(e)))}async collectTableDiff(e){const t=this.rowPrefix(e),s={},n=[],i=await this.memory.getTableSchema(e);if(i){const r=this.getPK(i),a=await this.memory.find(e,{table:e}),o=new Set;for(const t of a){const n=this.rowKey(e,String(t[r]));o.add(n),s[n]=$(JSON.stringify(t))}const h=await this.kv.getAll();for(const[e]of h)e.startsWith(t)&&!o.has(e)&&n.push(e)}else{const e=await this.kv.getAll();for(const[s]of e)s.startsWith(t)&&n.push(s)}return{puts:s,deletes:n}}}const _=4096;var M;!function(e){e[e.DATA=1]="DATA",e[e.INDEX=2]="INDEX",e[e.OVERFLOW=3]="OVERFLOW",e[e.META=4]="META"}(M||(M={}));const P=4194304;var B,K;!function(e){e[e.INSERT=1]="INSERT",e[e.UPDATE=2]="UPDATE",e[e.DELETE=3]="DELETE",e[e.BEGIN=4]="BEGIN",e[e.COMMIT=5]="COMMIT",e[e.ROLLBACK=6]="ROLLBACK",e[e.CREATE_TABLE=7]="CREATE_TABLE",e[e.DROP_TABLE=8]="DROP_TABLE"}(B||(B={})),function(e){e[e.ACTIVE=1]="ACTIVE",e[e.COMMITTED=2]="COMMITTED",e[e.ABORTED=3]="ABORTED"}(K||(K={}));const z={pageSize:_,bufferPoolPages:256,memtableSizeThreshold:P,levelSizeMultiplier:10,bloomFilterBitsPerKey:10,walEnabled:!0,walSyncMode:"full",checkpointInterval:1e3,compression:!1,storageBackend:"opfs",walSizeThreshold:16777216,maxMemoryMB:64,encryption:void 0,pageStorage:void 0};var F;!function(e){e[e.RED=0]="RED",e[e.BLACK=1]="BLACK"}(F||(F={}));class q{constructor(e,t){this.color=F.RED,this.left=null,this.right=null,this.parent=null,this.key=e,this.value=t}}class j{constructor(){this.root=null,this._size=0}get size(){return this._size}insert(e,t){const s=new q(e,t);if(!this.root)return this.root=s,s.color=F.BLACK,void this._size++;let n=null,i=this.root;for(;i;)if(n=i,e<i.key)i=i.left;else{if(!(e>i.key))return void(i.value=t);i=i.right}s.parent=n,e<n.key?n.left=s:n.right=s,this._size++,this.fixInsert(s)}find(e){let t=this.root;for(;t;)if(e<t.key)t=t.left;else{if(!(e>t.key))return t.value;t=t.right}return null}delete(e){const t=this.findNode(e);return!!t&&(this.deleteNode(t),this._size--,!0)}inorder(e){this._inorder(this.root,e)}rangeScan(e,t,s){this._rangeScan(this.root,e,t,s)}getAllEntries(){const e=[];return this.inorder((t,s)=>e.push([t,s])),e}clear(){this.root=null,this._size=0}findNode(e){let t=this.root;for(;t;)if(e<t.key)t=t.left;else{if(!(e>t.key))return t;t=t.right}return null}deleteNode(e){if(e.left||e.right)if(e.left)if(e.right){const t=this.minimum(e.right);t.parent!==e&&(this.transplant(t,t.right),t.right=e.right,t.right.parent=t),this.transplant(e,t),t.left=e.left,t.left.parent=t;const s=t.color;t.color=e.color,s===F.BLACK&&this.fixDelete(t.right,t.right?.parent??null)}else this.transplant(e,e.left),e.color===F.BLACK&&this.fixDelete(e.left,e.left.parent);else this.transplant(e,e.right),e.color===F.BLACK&&this.fixDelete(e.right,e.right.parent);else this.transplant(e,null),e.color===F.BLACK&&this.fixDelete(null,e.parent)}transplant(e,t){e.parent?e===e.parent.left?e.parent.left=t:e.parent.right=t:this.root=t,t&&(t.parent=e.parent)}minimum(e){for(;e.left;)e=e.left;return e}fixInsert(e){for(;e.parent&&e.parent.color===F.RED;){const t=e.parent,s=t.parent;if(!s)break;if(t===s.left){const n=s.right;n&&n.color===F.RED?(t.color=F.BLACK,n.color=F.BLACK,s.color=F.RED,e=s):(e===t.right&&(e=t,this.rotateLeft(e)),e.parent&&(e.parent.color=F.BLACK),e.parent?.parent&&(e.parent.parent.color=F.RED),e.parent?.parent&&this.rotateRight(e.parent.parent))}else{const n=s.left;n&&n.color===F.RED?(t.color=F.BLACK,n.color=F.BLACK,s.color=F.RED,e=s):(e===t.left&&(e=t,this.rotateRight(e)),e.parent&&(e.parent.color=F.BLACK),e.parent?.parent&&(e.parent.parent.color=F.RED),e.parent?.parent&&this.rotateLeft(e.parent.parent))}}this.root&&(this.root.color=F.BLACK)}fixDelete(e,t){let s=e,n=t;for(;(!s||s.color===F.BLACK)&&s!==this.root&&n;)if(s===n.left){let e=n.right;if(!e)break;if(e.color===F.RED&&(e.color=F.BLACK,n.color=F.RED,this.rotateLeft(n),e=n.right,!e))break;const t=e.left,i=e.right;if(t&&t.color!==F.BLACK||i&&i.color!==F.BLACK){if(!(i&&i.color!==F.BLACK||(t&&(t.color=F.BLACK),e.color=F.RED,this.rotateRight(e),e=n.right,e)))break;e.color=n.color,n.color=F.BLACK,e.right&&(e.right.color=F.BLACK),this.rotateLeft(n),s=this.root}else e.color=F.RED,s=n,n=s.parent}else{let e=n.left;if(!e)break;if(e.color===F.RED&&(e.color=F.BLACK,n.color=F.RED,this.rotateRight(n),e=n.left,!e))break;const t=e.left,i=e.right;if(t&&t.color!==F.BLACK||i&&i.color!==F.BLACK){if(!(t&&t.color!==F.BLACK||(i&&(i.color=F.BLACK),e.color=F.RED,this.rotateLeft(e),e=n.left,e)))break;e.color=n.color,n.color=F.BLACK,e.left&&(e.left.color=F.BLACK),this.rotateRight(n),s=this.root}else e.color=F.RED,s=n,n=s.parent}s&&(s.color=F.BLACK)}rotateLeft(e){const t=e.right;t&&(e.right=t.left,t.left&&(t.left.parent=e),t.parent=e.parent,e.parent?e===e.parent.left?e.parent.left=t:e.parent.right=t:this.root=t,t.left=e,e.parent=t)}rotateRight(e){const t=e.left;t&&(e.left=t.right,t.right&&(t.right.parent=e),t.parent=e.parent,e.parent?e===e.parent.right?e.parent.right=t:e.parent.left=t:this.root=t,t.right=e,e.parent=t)}_inorder(e,t){e&&(this._inorder(e.left,t),t(e.key,e.value),this._inorder(e.right,t))}_rangeScan(e,t,s,n){e&&(e.key>t&&this._rangeScan(e.left,t,s,n),e.key>=t&&e.key<=s&&n(e.key,e.value),e.key<s&&this._rangeScan(e.right,t,s,n))}}class V{constructor(e=4194304){this._estimatedSize=0,this.tree=new j,this.maxSize=e}put(e,t){const s=this.estimateEntrySize(e,this.tree.find(e)),n=this.estimateEntrySize(e,t);this.tree.insert(e,t),this._estimatedSize+=n-s}get(e){return this.tree.find(e)}delete(e){const t=this.tree.find(e);return t&&(this._estimatedSize-=this.estimateEntrySize(e,t)),this.tree.delete(e)}shouldFlush(){return this._estimatedSize>=this.maxSize}getAllEntries(){return this.tree.getAllEntries()}rangeScan(e,t){const s=[];return this.tree.rangeScan(e,t,(e,t)=>s.push([e,t])),s}getEntryCount(){return this.tree.size}getEstimatedSize(){return this._estimatedSize}clear(){this.tree.clear(),this._estimatedSize=0}estimateEntrySize(e,t){if(!t)return 0;let s=2*e.length;for(const e of Object.entries(t)){s+=2*e[0].length;const t=e[1];s+="string"==typeof t?2*t.length:"number"==typeof t?8:"boolean"==typeof t||null==t?1:16}return s}}class W{constructor(e,t=10){this._inserted=0;const s=Math.max(64,e*t),n=Math.ceil(s/8);this.bits=new Uint8Array(n),this.numHashes=Math.max(1,Math.floor(.69*t))}static fromData(e,t){const s=new W(1);return s.bits=e,s.numHashes=t,s}insert(e){const t=this.getHashes(e);for(const e of t){const t=Math.floor(e/8),s=e%8;this.bits[t]|=1<<s}this._inserted++}mayContain(e){const t=this.getHashes(e);for(const e of t){const t=Math.floor(e/8),s=e%8;if(!(this.bits[t]&1<<s))return!1}return!0}serialize(){return this.bits}getHashCount(){return this.numHashes}getHashes(e){const t=8*this.bits.byteLength,s=this.fnv1a(e),n=this.murmurSimple(e),i=[];for(let e=0;e<this.numHashes;e++){const r=Math.abs((s+e*n)%t);i.push(r)}return i}fnv1a(e){let t=2166136261;for(let s=0;s<e.length;s++)t^=e.charCodeAt(s),t=16777619*t>>>0;return t}murmurSimple(e){let t=0;for(let s=0;s<e.length;s++)t=(t<<5)-t+e.charCodeAt(s)|0,t=(t^t>>>16)>>>0;return Math.abs(t)}}const G=1397969987;class H{constructor(e=4096){this.entries=[],this.blockSizeLimit=e}add(e,t){this.entries.push([e,t])}build(){const e=new TextEncoder,t=this.entries.map(([t,s])=>({key:t,keyBytes:e.encode(t),valueBytes:e.encode(JSON.stringify(s))})),s=this.splitIntoBlocks(t),n=new W(this.entries.length);let i=0;const r=[];for(const e of s)r.push(i),i+=this.computeBlockSize(e);const a=[];for(let e=0;e<s.length;e++){const t=s[e];a.push({key:t[t.length-1].key,blockOffset:r[e],blockSize:this.computeBlockSize(t)})}const o=this.estimateIndexBlockSize(a),h=n.serialize(),c=h.byteLength,l=new ArrayBuffer(i+o+c+32),u=new DataView(l);let f=0;for(const e of s)f=this.writeDataBlock(u,f,e,n);const d=f;f=this.writeIndexBlock(u,f,a);const p=f;new Uint8Array(u.buffer).set(h,f),f+=c;const y=f;u.setUint32(y,d,!1),u.setUint32(y+4,o,!1),u.setUint32(y+8,p,!1),u.setUint32(y+12,c,!1),u.setUint32(y+16,n.getHashCount(),!1),u.setUint32(y+20,this.entries.length,!1),u.setUint32(y+24,G,!1),u.setUint32(y+28,0,!1);const m=new Uint8Array(l);let g=k(m.subarray(0,m.byteLength-4));return 0===g&&(g=1),u.setUint32(y+28,g,!1),{sstableData:new Uint8Array(l),indexEntries:a}}getEntryCount(){return this.entries.length}splitIntoBlocks(e){const t=[];let s=[];for(const n of e)s.push(n),this.computeBlockSize(s)>=this.blockSizeLimit&&s.length>1&&(t.push(s.slice(0,-1)),s=[n]);return s.length>0&&t.push(s),t}computeBlockSize(e){let t=4;for(const s of e)t+=4+s.keyBytes.length+4+s.valueBytes.length;return t}writeDataBlock(e,t,s,n){e.setUint32(t,s.length,!1),t+=4;for(const i of s){if(i.keyBytes.length>4294967295||i.valueBytes.length>4294967295)throw new Error("SSTable entry too large (exceeds u32 length field)");e.setUint32(t,i.keyBytes.length,!1),t+=4,new Uint8Array(e.buffer).set(i.keyBytes,t),t+=i.keyBytes.length,e.setUint32(t,i.valueBytes.length,!1),t+=4,new Uint8Array(e.buffer).set(i.valueBytes,t),t+=i.valueBytes.length,n.insert(i.key)}return t}estimateIndexBlockSize(e){let t=4;const s=new TextEncoder;for(const n of e)t+=4+s.encode(n.key).byteLength+8;return t}writeIndexBlock(e,t,s){e.setUint32(t,s.length,!1),t+=4;for(const n of s){const s=(new TextEncoder).encode(n.key);e.setUint32(t,s.length,!1),t+=4,new Uint8Array(e.buffer).set(s,t),t+=s.length,e.setUint32(t,n.blockOffset,!1),t+=4,e.setUint32(t,n.blockSize,!1),t+=4}return t}}class X{constructor(e,t){this.indexEntries=[],this.entryCount=0,this.bloomFilter=null,this.format=2,this.storedChecksum=0,this.data=e,this.view=new DataView(e.buffer,e.byteOffset,e.byteLength),this.meta=t,this.parseFooter()}verifyChecksum(){return 0===this.storedChecksum||!(this.data.byteLength<4)&&k(this.data.subarray(0,this.data.byteLength-4))===this.storedChecksum}lenFieldSize(){return 2===this.format?4:2}readLen(e){return 2===this.format?this.view.getUint32(e,!1):this.view.getUint16(e,!1)}get(e){if(this.bloomFilter&&!this.bloomFilter.mayContain(e))return null;const t=this.locateBlock(e);if(t<0)return null;const s=this.indexEntries[t],n=this.getBlockData(s);if(!n)return null;const i=new DataView(n.buffer,n.byteOffset,n.byteLength),r=this.lenFieldSize(),a=i.getUint32(0,!1);let o=4;for(let t=0;t<a&&!(o+r>n.byteLength);t++){const t=2===this.format?i.getUint32(o,!1):i.getUint16(o,!1);if(o+=r,o+t+r>n.byteLength)break;const s=(new TextDecoder).decode(n.slice(o,o+t));o+=t;const a=2===this.format?i.getUint32(o,!1):i.getUint16(o,!1);if(o+=r,o+a>n.byteLength)break;const h=n.slice(o,o+a);if(o+=a,s===e)try{return JSON.parse((new TextDecoder).decode(h))}catch{return null}}return null}rangeScan(e,t,s){if(0===this.indexEntries.length)return;const n=Math.max(0,this.locateBlockGE(e)),i=Math.min(this.indexEntries.length-1,this.locateBlockLE(t)+1);if(n<0||i<0||n>i)return;const r=this.lenFieldSize();for(let a=n;a<=i&&a>=0;a++){const n=this.indexEntries[a],i=this.getBlockData(n);if(!i)continue;const o=new DataView(i.buffer,i.byteOffset,i.byteLength),h=o.getUint32(0,!1);let c=4;for(let n=0;n<h&&!(c+r>i.byteLength);n++){const n=2===this.format?o.getUint32(c,!1):o.getUint16(c,!1);if(c+=r,c+n+r>i.byteLength)break;const a=(new TextDecoder).decode(i.slice(c,c+n));c+=n;const h=2===this.format?o.getUint32(c,!1):o.getUint16(c,!1);if(c+=r,c+h>i.byteLength)break;const l=i.slice(c,c+h);if(c+=h,a>=e&&a<=t)try{s(a,JSON.parse((new TextDecoder).decode(l)))}catch{}}}}scanAll(e){const t=this.lenFieldSize();for(const s of this.indexEntries){const n=this.getBlockData(s);if(!n)continue;const i=new DataView(n.buffer,n.byteOffset,n.byteLength),r=i.getUint32(0,!1);let a=4;for(let s=0;s<r&&!(a+t>n.byteLength);s++){const s=2===this.format?i.getUint32(a,!1):i.getUint16(a,!1);if(a+=t,a+s+t>n.byteLength)break;const r=(new TextDecoder).decode(n.slice(a,a+s));a+=s;const o=2===this.format?i.getUint32(a,!1):i.getUint16(a,!1);if(a+=t,a+o>n.byteLength)break;const h=n.slice(a,a+o);a+=o;try{e(r,JSON.parse((new TextDecoder).decode(h)))}catch{}}}}parseFooter(){if(this.data.byteLength<32)throw new Error("SSTable too small: missing footer");const e=this.data.byteLength-32,t=this.view.getUint32(e+24,!1);if(1397969986===t)this.format=1;else{if(t!==G)throw new Error(`Invalid SSTable magic: expected 1397969986 or 1397969987, got ${t}`);this.format=2}const s=this.view.getUint32(e,!1),n=this.view.getUint32(e+4,!1),i=this.view.getUint32(e+8,!1),r=this.view.getUint32(e+12,!1),a=this.view.getUint32(e+16,!1);if(this.entryCount=this.view.getUint32(e+20,!1),this.storedChecksum=this.view.getUint32(e+28,!1),!(s+4>this.data.byteLength||s+n>this.data.byteLength)&&(this.parseIndexBlock(s,n),i>0&&r>0&&i+r<=this.data.byteLength))try{const e=this.data.slice(i,i+r);this.bloomFilter=W.fromData(e,a||10)}catch{}}parseIndexBlock(e,t){const s=this.view.getUint32(e,!1);e+=4;const n=this.lenFieldSize();for(let t=0;t<s&&!(e+n>this.data.byteLength);t++){const t=this.readLen(e);if((e+=n)+t+8>this.data.byteLength)break;const s=(new TextDecoder).decode(this.data.slice(e,e+t));e+=t;const i=this.view.getUint32(e,!1);e+=4;const r=this.view.getUint32(e,!1);e+=4,0===r||i+r>this.data.byteLength||this.indexEntries.push({key:s,blockOffset:i,blockSize:r})}}getBlockData(e){return e.blockSize<=0||e.blockOffset<0||e.blockOffset+e.blockSize>this.data.byteLength?null:new Uint8Array(this.data.buffer,this.data.byteOffset+e.blockOffset,e.blockSize)}locateBlock(e){let t=0,s=this.indexEntries.length-1;for(;t<=s;){const n=Math.floor((t+s)/2);if(e<=this.indexEntries[n].key){if(e>(0===n?"":this.indexEntries[n-1].key))return n;s=n-1}else t=n+1}return-1}locateBlockGE(e){let t=0,s=this.indexEntries.length;for(;t<s;){const n=t+s>>1;this.indexEntries[n].key<e?t=n+1:s=n}return t<this.indexEntries.length?t:this.indexEntries.length-1}locateBlockLE(e){let t=0,s=this.indexEntries.length;for(;t<s;){const n=t+s>>1;this.indexEntries[n].key<=e?t=n+1:s=n}return t>0?t-1:0}}class Y{constructor(e){this.index=0,this.entries=e}next(){return this.index>=this.entries.length?null:this.entries[this.index++]}reset(){this.index=0}}class J{constructor(){this.heap=[]}push(e){this.heap.push(e),this.bubbleUp(this.heap.length-1)}pop(){if(0===this.heap.length)return null;if(1===this.heap.length)return this.heap.pop();const e=this.heap[0];return this.heap[0]=this.heap.pop(),this.bubbleDown(0),e}peek(){return this.heap.length>0?this.heap[0]:null}get size(){return this.heap.length}bubbleUp(e){for(;e>0;){const t=Math.floor((e-1)/2);if(this.heap[e].key>=this.heap[t].key)break;[this.heap[e],this.heap[t]]=[this.heap[t],this.heap[e]],e=t}}bubbleDown(e){const t=this.heap.length;for(;;){let s=e;const n=2*e+1,i=2*e+2;if(n<t&&this.heap[n].key<this.heap[s].key&&(s=n),i<t&&this.heap[i].key<this.heap[s].key&&(s=i),s===e)break;[this.heap[e],this.heap[s]]=[this.heap[s],this.heap[e]],e=s}}}class Q{constructor(){this.sources=[],this.heap=new J}addSource(e){this.sources.push(e),this.seedFromSource(this.sources.length-1)}next(){if(0===this.heap.size)return null;const e=this.heap.pop(),t=e.key;let s=e;for(this.seedFromSource(e.sourceIndex);this.heap.peek()&&this.heap.peek().key===t;){const e=this.heap.pop();this.seedFromSource(e.sourceIndex),e.sourceIndex<s.sourceIndex&&(s=e)}return[s.key,s.value]}drain(){const e=[];let t=this.next();for(;t;)e.push(t),t=this.next();return e}seedFromSource(e){const t=this.sources[e].next();t&&this.heap.push({key:t[0],value:t[1],sourceIndex:e})}}class Z{constructor(e){this.immutableMemtable=null,this.frozenMemtables=[],this.levels=[],this.sstableCache=new Map,this.cacheSize=0,this.operationCount=0,this.initialized=!1,this.compacting=!1,this.flushChain=Promise.resolve(),this.lastBackgroundError=null,this.memtableSizeThreshold=e.memtableSizeThreshold??P,this.memtable=new V(this.memtableSizeThreshold),this.levelSizeMultiplier=e.levelSizeMultiplier??10,this.blockSize=e.blockSize??4096,this.sstableStore=e.sstableStore,this.cacheLimitBytes=e.cacheLimitBytes??67108864;for(let e=0;e<7;e++)this.levels.push([])}async init(){if(this.initialized)return;const e=await this.sstableStore.listMeta(),t=[];for(const s of e)await this.validateSSTable(s)&&t.push(s);for(const e of t)e.level>=0&&e.level<7&&this.levels[e.level].push(e);for(let e=0;e<7;e++)this.levels[e].sort((e,t)=>t.id-e.id);this.initialized=!0}put(e,t){this.levels[0].length>=8&&this.enqueueCompact(0),this.memtable.put(e,t),this.operationCount++,this.memtable.shouldFlush()&&this.freezeMemtable()}delete(e){this.levels[0].length>=8&&this.enqueueCompact(0),this.memtable.put(e,{__tombstone:!0}),this.operationCount++,this.memtable.shouldFlush()&&this.freezeMemtable()}getEstimatedMemory(){let e=this.memtable.getEstimatedSize();for(const t of this.frozenMemtables)e+=t.getEstimatedSize();return e+=this.cacheSize,e}freezeMemtable(){if(this.immutableMemtable){const e=this.immutableMemtable;this.flushChain=this.enqueueOnChain(()=>this.flushImmutableAsync(e))}this.immutableMemtable=this.memtable,this.frozenMemtables.push(this.immutableMemtable),this.memtable=new V(this.memtableSizeThreshold)}enqueueOnChain(e){return this.flushChain.then(e).catch(e=>{this.lastBackgroundError=e})}async drainChain(){for(;;){const e=this.flushChain;if(await e,this.flushChain===e)return}}async flushImmutableAsync(e){const t=e.getAllEntries();if(0===t.length)return void(this.immutableMemtable===e&&(this.immutableMemtable=null));const s=await this.sstableStore.allocateId(),n=new H(this.blockSize);for(const[e,s]of t)n.add(e,s);const{sstableData:i,indexEntries:r}=n.build(),a={id:s,level:0,minKey:t[0][0],maxKey:t[t.length-1][0],blockCount:r.length,totalSize:i.byteLength,bloomData:null};this.cacheSSTable(s,i),this.trimCache(),await this.sstableStore.save(s,i),await this.sstableStore.saveMeta(a),this.immutableMemtable===e&&(this.immutableMemtable=null),this.levels[0].unshift(a),this.frozenMemtables=this.frozenMemtables.filter(t=>t!==e),this.levels[0].length>=4&&!this.compacting&&this.scheduleCompact(0)}scheduleCompact(e){e>=6||this.compacting||(this.compacting=!0,this.flushChain=this.enqueueOnChain(()=>this.compactLevelAsync(e).finally(()=>{this.compacting=!1,this.levels[e].length>=4&&this.scheduleCompact(e),e+1<6&&this.levels[e+1].length>=4&&this.scheduleCompact(e+1)})))}enqueueCompact(e){e>=6||this.compacting||(this.compacting=!0,this.flushChain=this.flushChain.then(async()=>{try{await this.compactLevelAsync(e)}finally{this.compacting=!1}}).catch(e=>{this.compacting=!1,this.lastBackgroundError=e}))}async prefetchRange(e,t){await this.drainChain(),this.trimCache();const s=[];for(let n=0;n<7;n++)for(const i of this.levels[n])t<i.minKey||e>i.maxKey||this.sstableCache.has(i.id)||s.push(i.id);for(const e of s){const t=this.findMetaById(e);await this.preloadSSTable(e,t)}}async prefetchKeys(e){if(0===e.length)return;await this.drainChain(),this.trimCache();const t=new Set;for(let s=0;s<7;s++)for(const n of this.levels[s])if(!this.sstableCache.has(n.id))for(const s of e)if(s>=n.minKey&&s<=n.maxKey){t.add(n.id);break}for(const e of t){const t=this.findMetaById(e);await this.preloadSSTable(e,t)}}async prefetchPrefixRanges(e){if(0===e.length)return;const t=new Set,s=[];for(const n of e){const e=`${n[0]}\0${n[1]}`;t.has(e)||(t.add(e),s.push(n))}if(0===s.length)return;await this.drainChain(),this.trimCache();const n=new Set;for(let e=0;e<7;e++)for(const t of this.levels[e])if(!this.sstableCache.has(t.id))for(const[e,i]of s)if(!(i<t.minKey||e>t.maxKey)){n.add(t.id);break}for(const e of n){const t=this.findMetaById(e);await this.preloadSSTable(e,t)}}findMetaById(e){for(let t=0;t<7;t++)for(const s of this.levels[t])if(s.id===e)return s}get(e){let t=this.memtable.get(e);if(null!==t)return this.unwrapTombstone(t);for(let s=this.frozenMemtables.length-1;s>=0;s--)if(t=this.frozenMemtables[s].get(e),null!==t)return this.unwrapTombstone(t);for(let t=0;t<7;t++)for(const s of this.levels[t]){if(e<s.minKey||e>s.maxKey)continue;const t=this.loadSSTableReader(s);if(!t)continue;const n=t.get(e);if(null!==n)return this.unwrapTombstone(n)}return null}rangeScan(e,t){const s=[];return this.rangeScanLazy(e,t,(e,t)=>s.push([e,t])),s}rangeScanLazy(e,t,s){const n=new Q;n.addSource(new Y(this.memtable.rangeScan(e,t)));for(let s=this.frozenMemtables.length-1;s>=0;s--)n.addSource(new Y(this.frozenMemtables[s].rangeScan(e,t)));for(let s=0;s<7;s++)for(const i of this.levels[s]){if(t<i.minKey||e>i.maxKey)continue;const s=this.loadSSTableReader(i);s&&s.rangeScan(e,t,(e,t)=>{n.addSource(new Y([[e,t]]))})}const i=n.drain();for(const[e,t]of i)t.__tombstone||s(e,t)}getAllEntries(){const e=new Map;for(let t=6;t>=0;t--)for(let s=this.levels[t].length-1;s>=0;s--){const n=this.levels[t][s],i=this.loadSSTableReader(n);i&&i.scanAll((t,s)=>e.set(t,s))}for(const[t,s]of this.memtable.getAllEntries())e.set(t,s);for(let t=this.frozenMemtables.length-1;t>=0;t--)for(const[s,n]of this.frozenMemtables[t].getAllEntries())e.set(s,n);return Array.from(e.entries()).filter(([,e])=>!e.__tombstone)}async compactLevel(e){await this.compactLevelAsync(e,2)}async compactLevelAsync(e,t=4){if(e>=6)return;if(this.levels[e].length<t)return;const s=this.levels[e].splice(0,this.levels[e].length),n=new Q,i=[];for(const e of s){let t,s=this.sstableCache.get(e.id)??null;if(!s)try{s=await this.sstableStore.load(e.id)}catch{s=null}if(!s||s.byteLength<32){await this.dropInvalidSSTable(e);continue}try{if(t=new X(s,e),!t.verifyChecksum()){await this.dropInvalidSSTable(e);continue}}catch{await this.dropInvalidSSTable(e);continue}const r=[];t.scanAll((e,t)=>r.push([e,t])),n.addSource(new Y(r)),i.push(e)}const r=n.drain();if(0===r.length){for(const t of i)this.levels[e].push(t);return void this.levels[e].sort((e,t)=>t.id-e.id)}const a=await this.sstableStore.allocateId(),o=new H(this.blockSize);for(const[e,t]of r)o.add(e,t);const{sstableData:h,indexEntries:c}=o.build(),l={id:a,level:e+1,minKey:r[0][0],maxKey:r[r.length-1][0],blockCount:c.length,totalSize:h.byteLength,bloomData:null};this.cacheSSTable(a,h),this.trimCache(),await this.sstableStore.save(a,h),await this.sstableStore.saveMeta(l),this.levels[e+1].unshift(l);for(const e of s)this.sstableCache.delete(e.id),await this.sstableStore.delete(e.id),await this.sstableStore.deleteMeta(e.id)}async flush(){if(null!==this.lastBackgroundError){const e=this.lastBackgroundError;throw this.lastBackgroundError=null,new n("AriaEngine background flush/compaction failed (data may be inconsistent)","ARIA_BACKGROUND_ERROR",e)}if(await this.drainChain(),this.immutableMemtable){const e=this.immutableMemtable;this.flushChain=this.enqueueOnChain(()=>this.flushImmutableAsync(e)),this.immutableMemtable=null}if(this.memtable.getEntryCount()>0){this.freezeMemtable();const e=this.immutableMemtable;e&&(this.flushChain=this.enqueueOnChain(()=>this.flushImmutableAsync(e)),this.immutableMemtable=null)}await this.drainChain(),this.frozenMemtables=this.frozenMemtables.filter(e=>e.getEntryCount()>0)}async clear(){await this.drainChain(),this.memtable.clear(),this.immutableMemtable=null,this.frozenMemtables=[];for(const e of this.levels)for(const t of e)this.sstableCache.delete(t.id),this.sstableStore.delete(t.id).catch(()=>{}),this.sstableStore.deleteMeta(t.id).catch(()=>{});this.levels=[];for(let e=0;e<7;e++)this.levels.push([]);this.sstableCache.clear(),this.cacheSize=0}getStats(){return{memtableSize:this.memtable.getEntryCount(),sstableCount:this.levels.reduce((e,t)=>e+t.length,0),levelCounts:this.levels.map(e=>e.length)}}async validateAll(){let e=0;for(let t=0;t<7;t++){const s=[];for(const n of this.levels[t])await this.validateSSTable(n)?s.push(n):(this.sstableCache.delete(n.id),e++);this.levels[t]=s}return e}async validateSSTable(e){try{const t=await this.sstableStore.load(e.id);if(!t)return this.dropInvalidSSTable(e),!1;if(t.byteLength<32)return this.dropInvalidSSTable(e),!1;try{if(!new X(t,e).verifyChecksum())return this.dropInvalidSSTable(e),!1}catch{return this.dropInvalidSSTable(e),!1}return!0}catch{return this.dropInvalidSSTable(e),!1}}async dropInvalidSSTable(e){try{await this.sstableStore.delete(e.id)}catch{}try{await this.sstableStore.deleteMeta(e.id)}catch{}}unwrapTombstone(e){return e?e.__tombstone?null:e:null}loadSSTableReader(e){const t=this.sstableCache.get(e.id);if(!t)return null;this.sstableCache.delete(e.id),this.sstableCache.set(e.id,t);try{return new X(t,e)}catch{return null}}async preloadSSTable(e,t){if(this.sstableCache.has(e))return;const s=await this.sstableStore.load(e);if(s){if(t)try{if(!new X(s,t).verifyChecksum())return void await this.dropInvalidSSTable(t)}catch{return void await this.dropInvalidSSTable(t)}this.cacheSSTable(e,s)}}cacheSSTable(e,t){this.sstableCache.has(e)&&(this.cacheSize-=this.sstableCache.get(e).byteLength,this.sstableCache.delete(e)),this.sstableCache.set(e,t),this.cacheSize+=t.byteLength}trimCache(){for(;this.cacheSize>this.cacheLimitBytes&&this.sstableCache.size>0;){const e=this.sstableCache.keys().next().value,t=this.sstableCache.get(e);this.cacheSize-=t.byteLength,this.sstableCache.delete(e)}}}class ee{constructor(e,t=!0,s="batch"){this.lsn=0,this.buffer=[],this.bufferedBytes=0,this.store=e,this.enabled=t,this.syncMode=s}async append(e){if(!this.enabled)return;this.lsn++;const t={...e,lsn:this.lsn,checksum:0},s=this.encodeRecord(t);"full"===this.syncMode?(await this.store.append(s),this.bufferedBytes+=s.byteLength):"batch"===this.syncMode&&(this.buffer.push(s),this.bufferedBytes+=s.byteLength)}async appendBatch(e){if(!this.enabled||0===e.length)return;const t=[];for(const s of e)this.lsn++,t.push(this.encodeRecord({...s,lsn:this.lsn,checksum:0}));const s=this.mergeChunks(t);"full"===this.syncMode?(await this.store.append(s),this.bufferedBytes+=s.byteLength):"batch"===this.syncMode&&(this.buffer.push(s),this.bufferedBytes+=s.byteLength)}async flush(){if(!this.enabled||0===this.buffer.length)return;const e=this.mergeChunks(this.buffer);await this.store.append(e),this.buffer=[]}mergeChunks(e){if(1===e.length)return e[0];const t=e.reduce((e,t)=>e+t.byteLength,0),s=new Uint8Array(t);let n=0;for(const t of e)s.set(t,n),n+=t.byteLength;return s}async recover(e){if(!this.enabled)return 0;if(!await this.store.exists())return 0;const t=await this.store.readAll();if(0===t.byteLength)return 0;const s=this.decodeAllRecords(t);for(const t of s)e(t);return this.lsn=s.length>0?s[s.length-1].lsn:0,s.length}async checkpoint(){this.enabled&&(await this.flush(),await this.store.truncate(),this.lsn=0,this.bufferedBytes=0)}getBufferedCount(){return this.buffer.length}getBufferedBytes(){return this.bufferedBytes}legacyChecksum(e){let t=0;for(let s=0;s<e.length;s++)t=(t<<5)-t+e[s]|0;return t>>>0}encodeRecord(e){const t=new TextEncoder,s=t.encode(e.tableName),n=t.encode(e.key),i=e.data?JSON.stringify(e.data):"",r=t.encode(i),a=11+s.length+2+n.length+4+r.length+4,o=new ArrayBuffer(a),h=new DataView(o);let c=0;h.setUint32(c,e.lsn,!1),c+=4,h.setUint8(c,e.type),c+=1,h.setUint32(c,e.txnId,!1),c+=4,h.setUint16(c,s.length,!1),c+=2,new Uint8Array(o).set(s,c),c+=s.length,h.setUint16(c,n.length,!1),c+=2,new Uint8Array(o).set(n,c),c+=n.length,h.setUint32(c,r.length,!1),c+=4,new Uint8Array(o).set(r,c),c+=r.length;const l=k(new Uint8Array(o,0,c));return h.setUint32(c,l,!1),new Uint8Array(o)}decodeAllRecords(e){const t=[],s=new DataView(e.buffer,e.byteOffset,e.byteLength);let n=0;for(;n+15<=e.byteLength;)try{const i=n,r=s.getUint32(n,!1);n+=4;const a=s.getUint8(n);n+=1;const o=s.getUint32(n,!1);n+=4;const h=s.getUint16(n,!1);if(n+=2,n+h>e.byteLength)break;const c=(new TextDecoder).decode(e.slice(n,n+h));n+=h;const l=s.getUint16(n,!1);if(n+=2,n+l>e.byteLength)break;const u=(new TextDecoder).decode(e.slice(n,n+l));n+=l;const f=s.getUint32(n,!1);if(n+=4,n+f>e.byteLength)break;let d;if(f>0){const t=(new TextDecoder).decode(e.slice(n,n+f));try{d=JSON.parse(t)}catch{}}n+=f;const p=s.getUint32(n,!1);n+=4;const y=e.slice(i,n-4),m=k(y),g=this.legacyChecksum(y);if(m>>>0!==p&&g>>>0!==p)continue;t.push({lsn:r,type:a,txnId:o,tableName:c,key:u,data:d,checksum:p})}catch{break}return t}}const te="__wal_",se=/^__wal_(\d{6})\.bin$/,ne=/^__wal_(\d+)$/,ie="__wal_count";class re{constructor(e,t=4194304){this.backend=e,this.currentSegment=0,this.currentSize=0,this.segmentSize=t}segmentKey(e){return`${te}${String(e).padStart(6,"0")}.bin`}async append(e){if(0===e.byteLength)return;this.currentSize+e.byteLength>this.segmentSize&&(this.currentSegment++,this.currentSize=0);const t=this.segmentKey(this.currentSegment),s=e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength);if("function"==typeof this.backend.append)await this.backend.append(t,s);else{const e=await this.backend.read(t);if(e){const n=new ArrayBuffer(e.byteLength+s.byteLength);new Uint8Array(n).set(new Uint8Array(e),0),new Uint8Array(n).set(new Uint8Array(s),e.byteLength),await this.backend.write(t,n)}else await this.backend.write(t,s)}this.currentSize+=e.byteLength}async readAll(){const e=await this.backend.listKeys(),t=e.filter(e=>se.test(e)).map(e=>({seq:Number(e.match(se)[1]),key:e})).sort((e,t)=>e.seq-t.seq);let s=0;for(let e=0;e<t.length&&t[e].seq===e;e++)s=e+1;const n=t.slice(0,s),i=e.filter(e=>ne.test(e)).map(e=>({seq:Number(e.match(ne)[1]),key:e})).sort((e,t)=>e.seq-t.seq),r=[];for(const{key:e}of i){const t=await this.backend.read(e);t&&r.push(new Uint8Array(t))}for(const{key:e}of n){const t=await this.backend.read(e);t&&r.push(new Uint8Array(t))}if(n.length>0){this.currentSegment=n[n.length-1].seq;const e=await this.backend.read(n[n.length-1].key);this.currentSize=e?e.byteLength:0,i.length>0&&(this.currentSegment++,this.currentSize=0)}else i.length>0&&(this.currentSegment=0,this.currentSize=0);const a=r.reduce((e,t)=>e+t.byteLength,0),o=new Uint8Array(a);let h=0;for(const e of r)o.set(e,h),h+=e.byteLength;return o}async truncate(){const e=(await this.backend.listKeys()).filter(e=>e.startsWith(te)||e===ie);e.length>0&&await this.backend.deleteMany(e),this.currentSegment=0,this.currentSize=0}async exists(){return(await this.backend.listKeys()).some(e=>e.startsWith(te)||e===ie)}}class ae{constructor(){this.acquired=!1,this.supported=!1,this.releaseResolve=null,this.releasePromise=null}async acquire(e){const t=globalThis.navigator,s=t?.locks;return s&&"function"==typeof s.request?(this.supported=!0,await new Promise((t,i)=>{s.request.bind(s)(function(e){return`metona-sqlark:${e}`}(e),{ifAvailable:!0,mode:"exclusive"},async s=>{if(!s)return void i(new n(`Database "${e}" is already open in another tab (locked)`,"ARIA_LOCKED"));this.acquired=!0;const r=new Promise(e=>{this.releaseResolve=e});this.releasePromise=r,t(),await r})}),!0):(this.supported=!1,!1)}async release(){if(this.acquired){if(this.releaseResolve){const e=this.releaseResolve,t=this.releasePromise;this.releaseResolve=null,this.releasePromise=null,e();try{await t}catch{}}this.acquired=!1}}isAcquired(){return this.acquired}isSupported(){return this.supported}}class oe{constructor(e,t,s=null,n=1e3,i=16777216){this.opCount=0,this.lsm=e,this.wal=t,this.flushable=s,this.interval=n,this.walSizeThreshold=i}async tick(){this.opCount++,(this.opCount>=this.interval||this.getWALEstimatedSize()>=this.walSizeThreshold)&&await this.checkpoint()}getWALEstimatedSize(){const e=this.wal;if("function"==typeof e.getBufferedBytes){const t=e.getBufferedBytes();if(t>0)return t}return 200*("function"==typeof e.getBufferedCount?e.getBufferedCount():0)}async checkpoint(){await this.lsm.flush(),this.flushable&&await this.flushable.flushAll(),await this.wal.checkpoint(),this.opCount=0}}class he{constructor(){this.store=new Map,this.opened=!1}async open(e){this.opened=!0}async close(){this.store.clear(),this.opened=!1}isOpen(){return this.opened}async read(e){return this.store.get(e)??null}async write(e,t){this.store.set(e,t)}async writeMany(e){for(const[t,s]of Object.entries(e))this.store.set(t,s)}async delete(e){this.store.delete(e)}async deleteMany(e){for(const t of e)this.store.delete(t)}async listKeys(){return Array.from(this.store.keys())}async exists(e){return this.store.has(e)}async clear(){this.store.clear()}}class ce{constructor(e,t){this.kv=new N(e,t)}getKV(){return this.kv}async open(e){await this.kv.open(e)}async close(){await this.kv.close()}isOpen(){return this.kv.isOpen()}async read(e){return this.kv.get(e)}async write(e,t){await this.kv.put(e,t)}async append(e,t){await this.kv.appendValue(e,t)}async writeMany(e){await this.kv.putMany(e)}async delete(e){await this.kv.delete(e)}async deleteMany(e){await this.kv.deleteMany(e)}async listKeys(){return this.kv.listKeys()}async exists(e){return this.kv.exists(e)}async clear(){await this.kv.clear()}}const le="AES-GCM";class ue{constructor(){this.cryptoKey=null,this._enabled=!1}get enabled(){return this._enabled}async init(e,t){const s=new TextEncoder,n=await crypto.subtle.importKey("raw",s.encode(e),"PBKDF2",!1,["deriveKey"]),i=t||crypto.getRandomValues(new Uint8Array(16));return this.cryptoKey=await crypto.subtle.deriveKey({name:"PBKDF2",salt:i,iterations:1e5,hash:"SHA-256"},n,{name:le,length:256},!1,["encrypt","decrypt"]),this._enabled=!0,i}async encryptPage(e){if(!this.cryptoKey)throw new Error("Crypto not initialized");const t=crypto.getRandomValues(new Uint8Array(12)),s=e instanceof Uint8Array?e:new Uint8Array(e);return{iv:t,data:await crypto.subtle.encrypt({name:le,iv:t},this.cryptoKey,s)}}async decryptPage(e,t){if(!this.cryptoKey)throw new Error("Crypto not initialized");const s=t instanceof Uint8Array?t:new Uint8Array(t);return crypto.subtle.decrypt({name:le,iv:e},this.cryptoKey,s)}close(){this.cryptoKey=null,this._enabled=!1}}const fe=12,de="__aria_keymeta";function pe(e){if("undefined"!=typeof Buffer)return Buffer.from(e).toString("base64");let t="";for(let s=0;s<e.byteLength;s++)t+=String.fromCharCode(e[s]);return btoa(t)}function ye(e){if("undefined"!=typeof Buffer)return new Uint8Array(Buffer.from(e,"base64"));const t=atob(e),s=new Uint8Array(t.length);for(let e=0;e<t.length;e++)s[e]=t.charCodeAt(e);return s}class me{constructor(e,t){if(this.inner=e,this.password=t,this.crypto=new ue,this.opened=!1,!t||0===t.length)throw new n("Encryption password must not be empty","ARIA_ENCRYPT_CONFIG_ERROR")}getInner(){return this.inner}isCryptoReady(){return this.crypto.enabled}async open(e){this.inner.isOpen()||await this.inner.open(e);const t=await this.inner.read(de);if(t){let e;try{e=JSON.parse((new TextDecoder).decode(t))}catch{throw new n("Corrupted encryption key metadata","ARIA_DECRYPT_ERROR")}if(!e.salt||!e.verifier)throw new n("Corrupted encryption key metadata","ARIA_DECRYPT_ERROR");const s=ye(e.salt);await this.crypto.init(this.password,s);const i=ye(e.verifier);if(i.byteLength<=fe)throw new n("Corrupted encryption key metadata","ARIA_DECRYPT_ERROR");const r=i.subarray(0,fe),a=i.subarray(fe);try{await this.crypto.decryptPage(r,a)}catch{throw new n("Decryption failed: wrong password or corrupted key metadata","ARIA_DECRYPT_ERROR")}}else{if((await this.inner.listKeys()).some(e=>e!==de))throw new n("Cannot open with encryption: existing database has no key metadata (database was created without encryption, or key metadata was lost)","ARIA_ENCRYPT_CONFIG_ERROR");const e=await this.crypto.init(this.password),t=await this.crypto.encryptPage((new TextEncoder).encode("metona-sqlark-encryption-verifier").buffer),s=new Uint8Array(fe+t.data.byteLength);s.set(t.iv,0),s.set(new Uint8Array(t.data),fe);const i=JSON.stringify({salt:pe(e),verifier:pe(s)});await this.inner.write(de,(new TextEncoder).encode(i).buffer)}this.opened=!0}async close(){await this.inner.close(),this.crypto.close(),this.opened=!1}isOpen(){return this.opened}async read(e){this.ensureReady();const t=await this.inner.read(e);return null===t?null:this.decrypt(t)}async write(e,t){this.ensureReady(),await this.inner.write(e,await this.encrypt(t))}async writeMany(e){this.ensureReady();const t={};for(const[s,n]of Object.entries(e))t[s]=await this.encrypt(n);await this.inner.writeMany(t)}async delete(e){this.ensureReady(),await this.inner.delete(e)}async deleteMany(e){this.ensureReady(),await this.inner.deleteMany(e)}async listKeys(){return this.ensureReady(),this.inner.listKeys()}async exists(e){return this.ensureReady(),this.inner.exists(e)}async clear(){const e=(await this.inner.listKeys()).filter(e=>e!==de);e.length>0&&await this.inner.deleteMany(e)}ensureReady(){if(!this.opened)throw new n("EncryptedBackend not opened","ARIA_DB_NOT_OPEN");if(!this.crypto.enabled)throw new n("EncryptedBackend key not initialized","ARIA_DECRYPT_ERROR")}async encrypt(e){const t=await this.crypto.encryptPage(e),s=new ArrayBuffer(fe+t.data.byteLength),n=new Uint8Array(s);return n.set(t.iv,0),n.set(new Uint8Array(t.data),fe),s}async decrypt(e){const t=new Uint8Array(e);if(t.byteLength<=fe)throw new n("Corrupted encrypted data block (too short)","ARIA_DECRYPT_ERROR");const s=t.subarray(0,fe),i=t.subarray(fe);try{return await this.crypto.decryptPage(s,i)}catch(e){if(e instanceof n)throw e;throw new n("Decryption failed (data corrupted or wrong key)","ARIA_DECRYPT_ERROR",e)}}}class ge{constructor(e,t){this.fileManager=e,this.bufferPool=t,this.pageIds=new Map}async save(e,t){const s=Math.max(1,Math.ceil(t.byteLength/_)),n=await this.bufferPool.newPages(s,M.DATA),i=[];for(let e=0;e<s;e++){const s=n[e];i.push(s.pageId);const r=new Uint8Array(s.data);r.fill(0);const a=t.subarray(e*_,Math.min((e+1)*_,t.byteLength));r.set(a,0),s.dirty=!0,await this.bufferPool.flushPage(s.pageId),this.bufferPool.unpin(s)}this.pageIds.set(e,i)}getPageIds(e){return this.pageIds.get(e)}async load(e,t,s){if(0===t.length)return null;const n=[];for(const e of t){const t=await this.bufferPool.getPage(e);if(!t)return null;n.push(new Uint8Array(t.data)),this.bufferPool.unpin(t)}const i=n.reduce((e,t)=>e+t.byteLength,0),r=new Uint8Array(Math.min(i,s));let a=0;for(const e of n){const t=Math.min(e.byteLength,r.byteLength-a);if(t<=0)break;r.set(e.subarray(0,t),a),a+=t}return this.pageIds.delete(e),r}async delete(e,t){for(const e of t){this.bufferPool.removePage(e);try{await this.fileManager.freePageId(e)}catch{}}this.pageIds.delete(e)}}class we{constructor(e){this.nextPageId=0,this.metaLoaded=!1,this.dbName="",this.backend=e}async init(e){this.dbName=e;const t=await this.backend.read("__aria_meta");let s=1;t&&t instanceof ArrayBuffer&&t.byteLength>=4&&(s=new DataView(t).getUint32(0,!1));const n=await this.backend.listKeys();for(const e of n)if(e.startsWith("pg_")){const t=Number.parseInt(e.slice(3),10);!Number.isNaN(t)&&t+1>s&&(s=t+1)}this.nextPageId=s,t&&t instanceof ArrayBuffer&&!(t.byteLength<4)&&s===new DataView(t).getUint32(0,!1)||await this.saveMeta(),this.metaLoaded=!0}async readPage(e){const t=`pg_${e}`,s=await this.backend.read(t);if(!s)return null;if(s.byteLength<_){const e=new ArrayBuffer(_);return new Uint8Array(e).set(new Uint8Array(s)),e}return s}async writePage(e,t){const s=`pg_${e}`;await this.backend.write(s,t)}async allocatePageId(){const e=this.nextPageId++;return await this.saveMeta(),e}async allocatePageIds(e){if(e<=0)return[];const t=[],s=this.nextPageId;this.nextPageId+=e;for(let n=0;n<e;n++)t.push(s+n);return await this.saveMeta(),t}async freePageId(e){const t=`pg_${e}`;await this.backend.delete(t)}async saveMeta(){const e=new ArrayBuffer(8);new DataView(e).setUint32(0,this.nextPageId,!1),await this.backend.write("__aria_meta",e)}async clearAll(){await this.backend.clear(),this.nextPageId=1,await this.saveMeta()}}class be{constructor(){this.versionStore=new Map,this.activeTxns=new Map,this.nextTxnId=1,this.globalCommitLsn=0,this.txnWriteKeys=new Map}beginTransaction(){const e=this.nextTxnId++;return this.activeTxns.set(e,{txnId:e,state:K.ACTIVE,snapshotLsn:this.globalCommitLsn,startTime:Date.now()}),this.txnWriteKeys.set(e,new Set),e}commitTransaction(e){const t=this.activeTxns.get(e);if(!t)throw new Error(`Transaction ${e} not found`);t.state=K.COMMITTED,this.globalCommitLsn++;const s=this.txnWriteKeys.get(e);if(s)for(const t of s){const s=this.versionStore.get(t);if(!s)continue;const n=s.filter(t=>t.txnId!==e);0===n.length?this.versionStore.delete(t):this.versionStore.set(t,n)}this.activeTxns.delete(e),this.txnWriteKeys.delete(e)}rollbackTransaction(e){const t=this.activeTxns.get(e);if(!t)throw new Error(`Transaction ${e} not found`);t.state=K.ABORTED;const s=this.txnWriteKeys.get(e);if(s)for(const t of s){const s=this.versionStore.get(t);if(!s)continue;const n=s.filter(t=>t.txnId!==e);0===n.length?this.versionStore.delete(t):this.versionStore.set(t,n)}this.activeTxns.delete(e),this.txnWriteKeys.delete(e)}writeVersion(e,t,s,n){const i=`${e}.${t}`,r=this.versionStore.get(i)??[],a={txnId:n,data:s,prevVersion:r.length>0?r[r.length-1]:null,committed:!1};r.push(a),this.versionStore.set(i,r),this.txnWriteKeys.get(n)?.add(i)}deleteVersion(e,t,s){this.writeVersion(e,t,{__mvcc_tombstone:!0},s)}discardVersions(e){const t=this.txnWriteKeys.get(e);if(t)for(const s of t){const t=this.versionStore.get(s);if(!t)continue;const n=t.filter(t=>t.txnId!==e);0===n.length?this.versionStore.delete(s):this.versionStore.set(s,n)}}gc(e=100){for(const[t,s]of this.versionStore){if(s.length<=e)continue;const n=s.slice(s.length-e);this.versionStore.set(t,n)}}getGlobalLSN(){return this.globalCommitLsn}}function Te(e,t){const s=new ArrayBuffer(_);return function(e,t,s){const n=new DataView(e);n.setUint32(0,t,!1),n.setUint8(4,s),n.setUint16(5,16,!1),n.setUint16(7,e.byteLength,!1),n.setUint16(9,0,!1),n.setUint32(11,0,!1),n.setUint8(15,0)}(s,e,t),{pageId:e,type:t,data:s,dirty:!0,pins:0,prev:null,next:null,lastAccess:Date.now()}}class Ee{constructor(){this.head=null,this.tail=null,this._size=0}get size(){return this._size}moveToHead(e){this.head!==e&&(null!==e.prev||null!==e.next||this.head===e||this.tail===e?this.detach(e):this._size++,e.prev=null,e.next=this.head,this.head&&(this.head.prev=e),this.head=e,this.tail||(this.tail=e))}remove(e){(null!==e.prev||null!==e.next||this.head===e||this.tail===e)&&(this.detach(e),this._size=Math.max(0,this._size-1))}detach(e){e.prev?e.prev.next=e.next:this.head===e&&(this.head=e.next),e.next?e.next.prev=e.prev:this.tail===e&&(this.tail=e.prev),e.prev=null,e.next=null}clear(){this.head=null,this.tail=null,this._size=0}getLRU(){return this.tail}}class ke{constructor(e,t,s){this.lru=new Ee,this.capacity=e,this.onEvict=t,this.onRemove=s}access(e){e.lastAccess=Date.now(),this.lru.moveToHead(e)}add(e){this.access(e)}remove(e){this.lru.remove(e)}async evictIfNeeded(e){let t=0;for(;this.lru.size+e>this.capacity&&this.lru.size>0;){const e=this.findEvictionCandidate();if(!e)break;e.dirty&&(await this.onEvict(e),e.dirty=!1),this.lru.remove(e),this.onRemove?.(e),t++}return t}findEvictionCandidate(){let e=this.lru.getLRU();for(;e;){if(0===e.pins&&!e.dirty)return e;e=e.prev}for(e=this.lru.getLRU();e;){if(0===e.pins)return e;e=e.prev}return null}clear(){this.lru.clear()}}class xe{constructor(e,t=256){this.pages=new Map,this.nextPageId=0,this.pageIO=e,this.eviction=new ke(t,async e=>{e.dirty&&(await this.pageIO.writePage(e.pageId,e.data),e.dirty=!1)},e=>{this.pages.delete(e.pageId)})}async getPage(e){let t=this.pages.get(e);if(t)return this.eviction.access(t),t.pins++,t;const s=await this.pageIO.readPage(e);return s?(await this.eviction.evictIfNeeded(1),t={pageId:e,type:new DataView(s).getUint8(4),data:s,dirty:!1,pins:1,prev:null,next:null,lastAccess:Date.now()},this.pages.set(e,t),this.eviction.add(t),t):null}async newPages(e,t=M.DATA){if(e<=0)return[];let s;if("function"==typeof this.pageIO.allocatePageIds)s=await this.pageIO.allocatePageIds(e);else{s=[];for(let t=0;t<e;t++)s.push(await this.pageIO.allocatePageId())}await this.eviction.evictIfNeeded(e);const n=[];for(const e of s){const s=Te(e,t);s.pins=1,this.pages.set(e,s),this.eviction.add(s),n.push(s)}return n}unpin(e){e.pins>0&&e.pins--}markDirty(e){e.dirty=!0}async flushPage(e){const t=this.pages.get(e);t&&t.dirty&&(await this.pageIO.writePage(e,t.data),t.dirty=!1)}async flushAll(){for(const[,e]of this.pages)e.dirty&&(await this.pageIO.writePage(e.pageId,e.data),e.dirty=!1)}removePage(e){const t=this.pages.get(e);t&&(this.eviction.remove(t),this.pages.delete(e))}async clear(){await this.flushAll(),this.pages.clear(),this.eviction.clear()}}class Se{constructor(e={}){this.name="aria",this.opened=!1,this.dbName="",this.dbLock=null,this.schemas=new Map,this.tablePKs=new Map,this.opCounter=0,this.secondaryIndexes=new Map,this.mvcc=new be,this.currentTxnId=null,this.txnSnapshot=null,this.gcCounter=0,this.savepoints=new Map,this.config={...z,...e}}async open(e,t){if(!this.opened)try{await this.openInternal(e)}catch(t){if(this.dbLock){try{await this.dbLock.release()}catch{}this.dbLock=null}if(t instanceof n)throw t;throw new n(`Failed to open AriaEngine database "${e}"`,"ARIA_OPEN_ERROR",t)}}async openInternal(e){this.dbName=e;const t=new ae;let s;if(this.dbLock=t,await t.acquire(e),s="opfs"===this.config.storageBackend?new g:"kv"===this.config.storageBackend?new ce:new he,await s.open(e),this.config.encryption?.password)this.backend=new me(s,this.config.encryption.password);else if(this.backend=s,await s.exists("__aria_keymeta"))throw await s.close(),new n("Database is encrypted: provide encryption.password to open it","ARIA_ENCRYPT_REQUIRED");await this.backend.open(e),this.fileManager=new we(this.backend),await this.fileManager.init(e),this.bufferPool=new xe(this.fileManager,this.config.bufferPoolPages);const i=this.createSSTableStore("main");this.lsm=new Z({memtableSizeThreshold:this.config.memtableSizeThreshold,levelSizeMultiplier:this.config.levelSizeMultiplier,blockSize:this.config.pageSize,bloomBitsPerKey:this.config.bloomFilterBitsPerKey,cacheLimitBytes:this.config.bufferPoolPages*this.config.pageSize,sstableStore:i}),this.wal=new ee(new re(this.backend),this.config.walEnabled,this.config.walSyncMode),await this.loadSchemas();for(const[e,t]of this.schemas){const s=this.tablePKs.get(e);for(const[n,i]of Object.entries(t.columns))if((i.index||i.unique)&&n!==s){const t=`${e}:idx:${n}`;if(!this.secondaryIndexes.has(t)){const s=new Z({memtableSizeThreshold:this.config.memtableSizeThreshold,levelSizeMultiplier:this.config.levelSizeMultiplier,blockSize:this.config.pageSize,bloomBitsPerKey:this.config.bloomFilterBitsPerKey,cacheLimitBytes:this.config.bufferPoolPages*this.config.pageSize,sstableStore:this.createSSTableStore(`idx_${e}_${n}`)});await s.init(),this.secondaryIndexes.set(t,s)}}}await this.lsm.init();const r=new Set,a=[];await this.wal.recover(e=>a.push(e));for(const e of a)e.type===B.COMMIT&&r.add(e.txnId),e.type===B.ROLLBACK&&r.delete(e.txnId);for(const e of a)(0===e.txnId||r.has(e.txnId))&&(e.type===B.DROP_TABLE?await this.applyDropTableRecovery(e.tableName):this.applyWALRecord(e));if(a.length>0){await this.lsm.flush(),await this.wal.checkpoint();for(const e of this.schemas.keys())await this.reindexTableInternal(e)}this.checkpointManager=new oe(this.lsm,{checkpoint:async()=>{this.currentTxnId||await this.wal.checkpoint()},flush:async()=>{this.currentTxnId||await this.wal.flush()},getBufferedBytes:()=>this.wal.getBufferedBytes(),getBufferedCount:()=>this.wal.getBufferedCount()},{flushAll:async()=>{await this.lsm.flush();for(const e of this.secondaryIndexes.values())await e.flush()}},this.config.checkpointInterval,this.config.walSizeThreshold),this.opened=!0}async close(){if(this.opened){await this.persistSchemas(),await this.lsm.flush();for(const e of this.secondaryIndexes.values())await e.flush();await this.bufferPool.flushAll(),await this.wal.flush(),await this.wal.checkpoint(),await this.backend.close(),this.dbLock&&(await this.dbLock.release(),this.dbLock=null),this.schemas.clear(),this.tablePKs.clear(),this.secondaryIndexes.clear(),this.mvcc=new be,this.currentTxnId=null,this.txnSnapshot=null,this.savepoints.clear(),this.opCounter=0,this.opened=!1}}async repair(){this.ensureOpen(),await this.bufferPool.clear(),await this.lsm.validateAll(),await this.lsm.flush(),await this.wal.checkpoint();for(const e of this.schemas.keys())await this.reindexTable(e);const e=this.backend;if("function"==typeof e.cleanupStaleFiles)try{await e.cleanupStaleFiles()}catch{}await this.cleanupOrphanPages()}async cleanupOrphanPages(){const e=(await this.backend.listKeys()).filter(e=>/^pg_\d+$/.test(e));if(0===e.length)return;const t=new Set,s=async e=>{const s="main"===e?"__aria_lsm_meta":`__aria_lsm_meta_${e}`,n=await this.backend.read(s);if(n)try{const e=JSON.parse((new TextDecoder).decode(n));for(const s of e)if(s.pageIds)for(const e of s.pageIds)t.add(e)}catch{}};await s("main");for(const[e,t]of this.schemas)for(const[n,i]of Object.entries(t.columns))(i.index||i.unique)&&await s(`idx_${e}_${n}`);const n=e.map(e=>Number(e.slice(3))).filter(e=>!t.has(e));n.length>0&&await this.backend.deleteMany(n.map(e=>`pg_${e}`))}async clearAll(){this.ensureOpen(),await this.backend.clear(),await this.bufferPool.clear(),await this.fileManager.clearAll(),this.schemas.clear(),this.tablePKs.clear(),this.secondaryIndexes.clear(),this.lsm.clear(),this.mvcc=new be,this.currentTxnId=null,this.txnSnapshot=null,this.savepoints.clear(),this.opCounter=0,await this.persistSchemas(),await this.wal.checkpoint()}isOpen(){return this.opened}async getMeta(e){const t=await this.backend.read(`__meta_${e}`);return t?(new TextDecoder).decode(t):null}async setMeta(e,t){await this.backend.write(`__meta_${e}`,(new TextEncoder).encode(t).buffer)}async createTable(e){if(this.ensureOpen(),this.ensureNoDDLInTransaction("CREATE TABLE"),this.schemas.has(e.name))throw new n(`Table "${e.name}" already exists`,"TABLE_EXISTS");this.schemas.set(e.name,e),this.tablePKs.set(e.name,this.getPK(e));for(const[t,s]of Object.entries(e.columns))if(s.index||s.unique){const s=`${e.name}:idx:${t}`;if(!this.secondaryIndexes.has(s)){const n=new Z({memtableSizeThreshold:this.config.memtableSizeThreshold,levelSizeMultiplier:this.config.levelSizeMultiplier,blockSize:this.config.pageSize,bloomBitsPerKey:this.config.bloomFilterBitsPerKey,cacheLimitBytes:this.config.bufferPoolPages*this.config.pageSize,sstableStore:this.createSSTableStore(`idx_${e.name}_${t}`)});await n.init(),this.secondaryIndexes.set(s,n)}}await this.persistSchemas(),await this.wal.append({type:B.CREATE_TABLE,txnId:0,tableName:e.name,key:"",data:{schema:JSON.stringify(e)}})}async dropTable(e){this.ensureOpen(),this.ensureNoDDLInTransaction("DROP TABLE"),this.ensureTable(e);const t=await this.getAllRows(e);for(const s of t){const t=this.tablePKs.get(e);this.lsm.delete(`${e}:${s[t]}`)}await this.cleanupTableIndexes(e),this.schemas.delete(e),this.tablePKs.delete(e),await this.persistSchemas(),await this.wal.append({type:B.DROP_TABLE,txnId:0,tableName:e,key:""})}async cleanupTableIndexes(e){const t=`${e}:idx:`,s=[];for(const[e,n]of this.secondaryIndexes)if(e.startsWith(t)){s.push(e);try{await n.clear()}catch{}}for(const e of s)this.secondaryIndexes.delete(e)}async hasTable(e){return this.ensureOpen(),this.schemas.has(e)}async getTableNames(){return this.ensureOpen(),Array.from(this.schemas.keys())}async getTableSchema(e){return this.ensureOpen(),this.schemas.get(e)??null}async insert(e,t){this.ensureOpen(),this.ensureTable(e);const s=this.schemas.get(e),i=this.tablePKs.get(e),r=[],a=[],o=this.uniqueColumns(e,s),h=[];for(const n of t){const t=this.validateRow(s,n),r=String(t[i]);h.push({row:t,pkValue:r,key:`${e}:${r}`})}await this.lsm.prefetchKeys(h.map(e=>e.key));for(const t of o){const s=this.secondaryIndexes.get(`${e}:idx:${t}`);await s.prefetchPrefixRanges(h.map(e=>{const s=e.row[t];if(null==s)return null;const n=`${String(s)}:`;return[n,`${n}￿`]}).filter(e=>null!==e))}const c=new Map;for(const{row:t,pkValue:s}of h)for(const i of o){const r=t[i];if(null==r)continue;const a=String(r);let o=c.get(i);if(o||(o=new Set,c.set(i,o)),o.has(a))throw new n(`Unique constraint violation on column "${i}" in table "${e}"`,"UNIQUE_VIOLATION");o.add(a),this.checkUniqueSync(e,[i],t,s)}for(const{row:t,pkValue:s,key:i}of h){const o=this.currentTxnId?this.txnSnapshot?.get(i)??this.lsm.get(i):this.lsm.get(i);if(o&&!o.__txn_deleted)throw new n(`Duplicate primary key "${s}" in table "${e}"`,"DUPLICATE_KEY");this.currentTxnId&&this.txnSnapshot?(this.txnSnapshot.set(i,t),this.mvcc.writeVersion(e,s,t,this.currentTxnId)):this.lsm.put(i,t),this.updateSecondaryIndexes(e,s,t,null),r.push(s),a.push({type:B.INSERT,txnId:this.currentTxnId??0,tableName:e,key:s,data:t})}return await this.wal.appendBatch(a),this.opCounter+=t.length,this.checkMemoryBudget(),await this.checkpointManager.tick(),this.tryGC(),r}async find(e,t){let s;this.ensureOpen(),this.ensureTable(e);const n=await this.tryIndexLookup(e,t);s=null!==n?n:await this.getAllRows(e),s=this.mergeTxnSnapshot(e,s),t.where&&Object.keys(t.where).length>0&&(s=s.filter(e=>a(e,t.where))),t.orderBy&&t.orderBy.length>0&&(s=c(s,t.orderBy));const i=t.offset??0,r=t.limit??s.length;return s=s.slice(i,i+r),t.columns&&t.columns.length>0&&"*"!==t.columns[0]&&(s=s.map(e=>u(e,t.columns))),this.trimAllCaches(),s}async update(e,t,s){this.ensureOpen(),this.ensureTable(e);const i=this.schemas.get(e),r=await this.getAllRows(e);let o=0;const h=[],c=new Set,l=d(s),u=this.uniqueColumns(e,i);for(const t of u){const s=this.secondaryIndexes.get(`${e}:idx:${t}`),n=[];if(void 0!==l[t]&&null!==l[t]){const e=`${String(l[t])}:`;n.push([e,`${e}￿`])}else if(!(t in l))for(const e of r){const s=e[t];if(null==s)continue;const i=`${String(s)}:`;n.push([i,`${i}￿`])}await s.prefetchPrefixRanges(n)}const f=[],p=new Map;for(const s of r){const r=this.tablePKs.get(e),o=`${e}:${s[r]}`;if(t.where&&Object.keys(t.where).length>0&&!a(s,t.where))continue;const h={...s,...l};this.validateRow(i,h),this.checkBatchUnique(e,u,h,p),this.checkUniqueSync(e,u,h,String(s[r]));const c=String(h[r]),d=c!==String(s[r]);if(d){const t=`${e}:${c}`,s=this.currentTxnId?this.txnSnapshot?.get(t)??this.lsm.get(t):this.lsm.get(t);if(s&&!s.__txn_deleted)throw new n(`Duplicate primary key "${c}" in table "${e}" (cannot update key to existing value)`,"DUPLICATE_KEY")}f.push({row:s,pk:String(s[r]),key:o,updated:h,newPk:c,pkChanged:d})}for(const t of f)t.pkChanged&&await this.checkForeignKeyUpdateRestrict(e,t.pk,t.newPk);for(const{row:t,pk:s,key:n,updated:i,newPk:r,pkChanged:a}of f)a&&await this.applyForeignKeyUpdateRules(e,s,r,h,c),this.currentTxnId&&this.txnSnapshot?(a&&(this.txnSnapshot.set(n,{__txn_deleted:!0}),this.mvcc.deleteVersion(e,s,this.currentTxnId)),this.txnSnapshot.set(`${e}:${r}`,i),this.mvcc.writeVersion(e,r,i,this.currentTxnId)):(a&&this.lsm.delete(n),this.lsm.put(`${e}:${r}`,i)),o++,a&&h.push({type:B.DELETE,txnId:this.currentTxnId??0,tableName:e,key:s}),h.push({type:B.UPDATE,txnId:this.currentTxnId??0,tableName:e,key:r,data:i}),this.updateSecondaryIndexes(e,r,i,t);return await this.wal.appendBatch(h),this.opCounter+=o,await this.checkpointManager.tick(),this.trimAllCaches(),o}checkBatchUnique(e,t,s,i){for(const r of t){const t=s[r];if(null==t)continue;let a=i.get(r);if(a||(a=new Set,i.set(r,a)),a.has(t))throw new n(`Unique constraint violation on column "${r}" in table "${e}"`,"UNIQUE_VIOLATION");a.add(t)}}async checkForeignKeyUpdateRestrict(e,t,s){for(const[s,i]of this.schemas)if(s!==e)for(const[r,a]of Object.entries(i.columns)){if(!a.references||!a.onUpdate)continue;const[i]=a.references.split(".");if(i===e&&("RESTRICT"===a.onUpdate||"SET NULL"===a.onUpdate&&a.required)){const i=await this.getAllRows(s);for(const o of i)if(String(o[r])===t){const i="RESTRICT"===a.onUpdate?`foreign key "${r}" in "${s}" has dependent rows`:`foreign key "${r}" in "${s}" is required (SET NULL violates constraint)`;throw new n(`Cannot update "${e}" key "${t}": ${i}`,"FOREIGN_KEY_VIOLATION")}}}}async applyForeignKeyUpdateRules(e,t,s,i,r){const a=`${e}:${t}`;if(!r.has(a)){r.add(a);for(const[s,i]of this.schemas)if(s!==e)for(const[r,a]of Object.entries(i.columns)){if(!a.references||!a.onUpdate)continue;const[i]=a.references.split(".");if(i===e&&("RESTRICT"===a.onUpdate&&(await this.getAllRows(s)).some(e=>String(e[r])===t)))throw new n(`Cannot update "${e}" key "${t}": foreign key "${r}" in "${s}" has dependent rows`,"FOREIGN_KEY_VIOLATION")}for(const[n,r]of this.schemas)if(n!==e)for(const[a,o]of Object.entries(r.columns)){if(!o.references||!o.onUpdate)continue;const[r]=o.references.split(".");if(r!==e)continue;if("CASCADE"!==o.onUpdate&&"SET NULL"!==o.onUpdate)continue;const h=await this.getAllRows(n);for(const e of h){if(String(e[a])!==t)continue;const r=this.tablePKs.get(n),h=String(e[r]),c={...e,[a]:"CASCADE"===o.onUpdate?s:null},l=`${n}:${h}`;this.currentTxnId&&this.txnSnapshot?(this.txnSnapshot.set(l,c),this.mvcc.writeVersion(n,h,c,this.currentTxnId)):this.lsm.put(l,c),this.updateSecondaryIndexes(n,h,c,e),i.push({type:B.UPDATE,txnId:this.currentTxnId??0,tableName:n,key:h,data:c})}}}}async delete(e,t){this.ensureOpen(),this.ensureTable(e);const s=await this.getAllRows(e);let n=0;const i=[],r=new Set,o=[];for(const n of s)t.where&&0!==Object.keys(t.where).length&&!a(n,t.where)||o.push(String(n[this.tablePKs.get(e)]));const h=new Set;for(const t of o)await this.checkCascadeRestrict(e,t,h);for(const o of s){const s=this.tablePKs.get(e),h=`${e}:${o[s]}`;t.where&&0!==Object.keys(t.where).length&&!a(o,t.where)||(n+=await this.applyForeignKeyRules(e,String(o[s]),i,r),this.currentTxnId&&this.txnSnapshot?(this.txnSnapshot.set(h,{__txn_deleted:!0}),this.mvcc.deleteVersion(e,String(o[s]),this.currentTxnId)):this.lsm.delete(h),n++,i.push({type:B.DELETE,txnId:this.currentTxnId??0,tableName:e,key:String(o[s])}),this.updateSecondaryIndexes(e,String(o[s]),null,o))}return await this.wal.appendBatch(i),this.opCounter+=n,await this.checkpointManager.tick(),this.trimAllCaches(),n}async checkCascadeRestrict(e,t,s){const i=`${e}:${t}`;if(!s.has(i)){s.add(i);for(const[i,r]of this.schemas)if(i!==e)for(const[a,o]of Object.entries(r.columns)){if(!o.references||!o.onDelete)continue;const[r]=o.references.split(".");if(r!==e)continue;const h=(await this.getAllRows(i)).filter(e=>String(e[a])===t);if("RESTRICT"===o.onDelete&&h.length>0)throw new n(`Cannot delete from "${e}": foreign key "${a}" in "${i}" has dependent rows`,"FOREIGN_KEY_VIOLATION");if("SET NULL"===o.onDelete&&o.required&&h.length>0)throw new n(`Cannot delete from "${e}": foreign key "${a}" in "${i}" is required (SET NULL violates constraint)`,"FOREIGN_KEY_VIOLATION");if("CASCADE"===o.onDelete){const e=this.tablePKs.get(i);for(const t of h)await this.checkCascadeRestrict(i,String(t[e]),s)}}}}async applyForeignKeyRules(e,t,s,i){let r=0;const a=`${e}:${t}`;if(i.has(a))return 0;i.add(a);for(const[a,o]of this.schemas)if(a!==e)for(const[h,c]of Object.entries(o.columns)){if(!c.references||!c.onDelete)continue;const[o]=c.references.split(".");if(o!==e)continue;const l=(await this.getAllRows(a)).filter(e=>String(e[h])===t);if("RESTRICT"===c.onDelete&&l.length>0)throw new n(`Cannot delete from "${e}": foreign key "${h}" in "${a}" has dependent rows`,"FOREIGN_KEY_VIOLATION");if("CASCADE"===c.onDelete){const e=this.tablePKs.get(a);for(const t of l){const n=String(t[e]);r+=await this.applyForeignKeyRules(a,n,s,i);const o=`${a}:${n}`;this.currentTxnId&&this.txnSnapshot?(this.txnSnapshot.set(o,{__txn_deleted:!0}),this.mvcc.deleteVersion(a,n,this.currentTxnId)):this.lsm.delete(o),this.updateSecondaryIndexes(a,n,null,t),s.push({type:B.DELETE,txnId:this.currentTxnId??0,tableName:a,key:n}),r++}}else if("SET NULL"===c.onDelete){const e=this.tablePKs.get(a);for(const t of l){const n=String(t[e]),i={...t,[h]:null},r=`${a}:${n}`;this.currentTxnId&&this.txnSnapshot?(this.txnSnapshot.set(r,i),this.mvcc.writeVersion(a,n,i,this.currentTxnId)):this.lsm.put(r,i),this.updateSecondaryIndexes(a,n,i,t),s.push({type:B.UPDATE,txnId:this.currentTxnId??0,tableName:a,key:n,data:i})}}}return r}async findStream(e,t,s){this.ensureOpen(),this.ensureTable(e);const n=!!(t.where&&Object.keys(t.where).length>0),i=t.columns&&t.columns.length>0&&"*"!==t.columns[0]?e=>u(e,t.columns):null,r=t.limit??1/0,o=t.offset??0,h=this.tablePKs.get(e),c=`${e}:`;let l=0,f=0;const d=e=>!(!n||a(e,t.where))||(f<o?(f++,!0):(s(i?i(e):e),l++,l<r));if(this.currentTxnId&&this.txnSnapshot){const n=await this.find(e,{...t,orderBy:void 0,limit:void 0,offset:void 0});for(const e of n)s(i?i(e):e);return n.length}const p=await this.tryIndexLookup(e,t);if(null!==p){for(const e of p)if(!d(e))break;return l}return await this.lsm.prefetchRange(c,`${c}￿`),this.lsm.rangeScanLazy(c,`${c}￿`,(e,t)=>{if(l>=r)return;const s={...t};s[h]=e.slice(c.length),d(s)}),l}async count(e,t){this.ensureOpen(),this.ensureTable(e);const s=await this.getAllRows(e);return this.trimAllCaches(),t?.where&&0!==Object.keys(t.where).length?s.filter(e=>a(e,t.where)).length:s.length}async clear(e){this.ensureOpen(),this.ensureTable(e);const t=await this.getAllRows(e),s=[];for(const n of t){const t=this.tablePKs.get(e),i=`${e}:${n[t]}`;this.currentTxnId&&this.txnSnapshot?(this.txnSnapshot.set(i,{__txn_deleted:!0}),this.mvcc.deleteVersion(e,String(n[t]),this.currentTxnId)):this.lsm.delete(i),s.push({type:B.DELETE,txnId:this.currentTxnId??0,tableName:e,key:String(n[t])}),this.updateSecondaryIndexes(e,String(n[t]),null,n)}await this.wal.appendBatch(s),this.opCounter+=t.length,await this.checkpointManager.tick(),this.tryGC()}async alterTable(e,t,s){this.ensureOpen(),this.ensureNoDDLInTransaction("ALTER TABLE"),this.ensureTable(e);const i=this.schemas.get(e);if("ADD"===t){if(i.columns[s.name])throw new n(`Column "${s.name}" already exists in table "${e}"`,"COLUMN_EXISTS");return i.columns[s.name]=s,void await this.persistSchemas()}if(!i.columns[s.name])throw new n(`Column "${s.name}" does not exist in table "${e}"`,"COLUMN_NOT_FOUND");if(i.columns[s.name].index||i.columns[s.name].unique){const t=`${e}:idx:${s.name}`,n=this.secondaryIndexes.get(t);if(n){try{await n.clear()}catch{}this.secondaryIndexes.delete(t)}}delete i.columns[s.name],await this.persistSchemas();const r=`${e}:`,a=`${r}￿`;await this.lsm.prefetchRange(r,a);const o=this.lsm.rangeScan(r,a),h=[];for(const[t,n]of o){if(!(s.name in n))continue;const i={...n};delete i[s.name],this.lsm.put(t,i);const a=t.slice(r.length);this.updateSecondaryIndexes(e,a,i,n),h.push({type:B.UPDATE,txnId:this.currentTxnId??0,tableName:e,key:a,data:i})}await this.wal.appendBatch(h),this.opCounter+=h.length,await this.checkpointManager.tick(),this.trimAllCaches()}async createIndex(e,t,s){this.ensureOpen(),this.ensureNoDDLInTransaction("CREATE INDEX"),this.ensureTable(e);const i=this.schemas.get(e).columns[t];if(!i)throw new n(`Column "${t}" does not exist in table "${e}"`,"COLUMN_NOT_FOUND");const r=`${e}:idx:${t}`;if(this.secondaryIndexes.has(r))return;i.index=!0,s&&(i.unique=!0);const a=new Z({memtableSizeThreshold:this.config.memtableSizeThreshold,levelSizeMultiplier:this.config.levelSizeMultiplier,blockSize:this.config.pageSize,bloomBitsPerKey:this.config.bloomFilterBitsPerKey,cacheLimitBytes:this.config.bufferPoolPages*this.config.pageSize,sstableStore:this.createSSTableStore(`idx_${e}_${t}`)});await a.init(),this.secondaryIndexes.set(r,a);const o=this.tablePKs.get(e),h=await this.getAllRows(e);for(const e of h){const s=e[t];null!=s&&a.put(`${String(s)}:${e[o]}`,{pk:e[o]})}await a.flush(),await this.persistSchemas()}async dropIndex(e,t,s){this.ensureOpen(),this.ensureNoDDLInTransaction("DROP INDEX"),this.ensureTable(e);const i=this.schemas.get(e).columns[t];if(!i)throw new n(`Column "${t}" does not exist in table "${e}"`,"COLUMN_NOT_FOUND");if(i.primaryKey)throw new n(`Cannot drop primary key index on column "${t}"`,"NOT_SUPPORTED");if(!i.index&&!i.unique&&!this.secondaryIndexes.has(`${e}:idx:${t}`))throw new n(`Index on column "${t}" does not exist in table "${e}"`,"INDEX_NOT_FOUND");i.index=!1,i.unique=!1;const r=`${e}:idx:${t}`,a=this.secondaryIndexes.get(r);a&&(await a.clear(),this.secondaryIndexes.delete(r)),await this.persistSchemas()}async beginTransaction(){if(this.currentTxnId)throw new n("Transaction already in progress","TX_ACTIVE");this.currentTxnId=this.mvcc.beginTransaction(),this.txnSnapshot=new Map,await this.wal.append({type:B.BEGIN,txnId:this.currentTxnId,tableName:"",key:""})}async commitTransaction(){if(!this.currentTxnId)throw new n("No active transaction","TX_NONE");if(await this.wal.append({type:B.COMMIT,txnId:this.currentTxnId,tableName:"",key:""}),await this.wal.flush(),this.txnSnapshot)for(const[e,t]of this.txnSnapshot)t.__txn_deleted?this.lsm.delete(e):this.lsm.put(e,t);this.mvcc.commitTransaction(this.currentTxnId),this.currentTxnId=null,this.txnSnapshot=null}async rollbackTransaction(){if(!this.currentTxnId)throw new n("No active transaction","TX_NONE");const e=new Set;if(this.txnSnapshot)for(const t of this.txnSnapshot.keys()){const s=t.indexOf(":");s>0&&e.add(t.slice(0,s))}this.mvcc.rollbackTransaction(this.currentTxnId),this.txnSnapshot=null,await this.wal.append({type:B.ROLLBACK,txnId:this.currentTxnId,tableName:"",key:""}),this.currentTxnId=null;for(const t of e)this.schemas.has(t)&&await this.reindexTable(t)}async savepoint(e){if(!this.currentTxnId)throw new n("No active transaction for savepoint","TX_NONE");if(this.savepoints.has(e))throw new n(`Savepoint "${e}" already exists`,"SAVEPOINT_EXISTS");this.savepoints.set(e,{txnId:this.currentTxnId,snapshot:this.txnSnapshot?new Map(this.txnSnapshot):null})}async rollbackToSavepoint(e){const t=this.savepoints.get(e);if(!t)throw new n(`Savepoint "${e}" not found`,"SAVEPOINT_NOT_FOUND");const s=new Set;if(this.txnSnapshot)for(const e of this.txnSnapshot.keys()){const t=e.indexOf(":");t>0&&s.add(e.slice(0,t))}this.txnSnapshot=t.snapshot?new Map(t.snapshot):null,this.mvcc.discardVersions(this.currentTxnId);let i=!1;for(const[t]of this.savepoints)t!==e?i&&this.savepoints.delete(t):i=!0;for(const e of s)this.schemas.has(e)&&await this.reindexTable(e)}async releaseSavepoint(e){if(!this.savepoints.has(e))throw new n(`Savepoint "${e}" not found`,"SAVEPOINT_NOT_FOUND");this.savepoints.delete(e)}async backup(){this.ensureOpen();const e={};for(const t of this.schemas.keys())e[t]=await this.getAllRows(t);return e}async getAllRows(e){const t=this.tablePKs.get(e),s=`${e}:`;await this.lsm.prefetchRange(s,`${s}￿`);const n=this.lsm.rangeScan(s,`${s}￿`).map(([e,n])=>{const i={...n};return i[t]=e.slice(s.length),i});return this.mergeTxnSnapshot(e,n)}mergeTxnSnapshot(e,t){if(!this.currentTxnId||!this.txnSnapshot)return t;const s=this.tablePKs.get(e),n=`${e}:`;for(const[e,i]of this.txnSnapshot){if(!e.startsWith(n))continue;const r=e.slice(n.length),a=i.__txn_deleted,o=t.findIndex(e=>e[s]===r);if(a)o>=0&&t.splice(o,1);else{const e={...i,[s]:r};o>=0?t[o]=e:t.push(e)}}return t}getPK(e){for(const[t,s]of Object.entries(e.columns))if(s.primaryKey)return t;return Object.keys(e.columns)[0]}validateRow(e,t){const s={};for(const[i,r]of Object.entries(e.columns)){let a=t[i];if(void 0===a&&void 0!==r.default&&(a=r.default),r.required&&null==a)throw new n(`Column "${i}" is required in table "${e.name}"`,"VALIDATION_ERROR");null!=a&&this.checkType(i,r.type,a,r),void 0!==a&&(s[i]=a)}return s}checkType(e,t,s,i){!function(e,t,s,i,r){const a=typeof i;switch(s){case"string":if("string"!==a)throw new n(`Column "${t}" in table "" expects string, got ${a}`,"TYPE_ERROR");if(void 0!==r?.maxLength&&i.length>r.maxLength)throw new n(`Column "${t}" in table "" exceeds max length ${r.maxLength}`,"VALIDATION_ERROR");break;case"number":if("number"!==a)throw new n(`Column "${t}" in table "" expects number, got ${a}`,"TYPE_ERROR");if(void 0!==r?.min&&i<r.min)throw new n(`Column "${t}" in table "" value ${i} below minimum ${r.min}`,"VALIDATION_ERROR");if(void 0!==r?.max&&i>r.max)throw new n(`Column "${t}" in table "" value ${i} above maximum ${r.max}`,"VALIDATION_ERROR");break;case"boolean":if("boolean"!==a)throw new n(`Column "${t}" in table "" expects boolean, got ${a}`,"TYPE_ERROR");break;case"date":if("string"!==a||isNaN(Date.parse(i)))throw new n(`Column "${t}" in table "" expects valid date string, got ${typeof i}`,"TYPE_ERROR");break;case"json":if("object"!==a)throw new n(`Column "${t}" in table "" expects object/array, got ${a}`,"TYPE_ERROR")}}(0,e,t,s,i)}async persistSchemas(){const e={};for(const[t,s]of this.schemas)e[t]=s.columns;const t=JSON.stringify(e),s=(new TextEncoder).encode(t).buffer;await this.backend.write("__aria_schemas",s)}async loadSchemas(){const e=await this.backend.read("__aria_schemas");if(e)try{const t=(new TextDecoder).decode(e),s=JSON.parse(t);for(const[e,t]of Object.entries(s)){const s={name:e,columns:t};this.schemas.set(e,s),this.tablePKs.set(e,this.getPK(s))}}catch{}}createSSTableStore(e){const t="main"===e?"sst_":`sst_${e}_`,s="main"===e?"__aria_lsm_meta":`__aria_lsm_meta_${e}`;let n=0,i=!1;const r=this.isPageStorage()?new ge(this.fileManager,this.bufferPool):null,a=e=>(new TextEncoder).encode(e).buffer,o=async()=>{const e=await this.backend.read(s);if(!e)return[];try{return JSON.parse((new TextDecoder).decode(e))}catch{return[]}};return{save:async(e,s)=>{if(r)return void await r.save(e,s);let n=s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength);if(this.config.compression){const e=function(e){if(0===e.byteLength){const e=new Uint8Array(4);return new DataView(e.buffer).setUint32(0,0,!0),e}const t=e.byteLength+Math.ceil(e.byteLength/15)+8,s=new Uint8Array(t);let n=0,i=0,r=0;for(;n<e.byteLength;){let t=0,a=0;for(let s=Math.max(0,n-65535);s<n;s++){let i=0;for(;n+i<e.byteLength&&s+i<n&&e[s+i]===e[n+i]&&i<19;)i++;i>=4&&i>t&&(t=i,a=n-s)}if(t>4&&n-r<=15){const o=n-r,h=t-4;s[i++]=(15&o)<<4|15&h;for(let t=0;t<o;t++)s[i++]=e[r+t];s[i++]=255&a,s[i++]=a>>8&255,n+=t,r=n}else if(n++,n-r>=15){s[i++]=240;for(let t=0;t<15;t++)s[i++]=e[r+t];r=n}}let a=n-r;for(;a>0;){const t=Math.min(a,15);s[i++]=(15&t)<<4;for(let n=0;n<t;n++)s[i++]=e[r+n];a-=t,r+=t}const o=s.slice(0,i),h=new Uint8Array(4+o.byteLength);return new DataView(h.buffer).setUint32(0,e.byteLength,!0),h.set(o,4),h}(new Uint8Array(n));n=e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}await this.backend.write(`${t}${e}`,n)},load:async e=>{if(r){const t=(await o()).find(t=>t.id===e);if(t&&t.pageIds&&t.pageIds.length>0)return r.load(e,t.pageIds,t.totalSize)}const s=await this.backend.read(`${t}${e}`);if(!s)return null;let n=new Uint8Array(s);return this.config.compression&&(n=function(e){if(e.byteLength<4)throw new Error("LZ4 stream too short: missing header");const t=new DataView(e.buffer,e.byteOffset,e.byteLength).getUint32(0,!0);if(0===t&&4===e.byteLength)return new Uint8Array(0);if(t<=0||t>1073741823)throw new Error("Invalid LZ4 header: bad original size");const s=e.subarray(4),n=new Uint8Array(t);let i=0,r=0;for(;i<s.byteLength&&r<t;){const e=s[i++],a=e>>4&15,o=15&e;for(let e=0;e<a&&i<s.byteLength&&r<t;e++)n[r++]=s[i++];if(0===o)continue;if(i+1>=s.byteLength)break;const h=s[i++]|s[i++]<<8,c=o+4;for(let e=0;e<c&&r<t;e++)n[r]=n[r-h],r++}return n}(n)),n},delete:async e=>{if(r){const t=(await o()).find(t=>t.id===e);t&&t.pageIds&&t.pageIds.length>0&&await r.delete(e,t.pageIds)}await this.backend.delete(`${t}${e}`)},allocateId:async()=>{if(!i){const e=await o();n=e.reduce((e,t)=>Math.max(e,t.id),0),i=!0}return++n},listMeta:o,saveMeta:async e=>{const t=await o(),n=r?.getPageIds(e.id),i=n&&n.length>0?{...e,pageIds:n}:e,h=t.findIndex(t=>t.id===e.id);h>=0?t[h]=i:t.push(i),await this.backend.write(s,a(JSON.stringify(t)))},deleteMeta:async e=>{const t=(await o()).filter(t=>t.id!==e);await this.backend.write(s,a(JSON.stringify(t)))}}}isPageStorage(){return!0===this.config.pageStorage||!1!==this.config.pageStorage&&("opfs"===this.config.storageBackend||"kv"===this.config.storageBackend)}applyWALRecord(e){switch(e.type){case B.INSERT:case B.UPDATE:e.data&&this.lsm.put(`${e.tableName}:${e.key}`,e.data);break;case B.DELETE:this.lsm.delete(`${e.tableName}:${e.key}`);break;case B.CREATE_TABLE:if(e.data?.schema)try{const t=JSON.parse(e.data.schema);this.schemas.has(t.name)||(this.schemas.set(t.name,t),this.tablePKs.set(t.name,this.getPK(t)))}catch{}case B.COMMIT:case B.ROLLBACK:case B.BEGIN:}}async applyDropTableRecovery(e){if(!e)return;await this.cleanupTableIndexes(e),this.schemas.delete(e),this.tablePKs.delete(e);const t=`${e}:`,s=`${t}￿`;await this.lsm.prefetchRange(t,s);const n=this.lsm.rangeScan(t,s);for(const[e]of n)this.lsm.delete(e)}uniqueColumns(e,t){const s=[];for(const[n,i]of Object.entries(t.columns))i.unique&&this.secondaryIndexes.has(`${e}:idx:${n}`)&&s.push(n);return s}checkUniqueSync(e,t,s,i){for(const r of t){const t=s[r];if(null==t)continue;const a=this.secondaryIndexes.get(`${e}:idx:${r}`);if(!a)continue;const o=`${String(t)}:`,h=a.rangeScan(o,`${o}￿`);for(const[,t]of h){const s=t.pk;if(void 0!==s&&s!==i)throw new n(`Unique constraint violation on column "${r}" in table "${e}"`,"UNIQUE_VIOLATION")}}}updateSecondaryIndexes(e,t,s,n){const i=this.schemas.get(e);if(i)for(const[r,a]of Object.entries(i.columns)){if(!a.index&&!a.unique)continue;const i=`${e}:idx:${r}`,o=this.secondaryIndexes.get(i);if(o){if(n){const e=n[r];null!=e&&o.delete(`${String(e)}:${t}`)}if(s){const e=s[r];null!=e&&o.put(`${String(e)}:${t}`,{pk:t})}}}}async tryIndexLookup(e,t){if(!t.where)return null;const s=this.schemas.get(e);if(!s)return null;const n=this.tablePKs.get(e);for(const[i,r]of Object.entries(t.where)){if("$and"===i||"$or"===i||"$not"===i)continue;const t=s.columns[i];if(!(t&&(t.index||t.unique||t.primaryKey)||i===n))continue;if(i===n){if("object"!=typeof r||null===r){const t=`${e}:${r}`;await this.lsm.prefetchKeys([t]);const s=this.lsm.get(t);return s?[{...s,[n]:r}]:[]}const t=r;if("$eq"in t){const s=`${e}:${t.$eq}`;await this.lsm.prefetchKeys([s]);const i=this.lsm.get(s);return i?[{...i,[n]:t.$eq}]:[]}if("$in"in t&&Array.isArray(t.$in)){const s=t.$in.map(t=>`${e}:${t}`);await this.lsm.prefetchKeys(s);const i=[],r=new Set;for(const s of t.$in){const t=String(s);if(r.has(t))continue;const a=this.lsm.get(`${e}:${t}`);a&&(r.add(t),i.push({...a,[n]:t}))}return i}if("$gt"in t||"$gte"in t||"$lt"in t||"$lte"in t){const t=`${e}:`;await this.lsm.prefetchRange(t,`${t}￿`);const s=this.lsm.rangeScan(t,`${t}￿`),i=[];for(const[e,o]of s){const s={...o,[n]:e.slice(t.length)};a(s,{[n]:r})&&i.push(s)}return i}}const o=`${e}:idx:${i}`,h=this.secondaryIndexes.get(o);if(!h)continue;if("object"!=typeof r||null===r){if(null===r)continue;return this.indexScanToRows(e,n,h,String(r),String(r))}const c=r;if("$eq"in c){if(null===c.$eq)continue;const t=String(c.$eq);return this.indexScanToRows(e,n,h,t,t)}if("$in"in c&&Array.isArray(c.$in)){if(c.$in.some(e=>null===e))continue;const t=[],s=new Set;for(const i of c.$in){const r=await this.indexScanToRows(e,n,h,String(i),String(i));for(const e of r){const i=String(e[n]);s.has(i)||(s.add(i),t.push(e))}}return t}if("$gt"in c||"$gte"in c||"$lt"in c||"$lte"in c)return(await this.indexScanToRows(e,n,h,"","￿")).filter(e=>a(e,{[i]:r}))}return null}async indexScanToRows(e,t,s,n,i){const r=i.includes("￿")?i:`${i}￿`;await s.prefetchRange(n,r);const a=s.rangeScan(n,r),o=[];for(const[,e]of a){const t=e.pk;t&&o.push(t)}await this.lsm.prefetchKeys(o.map(t=>`${e}:${t}`));const h=[];for(const s of o){const n=this.lsm.get(`${e}:${s}`);n&&h.push({...n,[t]:s})}return h}tryGC(){this.gcCounter++,this.gcCounter>=10&&(this.mvcc.gc(100),this.gcCounter=0)}trimAllCaches(){this.lsm.trimCache();for(const e of this.secondaryIndexes.values())e.trimCache()}checkMemoryBudget(){const e=1024*this.config.maxMemoryMB*1024;this.lsm.getEstimatedMemory()>e&&(this.lsm.flush().catch(()=>{}),this.mvcc.gc(50))}getWALEstimatedSize(){return 200*this.wal.getBufferedCount()}async analyzeTable(e){this.ensureOpen(),this.ensureTable(e);const t=await this.getAllRows(e),s={table:e,rowCount:t.length,avgRowSize:t.length>0?Math.round(t.reduce((e,t)=>e+JSON.stringify(t).length,0)/t.length):0,indexDepth:this.lsm.getStats().levelCounts.filter(e=>e>0).length,sstableCount:this.lsm.getStats().sstableCount,memtableSize:this.lsm.getStats().memtableSize,estimatedMemory:this.lsm.getEstimatedMemory()},n=this.schemas.get(e);if(n&&t.length>0){const e={};for(const s of Object.keys(n.columns)){const n=new Set(t.map(e=>String(e[s])));e[s]={distinctValues:n.size}}s.columnStats=e}return s}async reindexTable(e){return this.ensureOpen(),this.ensureTable(e),this.reindexTableInternal(e)}async reindexTableInternal(e){const t=this.schemas.get(e);if(!t)return 0;let s=0;for(const[n,i]of Object.entries(t.columns)){if(!i.index&&!i.unique)continue;const t=`${e}:idx:${n}`,r=this.secondaryIndexes.get(t);if(!r)continue;await r.clear(),s++;const a=await this.getAllRows(e);for(const t of a){const s=t[n];null!=s&&r.put(`${String(s)}:${t[this.tablePKs.get(e)]}`,{pk:t[this.tablePKs.get(e)]})}}return s}async vacuum(){this.ensureOpen(),await this.lsm.flush();for(let e=0;e<6;e++)this.lsm.getStats().levelCounts[e]>=2&&await this.lsm.compactLevel(e);const e=this.mvcc.getGlobalLSN();return this.mvcc.gc(10),{compactedLevels:6,gcVersions:e}}ensureOpen(){if(!this.opened)throw new n("AriaEngine not opened","DB_NOT_OPEN")}ensureNoDDLInTransaction(e){if(this.currentTxnId)throw new n(`${e} is not supported inside a transaction (AriaEngine DDL is not transactional)`,"NOT_SUPPORTED")}ensureTable(e){if(!this.schemas.has(e))throw new n(`Table "${e}" does not exist`,"TABLE_NOT_FOUND")}}class Ie{constructor(e="opfs"){this.name="hybrid",this.dbName="",this.version=1,this.memoryEngine=new y,this.diskEngineType=e,this.diskEngine=new U}async open(e,t){this.dbName=e,this.version=t,await this.diskEngine.open(e,t),await this.memoryEngine.open(e,t),await this.reloadMemoryFromDisk()}async reloadMemoryFromDisk(){await this.memoryEngine.close(),await this.memoryEngine.open(this.dbName,this.version);const e=this.diskEngine;"function"==typeof e.reload&&await e.reload();const t=await this.diskEngine.getTableNames();for(const e of t){const t=await this.diskEngine.getTableSchema(e);if(!t)continue;await this.memoryEngine.createTable(t);const s=await this.diskEngine.find(e,{table:e});if(s.length>0)try{await this.memoryEngine.insert(e,s)}catch(e){}}}async close(){await this.memoryEngine.close(),await this.diskEngine.close()}isOpen(){return this.memoryEngine.isOpen()&&this.diskEngine.isOpen()}async repair(){"function"==typeof this.diskEngine.repair&&await this.diskEngine.repair(),await this.reloadMemoryFromDisk()}async clearAll(){if("function"==typeof this.diskEngine.clearAll)await this.diskEngine.clearAll();else{const e=await this.diskEngine.getTableNames();for(const t of e)await this.diskEngine.dropTable(t)}if("function"==typeof this.memoryEngine.clearAll)await this.memoryEngine.clearAll();else{const e=await this.memoryEngine.getTableNames();for(const t of e)await this.memoryEngine.dropTable(t)}}async getMeta(e){return"function"==typeof this.diskEngine.getMeta?this.diskEngine.getMeta(e):null}async setMeta(e,t){"function"==typeof this.diskEngine.setMeta&&await this.diskEngine.setMeta(e,t)}async createTable(e){await this.memoryEngine.createTable(e);try{await this.diskEngine.createTable(e)}catch(e){await this.recoverMemoryAfterDiskError(e)}}async dropTable(e){await this.memoryEngine.dropTable(e);try{await this.diskEngine.dropTable(e)}catch(e){await this.recoverMemoryAfterDiskError(e)}}async hasTable(e){return this.memoryEngine.hasTable(e)}async getTableNames(){return this.memoryEngine.getTableNames()}async getTableSchema(e){return this.memoryEngine.getTableSchema(e)}async alterTable(e,t,s){await this.memoryEngine.alterTable(e,t,s);try{if("function"==typeof this.diskEngine.alterTable)await this.diskEngine.alterTable(e,t,s);else{const n=await this.diskEngine.getTableSchema(e);n&&"DROP"===t&&delete n.columns[s.name]}}catch(e){await this.recoverMemoryAfterDiskError(e)}}async recoverMemoryAfterDiskError(e){try{await this.reloadMemoryFromDisk()}catch{}throw e}async insert(e,t){const s=await this.memoryEngine.insert(e,t);try{await this.diskEngine.insert(e,t)}catch(e){await this.recoverMemoryAfterDiskError(e)}return s}async find(e,t){return this.memoryEngine.find(e,t)}async findStream(e,t,s){return this.memoryEngine.findStream(e,t,s)}async update(e,t,s){const n=await this.memoryEngine.update(e,t,s);try{await this.diskEngine.update(e,t,s)}catch(e){await this.recoverMemoryAfterDiskError(e)}return n}async delete(e,t){const s=await this.memoryEngine.delete(e,t);try{await this.diskEngine.delete(e,t)}catch(e){await this.recoverMemoryAfterDiskError(e)}return s}async count(e,t){return this.memoryEngine.count(e,t)}async clear(e){await this.memoryEngine.clear(e);try{await this.diskEngine.clear(e)}catch(e){await this.recoverMemoryAfterDiskError(e)}}async createIndex(e,t,s){await this.memoryEngine.createIndex(e,t,s);try{"function"==typeof this.diskEngine.createIndex&&await this.diskEngine.createIndex(e,t,s)}catch(e){await this.recoverMemoryAfterDiskError(e)}}async dropIndex(e,t,s){await this.memoryEngine.dropIndex(e,t,s);try{"function"==typeof this.diskEngine.dropIndex&&await this.diskEngine.dropIndex(e,t,s)}catch(e){await this.recoverMemoryAfterDiskError(e)}}async beginTransaction(){await this.memoryEngine.beginTransaction(),await this.diskEngine.beginTransaction()}async commitTransaction(){await this.diskEngine.commitTransaction();try{await this.memoryEngine.commitTransaction()}catch(e){throw new n("Hybrid commit failed: memory engine error after disk commit (disk data is committed)","TX_COMMIT_ERROR",e)}}async rollbackTransaction(){await this.memoryEngine.rollbackTransaction(),await this.diskEngine.rollbackTransaction()}getDiskEngineType(){return this.diskEngineType}getMemoryEngine(){return this.memoryEngine}}class Ae{constructor(e,t,s=["*"],n){this.engine=e,this.tableName=t,this._columns=s,this._where={},this._orderBy=[],this._joins=[],this._executor=n}as(e){return this._alias=e,this}innerJoin(e,t,s){return this._addJoin("INNER",e,t,s)}leftJoin(e,t,s){return this._addJoin("LEFT",e,t,s)}rightJoin(e,t,s){return this._addJoin("RIGHT",e,t,s)}crossJoin(e,t){return this._addJoin("CROSS",e,{},t)}join(e,t,s){return this._addJoin("INNER",e,t,s)}_addJoin(e,t,s,n){return this._joins.push({type:e,table:t,on:s,alias:n}),this}where(e){return this._where={...this._where,...e},this}orderBy(e,t="asc"){return this._orderBy.push({column:e,direction:t}),this}limit(e){return this._limit=e,this}offset(e){return this._offset=e,this}async execute(){if(this._joins.length>0&&this._executor){const e=this.toAST();return this._executor.execute(e)}return this.engine.find(this.tableName,{table:this.tableName,columns:this._columns,where:this._where,orderBy:this._orderBy.length>0?this._orderBy:void 0,limit:this._limit,offset:this._offset})}toAST(){return{type:"SELECT",columns:this._columns,from:this.tableName,alias:this._alias,joins:this._joins.length>0?[...this._joins]:void 0,where:this._where,orderBy:this._orderBy.length>0?this._orderBy:void 0,limit:this._limit,offset:this._offset}}}class Re{constructor(e,t,s,n,i){this.engine=e,this.tableName=t,this._updates=s,this._where={},this.onWrite=n,this.onHooks=i}where(e){return this._where={...this._where,...e},this}async execute(){const e={table:this.tableName,where:this._where};await(this.onHooks?.("beforeUpdate",[e,this._updates]));const t=await this.engine.update(this.tableName,e,this._updates);return this.onWrite?.(this.tableName),await(this.onHooks?.("afterUpdate",[e,this._updates,t])),t}toAST(){return{type:"UPDATE",table:this.tableName,sets:this._updates,where:this._where}}}class Ce{constructor(e,t,s,n){this.engine=e,this.tableName=t,this._where={},this.onWrite=s,this.onHooks=n}where(e){return this._where={...this._where,...e},this}async execute(){const e={table:this.tableName,where:this._where};await(this.onHooks?.("beforeDelete",[e]));const t=await this.engine.delete(this.tableName,e);return this.onWrite?.(this.tableName),await(this.onHooks?.("afterDelete",[e,t])),t}toAST(){return{type:"DELETE",from:this.tableName,where:this._where}}}class Oe{constructor(e,t,s,n,i){this.schema=null,this.engine=e,this.name=t,this.executor=s,this.onWrite=n,this.onHooks=i}async getSchema(){if(!this.schema){const e=await this.engine.getTableSchema(this.name);if(!e)throw new n(`Table "${this.name}" does not exist`,"TABLE_NOT_FOUND");this.schema=e}return this.schema}async insert(e){await(this.onHooks?.("beforeInsert",[[e]]));const t=await this.engine.insert(this.name,[e]);return this.onWrite?.(this.name),await(this.onHooks?.("afterInsert",[[e],t])),t[0]}async insertMany(e){await(this.onHooks?.("beforeInsert",[e]));const t=await this.engine.insert(this.name,e);return this.onWrite?.(this.name),await(this.onHooks?.("afterInsert",[e,t])),t}select(e=["*"]){return new Ae(this.engine,this.name,e,this.executor)}async stream(e,t={}){if("function"!=typeof this.engine.findStream){const s=await this.engine.find(this.name,{table:this.name,where:t.where,limit:t.limit,offset:t.offset,columns:t.columns});for(const t of s)e(t);return s.length}return this.engine.findStream(this.name,{table:this.name,where:t.where,limit:t.limit,offset:t.offset,columns:t.columns},e)}update(e){return new Re(this.engine,this.name,e,this.onWrite,this.onHooks)}delete(){return new Ce(this.engine,this.name,this.onWrite,this.onHooks)}async count(e){return this.engine.count(this.name,e?{table:this.name,where:e}:void 0)}async clear(){await this.engine.clear(this.name),this.onWrite?.(this.name)}async drop(){await this.engine.dropTable(this.name),this.onWrite?.(this.name)}}function Ne(e){switch(e.type){case"SELECT":return function(e){return{table:e.from,columns:e.columns,where:e.where,orderBy:e.orderBy?.length?e.orderBy:void 0,limit:e.limit,offset:e.offset}}(e);case"DELETE":return function(e){return{table:e.from,where:e.where}}(e);case"UPDATE":return function(e){return{table:e.table,where:e.where}}(e);default:throw new n(`Cannot compile statement type "${e.type}" to QueryPlan`,"COMPILE_ERROR")}}var Le;!function(e){e.SELECT="SELECT",e.FROM="FROM",e.WHERE="WHERE",e.INSERT="INSERT",e.INTO="INTO",e.VALUES="VALUES",e.UPDATE="UPDATE",e.SET="SET",e.DELETE="DELETE",e.CREATE="CREATE",e.TABLE="TABLE",e.DROP="DROP",e.ORDER="ORDER",e.BY="BY",e.ASC="ASC",e.DESC="DESC",e.LIMIT="LIMIT",e.OFFSET="OFFSET",e.AND="AND",e.OR="OR",e.NOT="NOT",e.LIKE="LIKE",e.IN="IN",e.PRIMARY="PRIMARY",e.KEY="KEY",e.UNIQUE="UNIQUE",e.DEFAULT="DEFAULT",e.NULL="NULL",e.TRUE="TRUE",e.REFERENCES="REFERENCES",e.CASCADE="CASCADE",e.BETWEEN="BETWEEN",e.IF="IF",e.EXISTS="EXISTS",e.FALSE="FALSE",e.ALTER="ALTER",e.ADD="ADD",e.TRUNCATE="TRUNCATE",e.INNER="INNER",e.LEFT="LEFT",e.RIGHT="RIGHT",e.CROSS="CROSS",e.JOIN="JOIN",e.ON="ON",e.AS="AS",e.OUTER="OUTER",e.GROUP="GROUP",e.HAVING="HAVING",e.COUNT="COUNT",e.SUM="SUM",e.AVG="AVG",e.MIN="MIN",e.MAX="MAX",e.DISTINCT="DISTINCT",e.BEGIN="BEGIN",e.COMMIT="COMMIT",e.ROLLBACK="ROLLBACK",e.UNION="UNION",e.ALL="ALL",e.INDEX="INDEX",e.CASE="CASE",e.WHEN="WHEN",e.THEN="THEN",e.ELSE="ELSE",e.END="END",e.EXPLAIN="EXPLAIN",e.ANALYZE="ANALYZE",e.REINDEX="REINDEX",e.VACUUM="VACUUM",e.SAVEPOINT="SAVEPOINT",e.RELEASE="RELEASE",e.TO="TO",e.IDENTIFIER="IDENTIFIER",e.STRING="STRING",e.NUMBER="NUMBER",e.COMMA="COMMA",e.LPAREN="LPAREN",e.RPAREN="RPAREN",e.SEMICOLON="SEMICOLON",e.EQ="EQ",e.NEQ="NEQ",e.GT="GT",e.GTE="GTE",e.LT="LT",e.LTE="LTE",e.STAR="STAR",e.DOT="DOT",e.EOF="EOF",e.ILLEGAL="ILLEGAL"}(Le||(Le={}));const ve={SELECT:Le.SELECT,FROM:Le.FROM,WHERE:Le.WHERE,INSERT:Le.INSERT,INTO:Le.INTO,VALUES:Le.VALUES,UPDATE:Le.UPDATE,SET:Le.SET,DELETE:Le.DELETE,CREATE:Le.CREATE,TABLE:Le.TABLE,DROP:Le.DROP,ORDER:Le.ORDER,BY:Le.BY,ASC:Le.ASC,DESC:Le.DESC,LIMIT:Le.LIMIT,OFFSET:Le.OFFSET,AND:Le.AND,OR:Le.OR,NOT:Le.NOT,LIKE:Le.LIKE,IN:Le.IN,PRIMARY:Le.PRIMARY,KEY:Le.KEY,UNIQUE:Le.UNIQUE,DEFAULT:Le.DEFAULT,NULL:Le.NULL,TRUE:Le.TRUE,FALSE:Le.FALSE,REFERENCES:Le.REFERENCES,CASCADE:Le.CASCADE,BETWEEN:Le.BETWEEN,IF:Le.IF,EXISTS:Le.EXISTS,ALTER:Le.ALTER,ADD:Le.ADD,TRUNCATE:Le.TRUNCATE,INNER:Le.INNER,LEFT:Le.LEFT,RIGHT:Le.RIGHT,CROSS:Le.CROSS,JOIN:Le.JOIN,ON:Le.ON,AS:Le.AS,OUTER:Le.OUTER,GROUP:Le.GROUP,HAVING:Le.HAVING,COUNT:Le.COUNT,SUM:Le.SUM,AVG:Le.AVG,MIN:Le.MIN,MAX:Le.MAX,DISTINCT:Le.DISTINCT,BEGIN:Le.BEGIN,COMMIT:Le.COMMIT,ROLLBACK:Le.ROLLBACK,UNION:Le.UNION,ALL:Le.ALL,INDEX:Le.INDEX,CASE:Le.CASE,WHEN:Le.WHEN,THEN:Le.THEN,ELSE:Le.ELSE,END:Le.END,EXPLAIN:Le.EXPLAIN,ANALYZE:Le.ANALYZE,REINDEX:Le.REINDEX,VACUUM:Le.VACUUM,SAVEPOINT:Le.SAVEPOINT,RELEASE:Le.RELEASE,TO:Le.TO};class $e{constructor(e){this.position=0,this.readPosition=0,this.ch="",this.input=e,this.readChar()}nextToken(){let e;switch(this.skipWhitespace(),this.ch){case",":e=this.makeToken(Le.COMMA,",");break;case"(":e=this.makeToken(Le.LPAREN,"(");break;case")":e=this.makeToken(Le.RPAREN,")");break;case";":e=this.makeToken(Le.SEMICOLON,";");break;case"*":e=this.makeToken(Le.STAR,"*");break;case".":e=this.makeToken(Le.DOT,".");break;case"=":e=this.makeToken(Le.EQ,"=");break;case"!":"="===this.peekChar()?(this.readChar(),e=this.makeToken(Le.NEQ,"!=")):e=this.makeToken(Le.ILLEGAL,"!");break;case">":"="===this.peekChar()?(this.readChar(),e=this.makeToken(Le.GTE,">=")):e=this.makeToken(Le.GT,">");break;case"<":"="===this.peekChar()?(this.readChar(),e=this.makeToken(Le.LTE,"<=")):">"===this.peekChar()?(this.readChar(),e=this.makeToken(Le.NEQ,"<>")):e=this.makeToken(Le.LT,"<");break;case"'":case'"':e=this.readString(this.ch);break;case"":e={type:Le.EOF,value:"",position:this.position};break;default:if("-"===this.ch&&"-"===this.peekChar())return this.skipLineComment(),this.nextToken();if("/"===this.ch&&"*"===this.peekChar())return this.skipBlockComment(),this.nextToken();if(this.isLetter(this.ch)){const t=this.readIdentifier();return e={type:ve[t.toUpperCase()]??Le.IDENTIFIER,value:t,position:this.position-t.length},e}if(this.isDigit(this.ch)||"-"===this.ch&&this.isDigit(this.peekChar())){const t=this.readNumber();return e={type:Le.NUMBER,value:t,position:this.position-t.length},e}e=this.makeToken(Le.ILLEGAL,this.ch)}return this.readChar(),e}readChar(){this.readPosition>=this.input.length?this.ch="":this.ch=this.input[this.readPosition],this.position=this.readPosition,this.readPosition++}peekChar(){return this.readPosition>=this.input.length?"":this.input[this.readPosition]}skipWhitespace(){for(;" "===this.ch||"\t"===this.ch||"\n"===this.ch||"\r"===this.ch;)this.readChar()}skipLineComment(){for(;"\n"!==this.ch&&"\r"!==this.ch&&""!==this.ch;)this.readChar()}skipBlockComment(){for(this.readChar(),this.readChar();""!==this.ch&&("*"!==this.ch||"/"!==this.peekChar());)this.readChar();""!==this.ch&&(this.readChar(),this.readChar())}readIdentifier(){const e=this.position;for(;this.isLetter(this.ch)||this.isDigit(this.ch)||"_"===this.ch;)this.readChar();return this.input.slice(e,this.position)}readNumber(){const e=this.position;for("-"===this.ch&&this.readChar();this.isDigit(this.ch);)this.readChar();if("."===this.ch&&this.isDigit(this.peekChar()))for(this.readChar();this.isDigit(this.ch);)this.readChar();return this.input.slice(e,this.position)}readString(e){const t=this.position+1;this.readChar();let s="";for(;""!==this.ch;){if(this.ch===e){if(this.peekChar()===e){s+=e,this.readChar(),this.readChar();continue}break}"\\"!==this.ch||this.peekChar()!==e?(s+=this.ch,this.readChar()):(this.readChar(),s+=e,this.readChar())}if(""===this.ch)throw new n(`Unterminated string literal at position ${t}`,"PARSE_ERROR");return{type:Le.STRING,value:s,position:t}}isLetter(e){return/[a-zA-Z_]/.test(e)}isDigit(e){return/[0-9]/.test(e)}makeToken(e,t){return{type:e,value:t,position:this.position}}}class De{constructor(e){this.sql=e,this.lexer=new $e(e),this.nextToken(),this.nextToken()}parseStatement(){switch(this.curToken.type){case Le.SELECT:return this.parseSelect();case Le.INSERT:return this.parseInsert();case Le.UPDATE:return this.parseUpdate();case Le.DELETE:return this.parseDelete();case Le.CREATE:return this.parseCreateStatement();case Le.DROP:return this.parseDropStatement();case Le.ALTER:return this.parseAlterTable();case Le.TRUNCATE:return this.parseTruncateTable();case Le.BEGIN:return this.parseBegin();case Le.COMMIT:return this.parseCommit();case Le.ROLLBACK:return this.parseRollback();case Le.EXPLAIN:return this.parseExplain();case Le.ANALYZE:return this.parseAnalyze();case Le.REINDEX:return this.parseReindex();case Le.VACUUM:return this.parseVacuum();case Le.SAVEPOINT:case Le.RELEASE:return this.parseSavepoint();default:throw this.error(`Unexpected token "${this.curToken.value}"`)}}parseAllStatements(){const e=[];for(;!this.curTokenIs(Le.EOF);){for(;this.curTokenIs(Le.SEMICOLON);)this.nextToken();if(this.curTokenIs(Le.EOF))break;if(e.push(this.parseStatement()),this.curTokenIs(Le.SEMICOLON))this.nextToken();else if(!this.curTokenIs(Le.EOF))throw this.error(`Expected ';' after statement, got "${this.curToken.value}"`)}return e}parseExplain(){if(this.expect(Le.EXPLAIN),this.curTokenIs(Le.EXPLAIN))throw this.error("Nested EXPLAIN is not allowed");return{type:"EXPLAIN",query:this.parseStatement()}}parseAnalyze(){return this.expect(Le.ANALYZE),this._isKeywordAsIdent()&&"TABLE"===this.curToken.value.toUpperCase()&&this.nextToken(),{type:"ANALYZE",table:this.expectIdentifier("table name")}}parseReindex(){return this.expect(Le.REINDEX),this._isKeywordAsIdent()&&"TABLE"===this.curToken.value.toUpperCase()&&this.nextToken(),{type:"REINDEX",table:this.expectIdentifier("table name")}}parseVacuum(){return this.expect(Le.VACUUM),{type:"VACUUM"}}parseSavepoint(){let e;return this.curTokenIs(Le.RELEASE)?(e="RELEASE",this.nextToken()):(e="SAVE",this.expect(Le.SAVEPOINT)),this.curTokenIs(Le.SAVEPOINT)&&this.nextToken(),{type:"SAVEPOINT",name:this.expectIdentifier("savepoint name"),action:e}}parseBegin(){return this.expect(Le.BEGIN),this._isKeywordAsIdent()&&"TRANSACTION"===this.curToken.value.toUpperCase()&&this.nextToken(),{type:"BEGIN"}}parseCommit(){return this.expect(Le.COMMIT),this._isKeywordAsIdent()&&"TRANSACTION"===this.curToken.value.toUpperCase()&&this.nextToken(),{type:"COMMIT"}}parseRollback(){return this.expect(Le.ROLLBACK),this._isKeywordAsIdent()&&"TRANSACTION"===this.curToken.value.toUpperCase()?(this.nextToken(),{type:"ROLLBACK"}):this.curTokenIs(Le.TO)||this._isKeywordAsIdent()&&"TO"===this.curToken.value.toUpperCase()?(this.nextToken(),(this.curTokenIs(Le.SAVEPOINT)||this._isKeywordAsIdent()&&"SAVEPOINT"===this.curToken.value.toUpperCase())&&this.nextToken(),{type:"SAVEPOINT",name:this.expectIdentifier("savepoint name"),action:"ROLLBACK"}):{type:"ROLLBACK"}}parseCreateStatement(){if(this.expect(Le.CREATE),this.curTokenIs(Le.TABLE))return this.parseCreateTable();if(this.curTokenIs(Le.INDEX)||this._isKeywordAsIdent()&&"INDEX"===this.curToken.value.toUpperCase())return this.parseCreateIndex();if(this.curTokenIs(Le.UNIQUE)&&(this.nextToken(),this.curTokenIs(Le.INDEX)||this._isKeywordAsIdent()&&"INDEX"===this.curToken.value.toUpperCase())){const e=this.parseCreateIndex();return e.unique=!0,e}throw this.error(`Expected TABLE or INDEX after CREATE, got "${this.curToken.value}"`)}parseCreateIndex(){this.expect(Le.INDEX);const e=this.expectIdentifier("index name");this.expect(Le.ON);const t=this.expectIdentifier("table name");this.expect(Le.LPAREN);const s=this.expectIdentifier("column name");return this.expect(Le.RPAREN),{type:"CREATE_INDEX",name:e,table:t,column:s}}parseDropStatement(){if(this.expect(Le.DROP),this.curTokenIs(Le.TABLE))return this.parseDropTable();if(this.curTokenIs(Le.INDEX)||this._isKeywordAsIdent()&&"INDEX"===this.curToken.value.toUpperCase())return this.parseDropIndex();throw this.error(`Expected TABLE or INDEX after DROP, got "${this.curToken.value}"`)}parseDropIndex(){this.expect(Le.INDEX);const e=this.expectIdentifier("index name");let t="",s="";return this.curTokenIs(Le.ON)&&(this.nextToken(),t=this.expectIdentifier("table name"),this.curTokenIs(Le.LPAREN)&&(this.nextToken(),s=this.expectIdentifier("column name"),this.expect(Le.RPAREN))),{type:"DROP_INDEX",name:e,table:t,column:s}}parseSelect(){this.expect(Le.SELECT);let e=!1;this.curTokenIs(Le.DISTINCT)&&(e=!0,this.nextToken());const t=[];let s;this.curTokenIs(Le.STAR)?(t.push("*"),this.nextToken()):t.push(...this.parseColumnList());let n,i="";this.curTokenIs(Le.FROM)&&(this.nextToken(),this.curTokenIs(Le.LPAREN)?(this.nextToken(),s=this.parseSelect(),this.expect(Le.RPAREN),this.curTokenIs(Le.AS)?(this.nextToken(),n=this.expectIdentifier("alias")):this.curToken.type!==Le.IDENTIFIER||this._isReservedAfterFrom()||(n=this.curToken.value,this.nextToken())):(i=this.expectIdentifier("table name"),this.curTokenIs(Le.AS)?(this.nextToken(),n=this.expectIdentifier("alias")):this.curToken.type!==Le.IDENTIFIER||this._isReservedAfterFrom()||(n=this.curToken.value,this.nextToken())));const r={type:"SELECT",columns:t,distinct:e||void 0,from:i,alias:n,where:{}};s&&(r.fromSubquery=s);const a=this.parseJoinClauses();return a.length>0&&(r.joins=a),this.curTokenIs(Le.WHERE)&&(this.nextToken(),r.where=this.parseCondition()),this.curTokenIs(Le.GROUP)&&(this.nextToken(),this.expect(Le.BY),r.groupBy=this.parseIdentifierList()),this.curTokenIs(Le.HAVING)&&(this.nextToken(),r.having=this.parseCondition()),this.curTokenIs(Le.ORDER)&&(this.nextToken(),this.expect(Le.BY),r.orderBy=this.parseOrderByList()),this.curTokenIs(Le.LIMIT)&&(this.nextToken(),r.limit=this.expectNumber("LIMIT value")),this.curTokenIs(Le.OFFSET)&&(this.nextToken(),r.offset=this.expectNumber("OFFSET value")),this.curTokenIs(Le.UNION)?this.parseUnion(r):r}parseUnion(e){this.expect(Le.UNION);let t=!1;this.curTokenIs(Le.ALL)&&(t=!0,this.nextToken());const s={type:"SELECT_UNION",left:e,right:this.parseSelect(),all:t||void 0};return this.curTokenIs(Le.UNION)?this.parseUnionChain(s):s}parseUnionChain(e){this.expect(Le.UNION);let t=!1;this.curTokenIs(Le.ALL)&&(t=!0,this.nextToken());const s={type:"SELECT_UNION",left:e,right:this.parseSelect(),all:t||void 0};return this.curTokenIs(Le.UNION)?this.parseUnionChain(s):s}parseJoinClauses(){const e=[];for(;this._isJoinKeyword();)e.push(this.parseJoinClause());return e}_isJoinKeyword(){return this.curTokenIs(Le.INNER)||this.curTokenIs(Le.LEFT)||this.curTokenIs(Le.RIGHT)||this.curTokenIs(Le.CROSS)||this.curTokenIs(Le.JOIN)}parseJoinClause(){let e="INNER";this.curTokenIs(Le.INNER)?(e="INNER",this.nextToken()):this.curTokenIs(Le.LEFT)?(e="LEFT",this.nextToken(),this.curTokenIs(Le.OUTER)&&this.nextToken()):this.curTokenIs(Le.RIGHT)?(e="RIGHT",this.nextToken(),this.curTokenIs(Le.OUTER)&&this.nextToken()):this.curTokenIs(Le.CROSS)&&(e="CROSS",this.nextToken()),this.expect(Le.JOIN);const t=this.expectIdentifier("table name");let s;this.curTokenIs(Le.AS)?(this.nextToken(),s=this.expectIdentifier("alias")):this.curToken.type!==Le.IDENTIFIER||this._isJoinReserved()||(s=this.curToken.value,this.nextToken());let n={};return"CROSS"!==e&&this.curTokenIs(Le.ON)&&(this.nextToken(),n=this.parseCondition()),{type:e,table:t,alias:s,on:n}}_isReservedAfterFrom(){return this.curTokenIs(Le.WHERE)||this.curTokenIs(Le.ORDER)||this.curTokenIs(Le.LIMIT)||this.curTokenIs(Le.OFFSET)||this.curTokenIs(Le.GROUP)||this._isJoinKeyword()}_isJoinReserved(){return this.curTokenIs(Le.ON)||this.curTokenIs(Le.WHERE)||this.curTokenIs(Le.ORDER)||this.curTokenIs(Le.LIMIT)||this._isJoinKeyword()}parseInsert(){this.expect(Le.INSERT),this.expect(Le.INTO);const e=this.expectIdentifier("table name");let t;if(this.curTokenIs(Le.LPAREN)&&(this.nextToken(),t=this.parseIdentifierList(),this.expect(Le.RPAREN)),this.curTokenIs(Le.SELECT))return{type:"INSERT",into:e,columns:t,select:this.parseSelect()};this.expect(Le.VALUES);const s=[];do{this.curTokenIs(Le.COMMA)&&this.nextToken(),this.expect(Le.LPAREN);const e=this.parseValueList();this.expect(Le.RPAREN),s.push(e)}while(this.curTokenIs(Le.COMMA));return{type:"INSERT",into:e,columns:t,values:s}}parseUpdate(){this.expect(Le.UPDATE);const e=this.expectIdentifier("table name");this.expect(Le.SET);const t={};do{this.curTokenIs(Le.COMMA)&&this.nextToken();const e=this.expectIdentifier("column name");this.expect(Le.EQ),t[e]=this.parseValue()}while(this.curTokenIs(Le.COMMA));let s={};return this.curTokenIs(Le.WHERE)&&(this.nextToken(),s=this.parseCondition()),{type:"UPDATE",table:e,sets:t,where:s}}parseDelete(){this.expect(Le.DELETE),this.expect(Le.FROM);const e=this.expectIdentifier("table name");let t={};return this.curTokenIs(Le.WHERE)&&(this.nextToken(),t=this.parseCondition()),{type:"DELETE",from:e,where:t}}parseCreateTable(){this.expect(Le.TABLE);let e=!1;this.curTokenIs(Le.IF)&&(this.nextToken(),this.expect(Le.NOT),this.expect(Le.EXISTS),e=!0);const t=this.expectIdentifier("table name");this.expect(Le.LPAREN);const s=[];do{this.curTokenIs(Le.COMMA)&&this.nextToken(),s.push(this.parseColumnDef())}while(this.curTokenIs(Le.COMMA));return this.expect(Le.RPAREN),{type:"CREATE_TABLE",name:t,columns:s,ifNotExists:e||void 0}}parseColumnDef(){const e={name:this.expectIdentifier("column name"),type:this.expectIdentifier("column type").toLowerCase()};for(;this.curTokenIs(Le.PRIMARY)||this.curTokenIs(Le.UNIQUE)||this.curTokenIs(Le.NOT)||this.curTokenIs(Le.DEFAULT)||this.curTokenIs(Le.REFERENCES);)if(this.curTokenIs(Le.PRIMARY))this.nextToken(),this.expect(Le.KEY),e.primaryKey=!0;else if(this.curTokenIs(Le.UNIQUE))this.nextToken(),e.unique=!0;else if(this.curTokenIs(Le.NOT))this.nextToken(),this.expect(Le.NULL),e.required=!0;else if(this.curTokenIs(Le.DEFAULT))this.nextToken(),e.default=this.parseValue();else{if(!this.curTokenIs(Le.REFERENCES))break;{this.nextToken();const t=this.expectIdentifier("referenced table");this.expect(Le.LPAREN);const s=this.expectIdentifier("referenced column");for(this.expect(Le.RPAREN),e.references=`${t}.${s}`;this.curTokenIs(Le.ON);)if(this.nextToken(),this.curTokenIs(Le.DELETE))this.nextToken(),e.onDelete=this.parseCascadeAction();else{if(!this.curTokenIs(Le.UPDATE))break;this.nextToken(),e.onUpdate=this.parseCascadeAction()}}}return e}parseCascadeAction(){return this.curTokenIs(Le.CASCADE)?(this.nextToken(),"CASCADE"):this.curTokenIs(Le.SET)?(this.nextToken(),this.expect(Le.NULL),"SET NULL"):this.curToken.type===Le.IDENTIFIER&&"RESTRICT"===this.curToken.value.toUpperCase()?(this.nextToken(),"RESTRICT"):"RESTRICT"}parseAlterTable(){this.expect(Le.ALTER),this.expect(Le.TABLE);const e=this.expectIdentifier("table name");let t;if(this.curTokenIs(Le.ADD))return t="ADD",this.nextToken(),this.curToken.type===Le.IDENTIFIER&&"COLUMN"===this.curToken.value.toUpperCase()&&this.nextToken(),{type:"ALTER_TABLE",name:e,action:t,column:this.parseColumnDef()};if(this.curTokenIs(Le.DROP)||this._isKeywordAsIdent()&&"DROP"===this.curToken.value.toUpperCase())return t="DROP",this.nextToken(),this.curToken.type===Le.IDENTIFIER&&"COLUMN"===this.curToken.value.toUpperCase()&&this.nextToken(),{type:"ALTER_TABLE",name:e,action:t,column:{name:this.expectIdentifier("column name"),type:"string"}};throw this.error("Expected ADD or DROP in ALTER TABLE")}parseTruncateTable(){return this.expect(Le.TRUNCATE),this.expect(Le.TABLE),{type:"TRUNCATE_TABLE",name:this.expectIdentifier("table name")}}parseDropTable(){this.expect(Le.TABLE);let e=!1;return this.curTokenIs(Le.IF)&&(this.nextToken(),this.expect(Le.EXISTS),e=!0),{type:"DROP_TABLE",name:this.expectIdentifier("table name"),ifExists:e||void 0}}parseCondition(){let e=this.parseSimpleCondition();for(;this.curTokenIs(Le.AND)||this.curTokenIs(Le.OR);){const t=this.curTokenIs(Le.AND);this.nextToken();const s=this.parseSimpleCondition();e=t?{$and:[e,s]}:{$or:[e,s]}}return e}parseWhere(){return this.parseCondition()}parseSimpleCondition(){if(this.curTokenIs(Le.EXISTS)||this._isKeywordAsIdent()&&"EXISTS"===this.curToken.value.toUpperCase())return this.nextToken(),this.parseExistsCondition(!1);if(this.curTokenIs(Le.NOT)&&this._peekIsExists())return this.nextToken(),this.nextToken(),this.parseExistsCondition(!0);if(this.curTokenIs(Le.NOT)&&!this._isNotInOrLike())return this.nextToken(),{$not:this.parseSimpleCondition()};if(this.curTokenIs(Le.LPAREN)){this.nextToken();const e=this.parseCondition();return this.expect(Le.RPAREN),e}const e=this.parseColumnRef();if(this.curTokenIs(Le.IDENTIFIER)&&"IS"===this.curToken.value.toUpperCase()){this.nextToken();const t=this.curTokenIs(Le.NOT);t&&this.nextToken(),this.expect(Le.NULL);const s={};return s[e]=t?{$ne:null}:{$eq:null},s}if(this.curTokenIs(Le.BETWEEN)){this.nextToken();const t=this.parseValue();this.expect(Le.AND);const s=this.parseValue(),n={};return n[e]={$gte:t,$lte:s},n}if(this.curTokenIs(Le.NOT)&&this.peekTokenIs(Le.BETWEEN)){this.nextToken(),this.nextToken();const t=this.parseValue();this.expect(Le.AND);const s=this.parseValue(),n={};return n[e]={$not:{$gte:t,$lte:s}},n}if(this.curTokenIs(Le.NOT)){if(this.peekTokenIs(Le.IN)){if(this.nextToken(),this.nextToken(),this.expect(Le.LPAREN),this.curTokenIs(Le.SELECT)){const t=this.parseSelect();this.expect(Le.RPAREN);const s={};return s[e]={$nin:{$subquery:t}},s}const t=this.parseValueList();this.expect(Le.RPAREN);const s={};return s[e]={$nin:t},s}if(this.peekTokenIs(Le.LIKE)){this.nextToken(),this.nextToken();const t=this.parseValue(),s={};return s[e]={$not:{$like:t}},s}}if(this.curTokenIs(Le.LIKE)){this.nextToken();const t=this.parseValue(),s={};return s[e]={$like:t},s}if(this.curTokenIs(Le.IN)){if(this.nextToken(),this.expect(Le.LPAREN),this.curTokenIs(Le.SELECT)){const t=this.parseSelect();this.expect(Le.RPAREN);const s={};return s[e]={$in:{$subquery:t}},s}const t=this.parseValueList();this.expect(Le.RPAREN);const s={};return s[e]={$in:t},s}if(this.curTokenIs(Le.AND)||this.curTokenIs(Le.OR)||this.curTokenIs(Le.RPAREN)||this.curTokenIs(Le.EOF)||this.curToken.type===Le.IDENTIFIER&&["THEN","END","ELSE","NULLS","LIMIT","OFFSET","ORDER","GROUP","HAVING","UNION","WHERE"].includes(this.curToken.value.toUpperCase())){const t={};return t[e]={$eq:!0},t}const t=this.parseComparisonOp();if(this.curTokenIs(Le.LPAREN)&&this.peekTokenIs(Le.SELECT)){this.nextToken();const s=this.parseSelect();this.expect(Le.RPAREN);const n={};return n[e]={[t]:{$subquery:s}},n}let s;s=(this.curToken.type===Le.IDENTIFIER||this._isKeywordAsIdent())&&this.peekTokenIs(Le.DOT)?{$col:this.parseColumnRef()}:this.parseValue();const n={};return n[e]={[t]:s},n}parseExistsCondition(e){this.expect(Le.LPAREN);const t=this.parseSelect();return this.expect(Le.RPAREN),{$exists:{$subquery:t,$negate:e||void 0}}}_peekIsExists(){return this.peekToken.type===Le.EXISTS||this.peekToken.type===Le.IDENTIFIER&&"EXISTS"===this.peekToken.value.toUpperCase()}_isNotInOrLike(){return this.peekTokenIs(Le.IN)||this.peekTokenIs(Le.LIKE)}peekTokenIs(e){return this.peekToken.type===e}parseComparisonOp(){switch(this.curToken.type){case Le.EQ:return this.nextToken(),"$eq";case Le.NEQ:return this.nextToken(),"$ne";case Le.GT:return this.nextToken(),"$gt";case Le.GTE:return this.nextToken(),"$gte";case Le.LT:return this.nextToken(),"$lt";case Le.LTE:return this.nextToken(),"$lte";default:throw this.error(`Expected comparison operator, got "${this.curToken.value}"`)}}parseColumnList(){const e=[];for(e.push(this.parseColumnWithAlias());this.curTokenIs(Le.COMMA);)this.nextToken(),e.push(this.parseColumnWithAlias());return e}parseColumnWithAlias(){let e=this.parseColumnRef();if(this.curTokenIs(Le.AS))this.nextToken(),e=`${e} AS ${this.expectIdentifier("alias")}`;else if(this.curToken.type===Le.IDENTIFIER&&!this._isReservedAfterFrom()&&!this._isJoinKeyword()){const t=this.curToken.value;this.nextToken(),e=`${e} AS ${t}`}return e}parseColumnRef(){if(this.curTokenIs(Le.CASE))return this.parseCaseExpressionText();if(this.curTokenIs(Le.NUMBER)){const e=this.curToken.value;return this.nextToken(),e}if(this.curTokenIs(Le.STRING)){const e=this.curToken.value;return this.nextToken(),`'${e}'`}if(this.curTokenIs(Le.COUNT)||this.curTokenIs(Le.SUM)||this.curTokenIs(Le.AVG)||this.curTokenIs(Le.MIN)||this.curTokenIs(Le.MAX))return this.parseAggregateCall();const e=this.expectIdentifier("column name");return this.curTokenIs(Le.DOT)?(this.nextToken(),`${e}.${this.expectIdentifier("column name")}`):e}parseCaseExpressionText(){const e=this.curToken.position;this.nextToken();let t=1,s=e+4;for(;!this.curTokenIs(Le.EOF)&&t>0&&(this.curTokenIs(Le.CASE)&&t++,!this.curTokenIs(Le.END)||(t--,s=this.curToken.position+3,this.nextToken(),0!==t));)s=this.curToken.position+this.curToken.value.length,this.nextToken();let n=this.sql.slice(e,s);return this.curTokenIs(Le.AS)?(this.nextToken(),n+=` AS ${this.expectIdentifier("alias")}`):this.curToken.type!==Le.IDENTIFIER||this.curTokenIs(Le.COMMA)||this._isReservedAfterFrom()||(n+=` AS ${this.curToken.value}`,this.nextToken()),n}parseAggregateCall(){const e=this.curToken.value.toUpperCase();this.nextToken(),this.expect(Le.LPAREN);let t,s=!1;this.curTokenIs(Le.DISTINCT)&&(s=!0,this.nextToken()),this.curTokenIs(Le.STAR)?(t="*",this.nextToken()):t=this.parseColumnRef(),this.expect(Le.RPAREN);let n="";this.curTokenIs(Le.AS)?(this.nextToken(),n=this.expectIdentifier("alias")):this.curToken.type===Le.IDENTIFIER&&this._isAggregateAlias()&&(n=this.curToken.value,this.nextToken());const i=s?`DISTINCT ${t}`:t;return n?`${e}(${i}) AS ${n}`:`${e}(${i})`}_isAggregateAlias(){return!this._isReservedAfterFrom()&&!this._isJoinKeyword()}parseIdentifierList(){const e=[];for(e.push(this.parseIdentifierWithDot());this.curTokenIs(Le.COMMA);)this.nextToken(),e.push(this.parseIdentifierWithDot());return e}parseValueList(){const e=[];for(e.push(this.parseValue());this.curTokenIs(Le.COMMA);)this.nextToken(),e.push(this.parseValue());return e}parseOrderByList(){const e=[];for(e.push(this.parseOrderBy());this.curTokenIs(Le.COMMA);)this.nextToken(),e.push(this.parseOrderBy());return e}parseOrderBy(){const e=this.parseIdentifierWithDot();let t,s="asc";return this.curTokenIs(Le.ASC)?this.nextToken():this.curTokenIs(Le.DESC)&&(s="desc",this.nextToken()),this.curTokenIs(Le.IDENTIFIER)&&"NULLS"===this.curToken.value.toUpperCase()&&(this.nextToken(),this.curTokenIs(Le.IDENTIFIER)&&"FIRST"===this.curToken.value.toUpperCase()?(t="first",this.nextToken()):this.curTokenIs(Le.IDENTIFIER)&&"LAST"===this.curToken.value.toUpperCase()&&(t="last",this.nextToken())),{column:e,direction:s,...t?{nulls:t}:{}}}parseIdentifierWithDot(){const e=this.expectIdentifier("identifier");return this.curTokenIs(Le.DOT)?(this.nextToken(),`${e}.${this.expectIdentifier("identifier")}`):e}parseValue(){switch(this.curToken.type){case Le.STRING:{const e=this.curToken.value;return this.nextToken(),e}case Le.NUMBER:{const e=Number(this.curToken.value);return this.nextToken(),e}case Le.TRUE:return this.nextToken(),!0;case Le.FALSE:return this.nextToken(),!1;case Le.NULL:return this.nextToken(),null;default:throw this.error(`Expected value, got "${this.curToken.value}"`)}}nextToken(){this.curToken=this.peekToken,this.peekToken=this.lexer.nextToken()}curTokenIs(e){return this.curToken.type===e}expect(e){if(!this.curTokenIs(e))throw this.error(`Expected ${e}, got "${this.curToken.value}"`);this.nextToken()}expectIdentifier(e){if(this.curToken.type===Le.IDENTIFIER||this._isKeywordAsIdent()){const e=this.curToken.value;return this.nextToken(),e}throw this.error(`Expected ${e}, got "${this.curToken.value}"`)}_isKeywordAsIdent(){return this.curToken.type!==Le.EOF&&this.curToken.type!==Le.ILLEGAL&&this.curToken.type!==Le.STRING&&this.curToken.type!==Le.NUMBER&&this.curToken.type!==Le.COMMA&&this.curToken.type!==Le.LPAREN&&this.curToken.type!==Le.RPAREN&&this.curToken.type!==Le.SEMICOLON&&this.curToken.type!==Le.EQ&&this.curToken.type!==Le.NEQ&&this.curToken.type!==Le.GT&&this.curToken.type!==Le.GTE&&this.curToken.type!==Le.LT&&this.curToken.type!==Le.LTE&&this.curToken.type!==Le.DOT&&this.curToken.type!==Le.STAR}expectNumber(e){if(this.curToken.type===Le.NUMBER){const e=Number(this.curToken.value);return this.nextToken(),e}throw this.error(`Expected ${e}, got "${this.curToken.value}"`)}error(e){return new n(`Parse error at position ${this.curToken.position}: ${e}`,"PARSE_ERROR")}}function Ue(e){return new De(e).parseAllStatements()}function _e(e){return new De(e).parseWhere()}function Me(e){const t=e.match(/^\s*CASE\s+([\s\S]*?)\s+END\s*(?:AS\s+(\w+))?\s*$/i);if(!t)return null;const s=t[1],n=t[2]??null,i=[],r=/WHEN\s+([\s\S]*?)\s+THEN\s+([\s\S]*?)(?=\s+WHEN\s+|\s+ELSE\s+|\s*$)/gi;let a;for(;null!==(a=r.exec(s));){let e=null;try{e=_e(a[1].trim())}catch{}i.push({cond:e,value:a[2].trim()})}let o=null;const h=s.match(/\sELSE\s+([\s\S]*)$/i);return h&&(o=h[1].trim()),{whens:i,elseValue:o,alias:n}}function Pe(e,t){const s=e.trim();if("null"===s)return null;if("true"===s)return!0;if("false"===s)return!1;const n=Number(s);if(""!==s&&!isNaN(n))return n;const i=s.match(/^'(.*)'$/s)||s.match(/^"(.*)"$/s);return i?i[1]:/^[a-zA-Z_][a-zA-Z0-9_.]*$/.test(s)?t[s]??null:s}function Be(e,t){for(const{cond:s,value:n}of e.whens)if(s&&a(t,s))return Pe(n,t);return null!==e.elseValue?Pe(e.elseValue,t):null}class Ke{constructor(e,t=0){this.engine=e,this.maxRowsPerQuery=t}async execute(e){switch(e.type){case"SELECT":return this.executeSelect(e);case"SELECT_UNION":return this.executeSelectUnion(e);case"EXPLAIN":return this.executeExplain(e);case"INSERT":return this.executeInsert(e);case"UPDATE":return this.executeUpdate(e);case"DELETE":return this.executeDelete(e);case"CREATE_TABLE":return this.executeCreateTable(e);case"DROP_TABLE":return this.executeDropTable(e);case"ALTER_TABLE":return this.executeAlterTable(e);case"TRUNCATE_TABLE":return this.executeTruncateTable(e);case"CREATE_INDEX":return this.executeCreateIndex(e);case"DROP_INDEX":return this.executeDropIndex(e);case"BEGIN":return this.executeBegin();case"COMMIT":return this.executeCommit();case"ROLLBACK":return this.executeRollback();case"SAVEPOINT":return this.executeSavepoint(e);case"ANALYZE":return this.executeAnalyze(e);case"REINDEX":return this.executeReindex(e);case"VACUUM":return this.executeVacuum();default:throw new n("Unknown statement type","UNKNOWN_STATEMENT")}}async executeSelectUnion(e){const t=await this.executeSelectPart(e.left),s=await this.executeSelectPart(e.right),n=t.length>0?Object.keys(t[0]):[],i=t.map(e=>e);if(e.all){for(const e of s)i.push(this.projectUnionRow(e,n));return i}const r=new Set,a=[];for(const e of i){const t=Object.values(e).map(e=>String(e??"\0")).join("");r.has(t)||(r.add(t),a.push(e))}for(const e of s){const t=this.projectUnionRow(e,n),s=Object.values(t).map(e=>String(e??"\0")).join("");r.has(s)||(r.add(s),a.push(t))}return a}async executeSelectPart(e){return"SELECT_UNION"===e.type?this.executeSelectUnion(e):this.executeSelect(e)}projectUnionRow(e,t){if(0===t.length)return e;const s=Object.values(e),n={};for(let e=0;e<t.length;e++)n[t[e]]=e<s.length?s[e]:null;return n}async executeExplain(e){const t=Date.now();let s=null,n=0;if("SELECT"===e.query.type||"SELECT_UNION"===e.query.type){try{s=await this.execute(e.query)}catch{}n=Array.isArray(s)?s.length:0}else if("UPDATE"===e.query.type||"DELETE"===e.query.type)try{const t=Ne(e.query);n=await this.engine.count(t.table,t)}catch{n=0}const i=Date.now()-t;let r=null;try{r=Ne(e.query)}catch{}let a="none";if(r&&r.table&&r.where&&Object.keys(r.where).length>0)try{const e=await this.engine.getTableSchema(r.table);if(e)for(const t of Object.keys(r.where)){if(t.startsWith("$"))continue;const s=e.columns[t];if(s){if(s.primaryKey){a="pk";break}if(s.index||s.unique){a=`index:${t}`;break}}}}catch{}return{type:e.query.type,table:r?.table,columns:r?.columns,where:r?.where||{},orderBy:r?.orderBy||[],limit:r?.limit,offset:r?.offset,usingIndex:a,estimatedRows:n,actualTimeMs:i}}async executeSelect(e){const t=!!(e.groupBy&&e.groupBy.length>0),s=!t&&this._hasAggregateColumn(e.columns);let n;const i=!!(e.joins&&e.joins.length>0),r=this.hasCaseColumn(e.columns)||!!e.where&&this.whereHasCase(e.where),o=this.orderByUsesSelectAlias(e),h=e.columns.some(e=>/\s+AS\s+\w+$/i.test(e));if(e.fromSubquery){const t=await this.executeSelectPart(e.fromSubquery);n=i?await this.executeJoinSelect(e,t.map(t=>this.prefixRow(t,e.alias??""))):t,!i&&e.where&&Object.keys(e.where).length>0&&(e.where=await this.resolveSubqueries(e.where),n=n.filter(t=>a(t,e.where)))}else if(e.from||i)if(i)n=await this.executeJoinSelect(e);else{e.where&&Object.keys(e.where).length>0&&(e.where=this.normalizeWhereColumns(e.where,[e.alias??e.from]));const i=[e.alias??e.from].filter(Boolean);if(e.orderBy&&e.orderBy.length>0&&(e.orderBy=e.orderBy.map(e=>({...e,column:this.stripAlias(e.column,i)}))),e.groupBy&&e.groupBy.length>0&&(e.groupBy=e.groupBy.map(e=>this.stripAlias(e,i))),e.columns=e.columns.map(e=>{if("*"===e||/^(COUNT|SUM|AVG|MIN|MAX)\(/i.test(e)||/^\s*CASE\b/i.test(e)||/^'/.test(e))return e;const t=e.match(/^(.+?)\s+AS\s+(\w+)$/i);if(t){const s=this.stripAlias(t[1].trim(),i);return s===t[1].trim()?e:`${s} AS ${t[2]}`}return this.stripAlias(e,i)}),e.where&&this.hasCorrelatedRefs(e.where)){const i=Ne(t||s?{...e,columns:["*"]}:e);i.columns=["*"],o&&(i.orderBy=void 0,i.limit=void 0,i.offset=void 0),n=await this.engine.find(i.table,{...i,where:this.stripCorrelatedExists(e.where)}),n=await this.filterCorrelated(n,e.where)}else{e.where&&Object.keys(e.where).length>0&&(e.where=await this.resolveSubqueries(e.where));const i=Ne(t||s?{...e,columns:["*"]}:e);(r||h)&&(i.columns=["*"]),o&&(i.orderBy=void 0,i.limit=void 0,i.offset=void 0),n=await this.engine.find(i.table,i)}}else n=[{}];if(s&&(n=[this.computeSingleAggregate(n,e)]),t&&(n=this.executeGroupBy(n,e)),e.distinct&&(n=this.executeDistinct(n)),e.having&&Object.keys(e.having).length>0){e.having=await this.resolveSubqueries(e.having);const t=e._aggAliasMap;if(t&&t.size>0){const s={};for(const[n,i]of Object.entries(e.having))s[t.get(n)??n]=i;e.having=s}n=n.filter(t=>a(t,e.having))}e.orderBy&&e.orderBy.length>0&&(n=c(n,e.orderBy)),!t&&!s&&e.columns.length>0&&"*"!==e.columns[0]&&(n=n.map(t=>this.projectRow(t,e.columns))),o&&e.orderBy&&e.orderBy.length>0&&(n=c(n,e.orderBy));const l=e.offset??0,u=e.limit??n.length;return n=n.slice(l,l+u),this.maxRowsPerQuery>0&&n.length>this.maxRowsPerQuery&&(n=n.slice(0,this.maxRowsPerQuery)),n}async executeJoinSelect(e,t){const s=e.alias??e.from;let n;if(t)n=t;else{const{pushable:t}=this.extractPushableWhere(e.where??{},s);n=(await this.engine.find(e.from,{table:e.from,where:Object.keys(t).length>0?t:void 0})).map(e=>this.prefixRow(e,s))}let i=n;for(const t of e.joins){const e=t.alias??t.table,n=await this.tryHashJoin(i,t,e,s);if(n){i=n;continue}const r=(await this.engine.find(t.table,{table:t.table})).map(t=>this.prefixRow(t,e));i=this.joinRows(i,r,t)}return e.where&&Object.keys(e.where).length>0&&(this.hasCorrelatedRefs(e.where)?i=await this.filterCorrelated(i,e.where):(e.where=await this.resolveSubqueries(e.where),i=i.filter(t=>a(t,e.where)))),i}prefixRow(e,t){const s={};for(const[n,i]of Object.entries(e))s[`${t}.${n}`]=i;return s}extractPushableWhere(e,t){const s={};if(!t)return{pushable:s};const n=`${t}.`;for(const[t,i]of Object.entries(e))t.startsWith(n)&&("object"==typeof i&&null!==i&&("$col"in i||"$subquery"in i||"$and"in i||"$or"in i||"$not"in i)||(s[t.slice(n.length)]=i));return{pushable:s}}async tryHashJoin(e,t,s,n){if("CROSS"===t.type||"RIGHT"===t.type)return null;const i=[],r=e=>{for(const[t,s]of Object.entries(e)){if("$and"===t){if(!s.every(r))return!1;continue}if("$or"===t||"$not"===t)return!1;let e=null;if("object"==typeof s&&null!==s){const t=s;"$eq"in t&&"object"==typeof t.$eq&&null!==t.$eq&&"$col"in t.$eq?e=String(t.$eq.$col):"$col"in t&&1===Object.keys(t).length&&(e=String(t.$col))}if(!e)return!1;const a=!!n&&t.startsWith(`${n}.`);i.push({leftCol:a?t:e,rightCol:a?e:t})}return!0};if(!r(t.on))return null;if(0===i.length)return null;const a=await this.engine.getTableSchema(t.table);if(!a)return null;const o=i.find(e=>{const t=e.rightCol.split(".").pop(),s=a.columns[t];return s&&(s.primaryKey||s.index||s.unique)});if(!o)return null;const h=o.rightCol.split(".").pop(),c=Array.from(new Set(e.map(e=>e[o.leftCol]).filter(e=>null!=e)));if(0===c.length)return null;const l=await this.engine.find(t.table,{table:t.table,where:{[h]:{$in:c}}}),u=new Map;for(const e of l){const t=i.map(t=>String(e[t.rightCol.split(".").pop()]??"\0")).join("");u.has(t)||u.set(t,[]),u.get(t).push(e)}const f={};for(const e of Object.keys(a.columns))f[e]=null;const d=[];for(const n of e){const e=i.map(e=>String(n[e.leftCol]??"\0")).join(""),r=u.get(e);if(r&&r.length>0)for(const e of r)d.push({...n,...this.prefixRow(e,s)});else"LEFT"===t.type&&d.push({...n,...this.prefixRow(f,s)})}return d}joinRows(e,t,s){if("CROSS"===s.type){const s=[];for(const n of e)for(const e of t)s.push({...n,...e});return s}const n=[];for(const i of e){let e=!1;for(const r of t){const t={...i,...r};a(t,s.on,{$col:!0})&&(n.push(t),e=!0)}if(!e&&"LEFT"===s.type){const e={};for(const s of Object.keys(t[0]??{}))e[s]=null;n.push({...i,...e})}}if("RIGHT"===s.type)for(const i of t)if(!e.some(e=>a({...e,...i},s.on,{$col:!0}))){const t={};for(const s of Object.keys(e[0]??{}))t[s]=null;n.push({...t,...i})}return n}executeGroupBy(e,t){const s=new Map;for(const n of e){const e=t.groupBy.map(e=>String(n[e]??"null")).join("|");s.has(e)||s.set(e,[]),s.get(e).push(n)}const n=[],i=new Map;for(const e of s.values()){const s={};for(const n of t.groupBy)s[n]=e[0][n];for(const n of t.columns){if("*"===n)continue;const r=n.match(/^(COUNT|SUM|AVG|MIN|MAX)\((.+?)\)(?:\s+AS\s+(\w+))?$/i);if(r){const[,t,a,o]=r,h=this.computeAggregate(t.toUpperCase(),e,a.trim()),c=`${t.toUpperCase()}(${a.trim()})`,l=o||n;l!==c&&i.set(c,l),s[l]=h}else if(/^\s*CASE\b/i.test(n)){const t=Me(n);s[t?.alias??n]=t?Be(t,e[0]):null}else t.groupBy.includes(n)||(s[n]=e[0][n])}n.push(s)}return t._aggAliasMap=i,n}computeAggregate(e,t,s){const n=/^\s*CASE\b/i.test(s)?Me(s):null,i=!n&&/^\s*DISTINCT\s+/i.test(s),r=i?s.replace(/^\s*DISTINCT\s+/i,"").trim():s,a=t.map(e=>n?Be(n,e):e[r]).filter(e=>null!=e);if("COUNT"===e)return"*"===r?t.length:i?new Set(a.map(e=>"object"==typeof e?JSON.stringify(e):String(e))).size:a.length;const o=a.map(Number),h=i?Array.from(new Set(o)):o;switch(e){case"SUM":return h.reduce((e,t)=>e+t,0);case"AVG":return 0===h.length?0:h.reduce((e,t)=>e+t,0)/h.length;case"MIN":return 0===h.length?0:Math.min(...h);case"MAX":return 0===h.length?0:Math.max(...h);default:return 0}}executeDistinct(e){const t=new Set;return e.filter(e=>{const s=Object.values(e).map(e=>String(e??"\0")).join("");return!t.has(s)&&(t.add(s),!0)})}async executeInsert(e){const t=await this.engine.getTableSchema(e.into);if(!t)throw new n(`Table "${e.into}" does not exist`,"TABLE_NOT_FOUND");const s=e.columns??Object.keys(t.columns);if(e.select){const t=await this.executeSelectPart(e.select);let n=[];const i=e.select;if("SELECT"===i.type)if(i.columns&&i.columns.length>0&&"*"!==i.columns[0])n=i.columns.map(e=>e.split(".").pop());else if(i.from){const e=await this.engine.getTableSchema(i.from);n=e?Object.keys(e.columns):[]}0===n.length&&t.length>0&&(n=Object.keys(t[0]));const r=t.map(e=>{const t={};for(let i=0;i<s.length;i++){const r=i<n.length?n[i]:null;r&&r in e&&(t[s[i]]=e[r])}return t});return this.engine.insert(e.into,r)}const i=(e.values??[]).map(e=>{const t={};for(let n=0;n<s.length;n++)n<e.length&&(t[s[n]]=e[n]);return t});return this.engine.insert(e.into,i)}async executeUpdate(e){const t=Ne(e);return this.engine.update(t.table,t,e.sets)}async executeDelete(e){const t=Ne(e);return this.engine.delete(t.table,t)}async executeCreateTable(e){if(e.ifNotExists&&await this.engine.hasTable(e.name))return;const t=Object.create(null);for(const s of e.columns)t[s.name]=p(s);return this.engine.createTable(f(e.name,t))}async executeDropTable(e){if(!e.ifExists||await this.engine.hasTable(e.name))return this.engine.dropTable(e.name)}async executeAlterTable(e){if(!await this.engine.hasTable(e.name))throw new n(`Table "${e.name}" does not exist`,"TABLE_NOT_FOUND");const t=await this.engine.getTableSchema(e.name);if(t){if("ADD"===e.action&&e.column.primaryKey&&Object.values(t.columns).some(e=>e.primaryKey))throw new n(`Composite primary keys are not supported yet: table "${e.name}" already has a primary key column`,"SCHEMA_ERROR");if("function"==typeof this.engine.alterTable)return this.engine.alterTable(e.name,e.action,{...p(e.column),name:e.column.name});if("ADD"===e.action){if(t.columns[e.column.name])throw new n(`Column "${e.column.name}" already exists in table "${e.name}"`,"COLUMN_EXISTS");t.columns[e.column.name]=p(e.column)}else if("DROP"===e.action){if(!t.columns[e.column.name])throw new n(`Column "${e.column.name}" does not exist in table "${e.name}"`,"COLUMN_NOT_FOUND");delete t.columns[e.column.name];const s=await this.engine.find(e.name,{table:e.name}),i=e.column.name;for(const e of s)i in e&&delete e[i]}}}async executeTruncateTable(e){if(!await this.engine.hasTable(e.name))throw new n(`Table "${e.name}" does not exist`,"TABLE_NOT_FOUND");return this.engine.clear(e.name)}async executeCreateIndex(e){if(!await this.engine.hasTable(e.table))throw new n(`Table "${e.table}" does not exist`,"TABLE_NOT_FOUND");const t=await this.engine.getTableSchema(e.table);if(t&&!t.columns[e.column])throw new n(`Column "${e.column}" does not exist in table "${e.table}"`,"COLUMN_NOT_FOUND");if("function"!=typeof this.engine.createIndex)throw new n(`Engine "${this.engine.name}" does not support CREATE INDEX`,"NOT_SUPPORTED");return this.engine.createIndex(e.table,e.column,e.unique)}async executeDropIndex(e){if("function"!=typeof this.engine.dropIndex)throw new n(`Engine "${this.engine.name}" does not support DROP INDEX`,"NOT_SUPPORTED");return this.engine.dropIndex(e.table,e.column,e.name)}async executeBegin(){return this.engine.beginTransaction()}async executeCommit(){return this.engine.commitTransaction()}async executeRollback(){return this.engine.rollbackTransaction()}async executeSavepoint(e){const t=this.engine;if("SAVE"===e.action){if("function"!=typeof t.savepoint)throw new n(`Engine "${this.engine.name}" does not support SAVEPOINT`,"NOT_SUPPORTED");return t.savepoint(e.name)}if("ROLLBACK"===e.action){if("function"!=typeof t.rollbackToSavepoint)throw new n(`Engine "${this.engine.name}" does not support ROLLBACK TO SAVEPOINT`,"NOT_SUPPORTED");return t.rollbackToSavepoint(e.name)}if("function"!=typeof t.releaseSavepoint)throw new n(`Engine "${this.engine.name}" does not support RELEASE SAVEPOINT`,"NOT_SUPPORTED");return t.releaseSavepoint(e.name)}async executeAnalyze(e){const t=this.engine;if("function"!=typeof t.analyzeTable)throw new n(`Engine "${this.engine.name}" does not support ANALYZE`,"NOT_SUPPORTED");if(!await this.engine.hasTable(e.table))throw new n(`Table "${e.table}" does not exist`,"TABLE_NOT_FOUND");return t.analyzeTable(e.table)}async executeReindex(e){const t=this.engine;if("function"!=typeof t.reindexTable)throw new n(`Engine "${this.engine.name}" does not support REINDEX`,"NOT_SUPPORTED");if(!await this.engine.hasTable(e.table))throw new n(`Table "${e.table}" does not exist`,"TABLE_NOT_FOUND");return t.reindexTable(e.table)}async executeVacuum(){const e=this.engine;if("function"!=typeof e.vacuum)throw new n(`Engine "${this.engine.name}" does not support VACUUM`,"NOT_SUPPORTED");return e.vacuum()}hasCaseColumn(e){return e.some(e=>/^\s*CASE\b/i.test(e))}orderByUsesSelectAlias(e){if(!e.orderBy||0===e.orderBy.length)return!1;const t=new Set;for(const s of e.columns){const e=s.match(/\s+AS\s+(\w+)$/i);if(e)t.add(e[1]);else if(/^\s*CASE\b/i.test(s)){const e=Me(s);e?.alias&&t.add(e.alias)}}return 0!==t.size&&e.orderBy.some(e=>t.has(e.column))}whereHasCase(e){for(const[t,s]of Object.entries(e))if("$and"!==t&&"$or"!==t){if("$not"!==t){if(/^\s*CASE\b/i.test(t))return!0}else if(this.whereHasCase(s))return!0}else if(s.some(e=>this.whereHasCase(e)))return!0;return!1}getEngine(){return this.engine}projectRow(e,t){const s=[],n=[],i=[],r=[];for(const e of t){if("*"===e)continue;const t=Me(e);if(t){i.push({alias:t.alias??e,expr:t});continue}const a=e.match(/^(.+?)\s+AS\s+(\w+)$/i);if(a){n.push({alias:a[2],source:a[1].trim()});continue}const o=e.match(/^'(.*)'$/s);if(o){const t=o[1].replace(/\\'/g,"'");r.push({key:e,value:t});continue}s.push(e)}const a=s.length>0?u(e,s):{};for(const{alias:t,source:s}of n)if("*"===s)Object.assign(a,e);else{const n=s.match(/^'(.*)'$/s);a[t]=n?n[1].replace(/\\'/g,"'"):e[s]}for(const{key:e,value:t}of r)a[e]=t;for(const{alias:t,expr:s}of i)a[t]=Be(s,e);return a}_hasAggregateColumn(e){return e.some(e=>/^(COUNT|SUM|AVG|MIN|MAX)\(/i.test(e))}computeSingleAggregate(e,t){const s={};for(const n of t.columns){if("*"===n)continue;const t=n.match(/^(COUNT|SUM|AVG|MIN|MAX)\((.+?)\)(?:\s+AS\s+(\w+))?$/i);if(t){const[,i,r,a]=t;s[a||n]=this.computeAggregate(i.toUpperCase(),e,r.trim())}else s[n]=e.length>0?e[0][n]:null}return s}normalizeWhereColumns(e,t){const s={};for(const[n,i]of Object.entries(e))"$and"!==n&&"$or"!==n?"$not"!==n?"$exists"!==n?s[this.stripAlias(n,t)]=this.normalizeFieldValue(i,t):s[n]=this.normalizeExistsValue(i,t):s.$not=this.normalizeWhereColumns(i,t):s[n]=i.map(e=>this.normalizeWhereColumns(e,t));return s}normalizeExistsValue(e,t){if("object"!=typeof e||null===e)return e;const s=e;if(s.$subquery){const e=s.$subquery,n=[e.alias??e.from,...t].filter(Boolean);return{...s,$subquery:{...e,where:this.normalizeWhereColumns(e.where,n)}}}return e}normalizeFieldValue(e,t){if("object"!=typeof e||null===e||Array.isArray(e))return e;const s={};for(const[n,i]of Object.entries(e))"$and"===n||"$or"===n?s[n]=i.map(e=>this.normalizeWhereColumns(e,t)):"$not"===n&&"object"==typeof i&&null!==i?s[n]=this.normalizeFieldValue(i,t):"$col"===n?s[n]=this.stripAlias(String(i),t):"object"==typeof i&&null!==i&&!Array.isArray(i)&&"$col"in i?s[n]={$col:this.stripAlias(String(i.$col),t)}:s[n]=i;return s}stripAlias(e,t){for(const s of t){if(!s)continue;const t=`${s}.`;if(e.startsWith(t))return e.slice(t.length)}return e}hasCorrelatedRefs(e){for(const[t,s]of Object.entries(e))if("$and"!==t&&"$or"!==t){if("$not"!==t){if("$exists"!==t){if(/^\s*CASE\b/i.test(t))return!0;if(this.fieldHasColRef(s))return!0}else if("object"==typeof s&&null!==s&&"$subquery"in s)return!0}else if(this.hasCorrelatedRefs(s))return!0}else if(s.some(e=>this.hasCorrelatedRefs(e)))return!0;return!1}fieldHasColRef(e){if("object"!=typeof e||null===e||Array.isArray(e))return!1;const t=e;if("$col"in t)return!0;if("$and"in t||"$or"in t)return(t.$and??t.$or).some(e=>this.hasCorrelatedRefs(e));if("$not"in t&&"object"==typeof t.$not&&null!==t.$not)return this.fieldHasColRef(t.$not);for(const[,e]of Object.entries(t))if("object"==typeof e&&null!==e&&!Array.isArray(e)){if("$col"in e)return!0;if(this.fieldHasColRef(e))return!0}return!1}stripCorrelatedExists(e){const t={};for(const[s,n]of Object.entries(e))if("$and"!==s&&"$or"!==s){if("$not"===s){const e=this.stripCorrelatedExists(n);Object.keys(e).length>0&&(t.$not=e);continue}"$exists"!==s&&(/^\s*CASE\b/i.test(s)||(t[s]=n))}else t[s]=n.map(e=>this.stripCorrelatedExists(e));return t}async filterCorrelated(e,t){const s=[];for(const n of e){let e=this.resolveCaseKeys(t,n);e=await this.resolveSubqueries(e,n),a(n,e)&&s.push(n)}return s}resolveCaseKeys(e,t){const s={};for(const[n,i]of Object.entries(e))if("$and"!==n&&"$or"!==n)if("$not"!==n){if(/^\s*CASE\b/i.test(n)){const e=Me(n);if(!e)continue;const r=Be(e,t);if(!this.caseConditionMatches(r,i))return{$caseResult:!1};s.$caseResult=!0;continue}s[n]=i}else s.$not=this.resolveCaseKeys(i,t);else s[n]=i.map(e=>this.resolveCaseKeys(e,t));return s}caseConditionMatches(e,t){if("object"!=typeof t||null===t||Array.isArray(t))return e===t;const s=t;for(const[t,n]of Object.entries(s))switch(t){case"$eq":if(e!==n)return!1;break;case"$ne":if(e===n)return!1;break;case"$gt":if(!(e>n))return!1;break;case"$gte":if(!(e>=n))return!1;break;case"$lt":if(!(e<n))return!1;break;case"$lte":if(!(e<=n))return!1;break;case"$in":if(!Array.isArray(n)||!n.includes(e))return!1;break;case"$nin":if(Array.isArray(n)&&n.includes(e))return!1}return!0}bindColumnRefs(e,t){if("object"!=typeof e||null===e||Array.isArray(e))return e;const s={};for(const[n,i]of Object.entries(e))"$col"===n?s[n]=t[String(i)]??null:"$and"===n||"$or"===n?s[n]=i.map(e=>this.bindWhereRefs(e,t)):"$not"===n&&"object"==typeof i&&null!==i?s[n]=this.bindColumnRefs(i,t):"object"==typeof i&&null!==i&&!Array.isArray(i)&&"$col"in i?s[n]=t[String(i.$col)]??null:s[n]=i;return s}bindWhereRefs(e,t){const s={};for(const[n,i]of Object.entries(e))"$and"===n||"$or"===n?s[n]=i.map(e=>this.bindWhereRefs(e,t)):"$not"===n?s.$not=this.bindWhereRefs(i,t):s[n]="$exists"===n?i:this.bindColumnRefs(i,t);return s}async resolveSubqueries(e,t){t&&(e=this.bindWhereRefs(e,t));const s={};for(const[n,i]of Object.entries(e)){if("$exists"===n&&"object"==typeof i&&null!==i){const e=i,n=e.$subquery,r=!!e.$negate;let a=n.where;this.hasCorrelatedRefs(a)&&(a=this.bindWhereRefs(a,t??{}));const o=await this.executeSelectPart({...n,where:a});s.$exists=o.length>0!==r;continue}"$and"===n&&Array.isArray(i)?s.$and=await Promise.all(i.map(e=>this.resolveSubqueries(e,t))):"$or"===n&&Array.isArray(i)?s.$or=await Promise.all(i.map(e=>this.resolveSubqueries(e,t))):"$not"!==n||"object"!=typeof i||null===i?s[n]="object"==typeof i&&null!==i?await this.resolveOperatorSubqueries(i):i:s.$not=await this.resolveSubqueries(i,t)}return s}async resolveOperatorSubqueries(e){const t={};for(const[s,n]of Object.entries(e))if("$and"===s&&Array.isArray(n))t.$and=await Promise.all(n.map(e=>this.resolveSubqueries(e)));else if("$or"===s&&Array.isArray(n))t.$or=await Promise.all(n.map(e=>this.resolveSubqueries(e)));else if("$not"!==s)if("object"==typeof n&&null!==n&&"$subquery"in n){const e=n.$subquery,i=await this.executeSelect(e);if("$in"===s||"$nin"===s){const e=Object.keys(i[0]||{})[0],n=i.map(t=>t[e]);t[s]=n}else if(0===i.length)t[s]=null;else{const e=Object.keys(i[0])[0];t[s]=i[0][e]}}else t[s]=n;else t.$not="object"==typeof n&&null!==n?await this.resolveOperatorSubqueries(n):n;return t}}function ze(e){if(null==e)return"NULL";if("number"==typeof e)return Number.isFinite(e)?String(e):"NULL";if("boolean"==typeof e)return e?"TRUE":"FALSE";if("string"==typeof e)return`'${e.replace(/'/g,"''")}'`;throw new n("Object/array query parameters are not supported by SQL binding (pass JSON strings explicitly)","PARAM_ERROR")}class Fe{constructor(e){this.tables=new Map,this.completed=!1,this.engine=e}table(e){let t=this.tables.get(e);return t||(t=new Oe(this.engine,e),this.tables.set(e,t)),t}_markCompleted(){this.completed=!0}isCompleted(){return this.completed}}class qe{constructor(e){this.engine=e}async execute(e){const t=new Fe(this.engine);await this.engine.beginTransaction();try{const s=await e(t);return await this.engine.commitTransaction(),t._markCompleted(),s}catch(e){try{await this.engine.rollbackTransaction()}catch{}if(e instanceof n)throw e;throw new n(`Transaction failed: ${e.message}`,"TRANSACTION_ERROR",e)}}}class je{constructor(){this.plugins=[],this.hooks=new Map}register(e,t){const s=e.priority??0,n=this.plugins.findIndex(e=>(e.priority??0)<s);-1===n?this.plugins.push(e):this.plugins.splice(n,0,e),e.install(t)}unregister(e){const t=this.plugins.findIndex(t=>t.name===e);-1!==t&&(this.plugins[t].destroy(),this.plugins.splice(t,1))}getPlugins(){return[...this.plugins]}on(e,t){const s=this.hooks.get(e)??[];s.push(t),this.hooks.set(e,s)}off(e,t){const s=this.hooks.get(e);if(s){const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}async trigger(e,...t){const s=this.hooks.get(e);if(s)for(const e of s)await e(...t)}destroy(){for(const e of this.plugins)try{e.destroy()}catch(e){}this.plugins=[],this.hooks.clear()}}class Ve{static async create(e){const t=new Ve(e);return await t.init(),t}get version(){return this._version}get maxRowsPerQuery(){return this.config.maxRowsPerQuery??0}get debug(){return this.config.debug??!1}constructor(e){this.ready=!1,this.tableCache=new Map,this.channel=null,this.listeners=new Map,this.migrations=new Map,this.config=e,this.name=e.name??s.name,this.mode=e.mode??s.mode,this._version=e.version??s.version,this.pluginManager=new je,e.multiTabSync&&"undefined"!=typeof BroadcastChannel&&(this.channel=new BroadcastChannel(`metona-sqlark:${this.name}`),this.channel.onmessage=e=>{const t=e.data;t&&"change"===t.type&&(this.emit(t.table??"",{type:"external",table:t.table??""}),this.engine instanceof Ie&&this.engine.reloadMemoryFromDisk().catch(()=>{}))})}async init(){if(this.engine=this.createEngine(),await this.engine.open(this.name,this.version),"function"==typeof this.engine.getMeta)try{const e=await this.engine.getMeta("__metona_version");null!=e&&Number(e)>=1&&(this._version=Math.max(this._version,Math.floor(Number(e))))}catch{}if(this.executor=new Ke(this.engine,this.maxRowsPerQuery),this.transactionManager=new qe(this.engine),this.config.plugins)for(const e of this.config.plugins)this.pluginManager.register(e,this);this.ready=!0,this.config.onReady&&this.config.onReady(this)}isReady(){return this.ready}async defineTable(e,t){this.ensureReady();const s=f(e,t);try{await this.pluginManager.trigger("beforeCreateTable",s),await this.engine.createTable(s),await this.pluginManager.trigger("afterCreateTable",s)}catch(e){throw this._onError(e),e}this.tableCache.delete(e)}table(e){this.ensureReady();let t=this.tableCache.get(e);return t||(t=new Oe(this.engine,e,this.executor,e=>this.broadcastChange(e),(e,t)=>this.pluginManager.trigger(e,...t)),this.tableCache.set(e,t)),t}async dropTable(e){this.ensureReady();try{await this.pluginManager.trigger("beforeDropTable",e),await this.engine.dropTable(e),await this.pluginManager.trigger("afterDropTable",e)}catch(e){throw this._onError(e),e}this.tableCache.delete(e)}async getTableNames(){return this.ensureReady(),this.engine.getTableNames()}async query(e,t){this.ensureReady();const s=this.debug?Date.now():0;let i;await this.pluginManager.trigger("beforeQuery",e);try{const s=function(e,t){if(!t)return e;let s="",i=0,r=0,a=null;for(;i<e.length;){const o=e[i];if(null===a)if("'"!==o&&'"'!==o)if("-"!==o||"-"!==e[i+1])if("/"!==o||"*"!==e[i+1])if("?"!==o)s+=o,i++;else{if(r>=t.length)throw new n(`Too few query parameters: placeholder #${r+1} has no value (got ${t.length} total)`,"PARAM_ERROR");s+=ze(t[r]),r++,i++}else{for(s+=e[i]+e[i+1],i+=2;i<e.length&&("*"!==e[i]||"/"!==e[i+1]);)s+=e[i],i++;i<e.length&&(s+=e[i]+e[i+1],i+=2)}else for(;i<e.length&&"\n"!==e[i]&&"\r"!==e[i];)s+=e[i],i++;else a=o,s+=o,i++;else{if(s+=o,o===a){if(e[i+1]===a){s+=e[i+1],i+=2;continue}a=null}i++}}if(null!==a)throw new n("Unterminated string literal in SQL","PARSE_ERROR");if(r<t.length)throw new n(`Too many query parameters: ${t.length} provided but only ${r} placeholders`,"PARAM_ERROR");return s}(e,t),r=Ue(s);for(const e of r){await this.triggerStatementHooks(e,"before"),i=await this.executor.execute(e),await this.triggerStatementHooks(e,"after",i);const t=this.writeStatementTable(e);t&&this.broadcastChange(t)}}catch(e){throw this._onError(e),e}if(await this.pluginManager.trigger("afterQuery",e,i),this.debug){const t=Date.now()-s,n=Array.isArray(i)?i.length:0;this._debug(`query [${t}ms] ${n} rows: ${e.slice(0,100)}`)}return i}async queryStream(e,t){this.ensureReady();const s=Ue(e)[0];if(!s||"SELECT"!==s.type)throw new n("queryStream only supports SELECT statements","NOT_SUPPORTED");const i=s,r=i.columns.some(e=>/^(COUNT|SUM|AVG|MIN|MAX)\(/i.test(e));if(!(i.joins||i.groupBy||i.having||i.distinct||r||i.orderBy&&i.orderBy.length>0||i.where&&void 0!==i.where.$exists)&&"function"==typeof this.engine.findStream&&"AsyncFunction"!==t.constructor?.name){const e=this.normalizeWhereForStream(i),s=i.columns.filter(e=>!/\s+AS\s+\w+$/i.test(e));return this.engine.findStream(i.from,{table:i.from,columns:s.length>0&&"*"!==s[0]?s:["*"],where:e&&Object.keys(e).length>0?e:void 0,limit:i.limit,offset:i.offset},t)}const a=await this.query(e);if(Array.isArray(a)){for(const e of a)await t(e);return a.length}return 0}normalizeWhereForStream(e){const t=[e.alias??e.from].filter(Boolean),s=e=>{for(const s of t)if(e.startsWith(`${s}.`))return e.slice(s.length+1);return e},n=e=>{const t={};for(const[i,r]of Object.entries(e))"$and"===i||"$or"===i?t[i]=r.map(n):"$not"===i&&"object"==typeof r&&null!==r?t.$not=n(r):t[s(i)]=r;return t};return n(e.where??{})}async transaction(e){this.ensureReady(),await this.pluginManager.trigger("beforeTransaction");try{const t=await this.transactionManager.execute(e);return await this.pluginManager.trigger("afterTransaction"),t}catch(e){throw this._onError(e),e}}async exportTable(e){return this.ensureReady(),this.engine.find(e,{table:e})}async importTable(e,t){this.ensureReady();try{return await this.engine.insert(e,t)}catch(e){throw this._onError(e),e}}async exportAll(){this.ensureReady();const e={},t=await this.engine.getTableNames();for(const s of t)e[s]=await this.engine.find(s,{table:s});return e}async backup(){return this.ensureReady(),"function"==typeof this.engine.backup?this.engine.backup():this.exportAll()}subscribe(e,t){const s=`change:${e}`;return this.listeners.has(s)||this.listeners.set(s,new Set),this.listeners.get(s).add(t),()=>this.listeners.get(s)?.delete(t)}emit(e,t){const s=`change:${e}`;this.listeners.get(s)?.forEach(e=>e(t))}broadcastChange(e){if(this.channel)try{this.channel.postMessage({type:"change",table:e})}catch{}}writeStatementTable(e){switch(e.type){case"INSERT":return e.into;case"UPDATE":case"CREATE_INDEX":case"DROP_INDEX":return e.table;case"DELETE":return e.from;case"CREATE_TABLE":case"DROP_TABLE":case"TRUNCATE_TABLE":case"ALTER_TABLE":return e.name;default:return null}}async triggerStatementHooks(e,t,s){switch(e.type){case"INSERT":{const n=(e.values??[]).map(t=>{const s={},n=e.columns??[];for(let e=0;e<t.length;e++)s[n[e]??String(e)]=t[e];return s});"before"===t?await this.pluginManager.trigger("beforeInsert",n):await this.pluginManager.trigger("afterInsert",n,s);break}case"UPDATE":{const n={table:e.table,where:e.where};"before"===t?await this.pluginManager.trigger("beforeUpdate",n,e.sets):await this.pluginManager.trigger("afterUpdate",n,e.sets,s);break}case"DELETE":{const n={table:e.from,where:e.where};"before"===t?await this.pluginManager.trigger("beforeDelete",n):await this.pluginManager.trigger("afterDelete",n,s);break}}}addMigration(e,t){this.migrations.set(e,t)}async migrateTo(e){this.ensureReady();for(const[t,s]of[...this.migrations.entries()].sort((e,t)=>e[0]-t[0]))t<=e&&t>this._version&&(await s(this),this._version=t);if("function"==typeof this.engine.setMeta)try{await this.engine.setMeta("__metona_version",String(this._version))}catch{}}async repair(){if(this.ensureReady(),"function"==typeof this.engine.repair)return await this.engine.repair(),void this.tableCache.clear();this.tableCache.clear()}async clearAll(){if(this.ensureReady(),"function"==typeof this.engine.clearAll)await this.engine.clearAll();else{const e=await this.engine.getTableNames();for(const t of e)await this.engine.dropTable(t)}this.tableCache.clear()}getPluginManager(){return this.pluginManager}on(e,t){this.pluginManager.on(e,t)}async close(){this.channel&&(this.channel.close(),this.channel=null),this.pluginManager.destroy(),this.engine&&await this.engine.close(),this.tableCache.clear(),this.ready=!1}getEngine(){return this.engine}createEngine(){const e=this.mode,t=this.config.diskEngine??"opfs";switch(e){case"memory":return new y;case"disk":return new U;case"aria":return new Se({storageBackend:"memory"===t?"memory":"kv"===t?"kv":"opfs",...this.config.aria??{}});case"hybrid":return new Ie(t);default:throw new n(`Unknown storage mode: ${e}`,"CONFIG_ERROR")}}ensureReady(){if(!this.ready)throw new n("Database not initialized. Call await db.init() first.","DB_NOT_READY")}_onError(e){if(this.config.onError)try{this.config.onError(e)}catch{}}_debug(e,...t){this.debug}}const We=new class{constructor(){this.connections=new Map,this.refCount=new Map}async connect(e){const t=e.name,s=this.connections.get(t);if(s&&s.isReady()){const e=(this.refCount.get(t)??0)+1;return this.refCount.set(t,e),s}const n=new Ve(e);return await n.init(),this.connections.set(t,n),this.refCount.set(t,1),n.disconnect=async()=>{await this.release(t)},n}async release(e){const t=(this.refCount.get(e)??1)-1;if(t<=0){const t=this.connections.get(e);t&&(await t.close(),this.connections.delete(e)),this.refCount.delete(e)}else this.refCount.set(e,t)}async forceClose(e){const t=this.connections.get(e);t&&(await t.close(),this.connections.delete(e)),this.refCount.delete(e)}async closeAll(){for(const[,e]of this.connections)try{await e.close()}catch{}this.connections.clear(),this.refCount.clear()}getActiveConnections(){return Array.from(this.connections.keys())}},Ge=Ve;async function He(e){return Ve.create(e)}Ge.connect=e=>We.connect(e),Ge.disconnect=e=>We.release(e),Ge.disconnectAll=()=>We.closeAll(),Ge.getActiveConnections=()=>We.getActiveConnections();const Xe={VERSION:i,version:i,create:He,MetonaSqlark:Ve,MeSqlark:Ve};"undefined"!=typeof window&&(window.MetonaSqlark=Xe,window.MeSqlark=Xe);const Ye=Ve;e.AriaEngine=Se,e.HybridEngine=Ie,e.KVStoreEngine=U,e.MeSqlark=Ye,e.MemoryEngine=y,e.MetonaSqlark=Ve,e.OPFSBackend=g,e.Table=Oe,e.VERSION=i,e.api=Xe,e.create=He,e.default=Xe,e.parse=function(e){return new De(e).parseStatement()},e.parseAll=Ue,e.tokenize=function(e){const t=new $e(e),s=[];let n=t.nextToken();for(;n.type!==Le.EOF;)s.push(n),n=t.nextToken();return s.push(n),s},Object.defineProperty(e,"__esModule",{value:!0})});