!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:"indexeddb",version:1,maxRowsPerQuery:0,debug:!1});class n extends Error{constructor(e,t,s){super(e),this.code=t,this.details=s,this.name="DatabaseError"}}const i="0.2.0",r=new Map;function o(e,t,s={}){for(const[n,i]of Object.entries(t))if("$and"!==n){if("$or"!==n){if(!a(e[n],i,e,s))return!1}else if(!i.some(t=>o(e,t,s)))return!1}else if(!i.every(t=>o(e,t,s)))return!1;return!0}function a(e,t,s,n){if("object"==typeof t&&null!==t&&"$and"in t)return t.$and.every(e=>o(s,e,n));if("object"==typeof t&&null!==t&&"$or"in t)return t.$or.some(e=>o(s,e,n));if("object"==typeof t&&null!==t&&"$not"in t)return!a(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{for(const{column:n,direction:i}of t){const t=l(e[n],s[n]);if(0!==t)return"desc"===i?-t:t}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}class d{constructor(){this.name="memory",this.tables=new Map,this.schemas=new Map,this.indexes=new Map,this.opened=!1,this.snapshot=null}async open(e,t){this.opened||(this.opened=!0)}async close(){this.tables.clear(),this.schemas.clear(),this.indexes.clear(),this.opened=!1}isOpen(){return this.opened}async createTable(e){if(this.schemas.has(e.name))throw new n(`Table "${e.name}" already exists`,"TABLE_EXISTS");this.schemas.set(e.name,e),this.tables.set(e.name,new Map);const t=new Map;for(const[s,n]of Object.entries(e.columns))(n.index||n.unique)&&t.set(s,new Map);this.indexes.set(e.name,t)}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 insert(e,t){this.ensureTable(e);const s=this.schemas.get(e),i=this.tables.get(e),r=this.getPrimaryKey(s),o=[];for(const a of t){const t=this.validateRow(s,a),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),o.push(h)}return o}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=>o(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 update(e,t,s){this.ensureTable(e);const n=this.schemas.get(e),i=this.tables.get(e);let r=0;for(const[e,a]of i)if(!t.where||0===Object.keys(t.where).length||o(a,t.where)){const t={...a,...s};this.validateRow(n,t),i.set(e,t),r++}return r}async delete(e,t){this.ensureTable(e);const s=this.tables.get(e),n=[];for(const[e,i]of s)t.where&&0!==Object.keys(t.where).length&&!o(i,t.where)||n.push(e);let i=0;for(const t of n){const n=s.get(t);n&&(i+=await this.cascadeDelete(e,t,n))}for(const e of n)s.delete(e);return n.length+i}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())o(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 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 o=t[i];if(void 0===o&&void 0!==r.default&&(o=r.default),r.required&&null==o)throw new n(`Column "${i}" is required in table "${e.name}"`,"VALIDATION_ERROR");null!=o&&this.checkType(i,r.type,o),void 0!==o&&(s[i]=o)}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 o=s.get(i);if(o&&o.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))if("object"!=typeof i||null===i){const s=n.get(e);if(s){const e=s.get(i);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))}}async cascadeDelete(e,t,s){let i=0;for(const[s,r]of this.schemas)if(s!==e)for(const[o,a]of Object.entries(r.columns)){if(!a.references||!a.onDelete)continue;const[r,h]=a.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"===a.onDelete&&l.length>0)throw new n(`Cannot delete from "${e}": foreign key "${o}" in "${s}" has dependent rows`,"FOREIGN_KEY_VIOLATION");if("CASCADE"===a.onDelete)for(const e of l){const t=c.get(e);t&&(i+=await this.cascadeDelete(s,e,t)),c.delete(e),i++}else if("SET NULL"===a.onDelete)for(const e of l){const t=c.get(e);t&&(t[o]=null)}}return i}}class f{constructor(){this.name="indexeddb",this.db=null,this.dbName="",this.version=1,this.memoryCache=new d,this.txActive=!1}async open(e,t){return this.dbName=e,this.version=t,await this.memoryCache.open(e,t),new Promise((s,i)=>{const r=indexedDB.open(e,t);r.onsuccess=()=>{this.db=r.result,this.db.onversionchange=()=>{this.db&&(this.db.close(),this.db=null)},s()},r.onerror=()=>i(new n(`Failed to open IndexedDB "${e}"`,"IDB_OPEN_ERROR",r.error)),r.onblocked=()=>i(new n(`IndexedDB "${e}" is blocked`,"IDB_BLOCKED"))})}async close(){this.db&&(this.db.onversionchange=null,this.db.close(),this.db=null),await this.memoryCache.close()}isOpen(){return null!==this.db}async createTable(e){await this.memoryCache.createTable(e),this.txActive||await this.idbCreateTable(e)}async dropTable(e){await this.memoryCache.dropTable(e),this.txActive||await this.idbDropTable(e)}async hasTable(e){return this.ensureDB().objectStoreNames.contains(e)}async getTableNames(){return Array.from(this.ensureDB().objectStoreNames)}async getTableSchema(e){return this.memoryCache.getTableSchema(e)}async insert(e,t){const s=await this.memoryCache.insert(e,t);return this.txActive||await this.idbInsert(e,t),s}async find(e,t){return this.txActive?this.memoryCache.find(e,t):this.idbFind(e,t)}async update(e,t,s){const n=await this.memoryCache.update(e,t,s);return this.txActive||await this.idbUpdate(e,t,s),n}async delete(e,t){const s=await this.memoryCache.delete(e,t);return this.txActive||await this.idbDelete(e,t),s}async count(e,t){return this.txActive?this.memoryCache.count(e,t):(await this.idbFind(e,{table:e,where:t?.where??{}})).length}async clear(e){await this.memoryCache.clear(e),this.txActive||await this.idbClear(e)}async beginTransaction(){if(this.txActive)throw new n("Transaction already in progress","TX_ACTIVE");this.txActive=!0,await this.memoryCache.beginTransaction()}async commitTransaction(){if(!this.txActive)throw new n("No active transaction","TX_NONE");await this.memoryCache.commitTransaction(),await this.flushToIDB(),this.txActive=!1}async rollbackTransaction(){if(!this.txActive)throw new n("No active transaction","TX_NONE");await this.memoryCache.rollbackTransaction(),this.txActive=!1}async idbCreateTable(e){const t=this.ensureDB();return new Promise((s,i)=>{const r=t.version+1;t.close();const o=indexedDB.open(this.dbName,r);o.onupgradeneeded=t=>{const s=t.target.result,n=Object.entries(e.columns).find(([,e])=>e.primaryKey)?.[0]??Object.keys(e.columns)[0],i=s.createObjectStore(e.name,{keyPath:n});for(const[t,s]of Object.entries(e.columns))s.index&&t!==n&&i.createIndex(`idx_${t}`,t,{unique:s.unique??!1})},o.onsuccess=()=>{this.db=o.result,s()},o.onerror=()=>i(new n(`Failed to create table "${e.name}"`,"IDB_UPGRADE_ERROR",o.error))})}async idbDropTable(e){const t=this.ensureDB();return new Promise((s,i)=>{const r=t.version+1;t.close();const o=indexedDB.open(this.dbName,r);o.onupgradeneeded=t=>{const s=t.target.result;s.objectStoreNames.contains(e)&&s.deleteObjectStore(e)},o.onsuccess=()=>{this.db=o.result,s()},o.onerror=()=>i(new n(`Failed to drop table "${e}"`,"IDB_UPGRADE_ERROR",o.error))})}async idbInsert(e,t){const s=this.ensureDB();return new Promise((i,r)=>{const o=s.transaction(e,"readwrite"),a=o.objectStore(e);for(const e of t)a.add(e);o.oncomplete=()=>i(),o.onerror=()=>r(new n(`Insert failed for "${e}"`,"IDB_TX_ERROR",o.error))})}async idbFind(e,t){const s=this.ensureDB();return new Promise((i,r)=>{const a=s.transaction(e,"readonly").objectStore(e).getAll();a.onsuccess=()=>{let e=a.result??[];t.where&&Object.keys(t.where).length>0&&(e=e.filter(e=>o(e,t.where))),t.orderBy&&t.orderBy.length>0&&(e=c(e,t.orderBy));const s=t.offset??0,n=t.limit??e.length;e=e.slice(s,s+n),t.columns&&t.columns.length>0&&"*"!==t.columns[0]&&(e=e.map(e=>u(e,t.columns))),i(e)},a.onerror=()=>r(new n(`Find failed for "${e}"`,"IDB_READ_ERROR",a.error))})}async idbUpdate(e,t,s){const i=this.ensureDB();return new Promise((r,a)=>{const h=i.transaction(e,"readwrite"),c=h.objectStore(e),l=c.getAll();l.onsuccess=()=>{for(const e of l.result??[])t.where&&0!==Object.keys(t.where).length&&!o(e,t.where)||(Object.assign(e,s),c.put(e))},h.oncomplete=()=>r(),h.onerror=()=>a(new n(`Update failed for "${e}"`,"IDB_TX_ERROR",h.error))})}async idbDelete(e,t){const s=this.ensureDB(),i=await this.memoryCache.getTableSchema(e);if(!i)throw new n(`Table "${e}" not found`,"TABLE_NOT_FOUND");const r=Object.entries(i.columns).find(([,e])=>e.primaryKey)?.[0]??Object.keys(i.columns)[0];return new Promise((i,a)=>{const h=s.transaction(e,"readwrite"),c=h.objectStore(e),l=c.getAll();l.onsuccess=()=>{for(const e of l.result??[])t.where&&0!==Object.keys(t.where).length&&!o(e,t.where)||c.delete(e[r])},h.oncomplete=()=>i(),h.onerror=()=>a(new n(`Delete failed for "${e}"`,"IDB_TX_ERROR",h.error))})}async idbClear(e){const t=this.ensureDB();return new Promise((s,i)=>{const r=t.transaction(e,"readwrite");r.objectStore(e).clear(),r.oncomplete=()=>s(),r.onerror=()=>i(new n(`Clear failed for "${e}"`,"IDB_TX_ERROR",r.error))})}async flushToIDB(){const e=await this.memoryCache.getTableNames(),t=this.ensureDB();for(const s of e){const e=await this.memoryCache.find(s,{table:s});await new Promise((i,r)=>{const o=t.transaction(s,"readwrite"),a=o.objectStore(s);a.clear();for(const t of e)a.add(t);o.oncomplete=()=>i(),o.onerror=()=>r(new n(`Flush failed for "${s}"`,"IDB_FLUSH_ERROR",o.error))})}}ensureDB(){if(!this.db)throw new n("Database not opened","DB_NOT_OPEN");return this.db}}class p{constructor(){this.name="opfs",this.root=null,this.tablesDir=null,this.dbName="",this.memoryCache=new d}async open(e,t){this.dbName=e,await this.memoryCache.open(e,t),this.root=await navigator.storage.getDirectory(),this.tablesDir=await this.root.getDirectoryHandle(e,{create:!0}),await this.loadExistingTables()}async close(){this.root=null,this.tablesDir=null,await this.memoryCache.close()}isOpen(){return null!==this.tablesDir}async createTable(e){await this.memoryCache.createTable(e),await this.writeTableData(e.name,[])}async dropTable(e){if(await this.memoryCache.dropTable(e),this.tablesDir)try{await this.tablesDir.removeEntry(`${e}.json`)}catch{}}async hasTable(e){if(!this.tablesDir)return!1;try{return await this.tablesDir.getFileHandle(`${e}.json`),!0}catch{return!1}}async getTableNames(){if(!this.tablesDir)return[];const e=[];for await(const[t]of this.tablesDir.entries())t.endsWith(".json")&&e.push(t.replace(".json",""));return e}async getTableSchema(e){return this.memoryCache.getTableSchema(e)}async insert(e,t){const s=await this.memoryCache.insert(e,t),n=await this.memoryCache.find(e,{table:e});return await this.writeTableData(e,n),s}async find(e,t){return this.memoryCache.find(e,t)}async update(e,t,s){const n=await this.memoryCache.update(e,t,s),i=await this.memoryCache.find(e,{table:e});return await this.writeTableData(e,i),n}async delete(e,t){const s=await this.memoryCache.delete(e,t),n=await this.memoryCache.find(e,{table:e});return await this.writeTableData(e,n),s}async count(e,t){return this.memoryCache.count(e,t)}async clear(e){await this.memoryCache.clear(e),await this.writeTableData(e,[])}async beginTransaction(){await this.memoryCache.beginTransaction()}async commitTransaction(){await this.memoryCache.commitTransaction();const e=await this.memoryCache.getTableNames();for(const t of e){const e=await this.memoryCache.find(t,{table:t});await this.writeTableData(t,e)}}async rollbackTransaction(){await this.memoryCache.rollbackTransaction()}ensureDir(){if(!this.tablesDir)throw new n("Database not opened","DB_NOT_OPEN");return this.tablesDir}async writeTableData(e,t){const s=this.ensureDir(),n=`${e}.json`,i=await s.getFileHandle(n,{create:!0}),r=await i.createWritable();await r.write(JSON.stringify(t)),await r.close()}async readTableData(e){const t=this.ensureDir(),s=`${e}.json`;try{const e=await t.getFileHandle(s),n=await e.getFile(),i=await n.text();return JSON.parse(i)}catch{return[]}}async loadExistingTables(){if(!this.tablesDir)return;const e=this.tablesDir;for await(const[t]of e.entries()){if(!t.endsWith(".json"))continue;const e=t.replace(".json","");try{const t=await this.readTableData(e);if(t.length>0){const s=t[0],n={};for(const e of Object.keys(s)){const t=s[e],i="number"==typeof t?"number":"boolean"==typeof t?"boolean":"object"==typeof t?"json":"string";n[e]={type:i,primaryKey:"id"===e}}await this.memoryCache.createTable({name:e,columns:n});for(const s of t)await this.memoryCache.insert(e,[s])}}catch{}}}async loadTableIntoMemory(e,t){await this.memoryCache.createTable(t);const s=await this.readTableData(e);if(s.length>0)for(const t of s)await this.memoryCache.insert(e,[t])}}var m,g;!function(e){e[e.DATA=1]="DATA",e[e.INDEX=2]="INDEX",e[e.OVERFLOW=3]="OVERFLOW",e[e.META=4]="META"}(m||(m={})),function(e){e[e.STRING=1]="STRING",e[e.NUMBER=2]="NUMBER",e[e.BOOLEAN=3]="BOOLEAN",e[e.DATE=4]="DATE",e[e.JSON=5]="JSON",e[e.NULL=6]="NULL"}(g||(g={}));const T=4194304;var b,y,w;!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.READ_COMMITTED=1]="READ_COMMITTED",e[e.SNAPSHOT=2]="SNAPSHOT"}(y||(y={})),function(e){e[e.ACTIVE=1]="ACTIVE",e[e.COMMITTED=2]="COMMITTED",e[e.ABORTED=3]="ABORTED"}(w||(w={}));const E={pageSize:4096,bufferPoolPages:256,memtableSizeThreshold:T,levelSizeMultiplier:10,bloomFilterBitsPerKey:10,walEnabled:!0,walSyncMode:"full",checkpointInterval:1e3,compression:!1,storageBackend:"indexeddb",walSizeThreshold:16777216,maxMemoryMB:64};var k;!function(e){e[e.RED=0]="RED",e[e.BLACK=1]="BLACK"}(k||(k={}));class S{constructor(e,t){this.color=k.RED,this.left=null,this.right=null,this.parent=null,this.key=e,this.value=t}}class x{constructor(){this.root=null,this._size=0}get size(){return this._size}insert(e,t){const s=new S(e,t);if(!this.root)return this.root=s,s.color=k.BLACK,void this._size++;let n=null,i=this.root;for(;i;)if(n=i,ei.key))return void(i.value=t);i=i.right}s.parent=n,et.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(et.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===k.BLACK&&this.fixDelete(t.right,t.right?.parent??null)}else this.transplant(e,e.left),e.color===k.BLACK&&this.fixDelete(e.left,e.left.parent);else this.transplant(e,e.right),e.color===k.BLACK&&this.fixDelete(e.right,e.right.parent);else this.transplant(e,null),e.color===k.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===k.RED;){const t=e.parent,s=t.parent;if(!s)break;if(t===s.left){const n=s.right;n&&n.color===k.RED?(t.color=k.BLACK,n.color=k.BLACK,s.color=k.RED,e=s):(e===t.right&&(e=t,this.rotateLeft(e)),e.parent&&(e.parent.color=k.BLACK),e.parent?.parent&&(e.parent.parent.color=k.RED),e.parent?.parent&&this.rotateRight(e.parent.parent))}else{const n=s.left;n&&n.color===k.RED?(t.color=k.BLACK,n.color=k.BLACK,s.color=k.RED,e=s):(e===t.left&&(e=t,this.rotateRight(e)),e.parent&&(e.parent.color=k.BLACK),e.parent?.parent&&(e.parent.parent.color=k.RED),e.parent?.parent&&this.rotateLeft(e.parent.parent))}}this.root&&(this.root.color=k.BLACK)}fixDelete(e,t){let s=e,n=t;for(;(!s||s.color===k.BLACK)&&s!==this.root&&n;)if(s===n.left){let e=n.right;if(!e)break;if(e.color===k.RED&&(e.color=k.BLACK,n.color=k.RED,this.rotateLeft(n),e=n.right,!e))break;const t=e.left,i=e.right;if(t&&t.color!==k.BLACK||i&&i.color!==k.BLACK){if(!(i&&i.color!==k.BLACK||(t&&(t.color=k.BLACK),e.color=k.RED,this.rotateRight(e),e=n.right,e)))break;e.color=n.color,n.color=k.BLACK,e.right&&(e.right.color=k.BLACK),this.rotateLeft(n),s=this.root}else e.color=k.RED,s=n,n=s.parent}else{let e=n.left;if(!e)break;if(e.color===k.RED&&(e.color=k.BLACK,n.color=k.RED,this.rotateRight(n),e=n.left,!e))break;const t=e.left,i=e.right;if(t&&t.color!==k.BLACK||i&&i.color!==k.BLACK){if(!(t&&t.color!==k.BLACK||(i&&(i.color=k.BLACK),e.color=k.RED,this.rotateLeft(e),e=n.left,e)))break;e.color=n.color,n.color=k.BLACK,e.left&&(e.left.color=k.BLACK),this.rotateRight(n),s=this.root}else e.color=k.RED,s=n,n=s.parent}s&&(s.color=k.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=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}contains(e){return null!==this.tree.find(e)}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 R{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 R(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<>>0;return t}murmurSimple(e){let t=0;for(let s=0;s>>16)>>>0;return Math.abs(t)}}class A{constructor(e=4096){this.entries=[],this.currentBlock=[],this.currentBlockStartKey="",this.blockSizeLimit=e}add(e,t){0===this.currentBlock.length&&(this.currentBlockStartKey=e),this.currentBlock.push([e,t]),this.entries.push([e,t]),this.estimateBlockSize()>=this.blockSizeLimit&&this.currentBlock.length}build(){const e=this.splitIntoBlocks(),t=new R(this.entries.length);let s=0;const n=[];for(const t of e)n.push(s),s+=this.computeBlockSize(t);const i=[];for(let t=0;t=this.blockSizeLimit&&t.length>1&&(e.push(t.slice(0,-1)),t=[s]);return t.length>0&&e.push(t),e}estimateBlockSize(){return this.estimateBlockSizeFromEntries(this.currentBlock)}estimateBlockSizeFromEntries(e){let t=0;for(const[s,n]of e)t+=4+s.length+JSON.stringify(n).length;return t}computeBlockSize(e){let t=4;for(const[s,n]of e){const e=JSON.stringify(n);t+=2+s.length+2+e.length}return t}writeDataBlock(e,t,s,n){e.setUint32(t,s.length,!1),t+=4;for(const[i,r]of s){const s=new TextEncoder,o=s.encode(i),a=s.encode(JSON.stringify(r));e.setUint16(t,o.length,!1),t+=2,new Uint8Array(e.buffer).set(o,t),t+=o.length,e.setUint16(t,a.length,!1),t+=2,new Uint8Array(e.buffer).set(a,t),t+=a.length,n.insert(i)}return t}estimateIndexBlockSize(e){let t=4;for(const s of e)t+=2+s.key.length+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.setUint16(t,s.length,!1),t+=2,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 C{constructor(e,t){this.indexEntries=[],this.entryCount=0,this.bloomFilter=null,this.data=e,this.view=new DataView(e.buffer,e.byteOffset,e.byteLength),this.meta=t,this.parseFooter()}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=new Uint8Array(this.data.buffer,this.data.byteOffset+s.blockOffset,s.blockSize),i=new DataView(n.buffer,n.byteOffset,n.byteLength),r=i.getUint32(0,!1);let o=4;for(let t=0;ti))for(let r=n;r<=i&&r>=0;r++){const n=this.indexEntries[r],i=new Uint8Array(this.data.buffer,this.data.byteOffset+n.blockOffset,n.blockSize),o=new DataView(i.buffer,i.byteOffset,i.byteLength),a=o.getUint32(0,!1);let h=4;for(let n=0;n=e&&r<=t)try{s(r,JSON.parse((new TextDecoder).decode(c)))}catch{}}}}scanAll(e){for(const t of this.indexEntries){const s=new Uint8Array(this.data.buffer,this.data.byteOffset+t.blockOffset,t.blockSize),n=new DataView(s.buffer,s.byteOffset,s.byteLength),i=n.getUint32(0,!1);let r=4;for(let t=0;t0&&r>0&&i+r<=this.data.byteLength)try{const e=this.data.slice(i,i+r);this.bloomFilter=R.fromData(e,o||10)}catch{}}parseIndexBlock(e,t){const s=this.view.getUint32(e,!1);e+=4;for(let t=0;t(0===n?"":this.indexEntries[n-1].key))return n;s=n-1}else t=n+1}return-1}locateBlockGE(e){for(let t=0;t=e)return t;return this.indexEntries.length-1}locateBlockLE(e){for(let t=this.indexEntries.length-1;t>=0;t--)if(this.indexEntries[t].key<=e)return t;return 0}}class N{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 O{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=0&&t.level<7&&this.levels[t.level].push(t);for(let e=0;e<7;e++)this.levels[e].sort((e,t)=>e.minKeyt.minKey?1:0);e.length>0&&(this.nextSSTableId=Math.max(...e.map(e=>e.id))+1);for(const t of e)try{await this.preloadSSTable(t.id)}catch{}this.initialized=!0}put(e,t){this.levels[0].length>=8&&this.compactLevelSync(0),this.memtable.put(e,t),this.operationCount++,this.memtable.shouldFlush()&&this.freezeMemtable()}delete(e){this.levels[0].length>=8&&this.compactLevelSync(0),this.memtable.put(e,{__tombstone:!0}),this.operationCount++,this.memtable.shouldFlush()&&this.freezeMemtable()}getEstimatedMemory(){let e=this.memtable.getEstimatedSize();this.immutableMemtable&&(e+=this.immutableMemtable.getEstimatedSize());for(const[,t]of this.sstableCache)e+=t.byteLength;return e}freezeMemtable(){this.immutableMemtable&&this.flushImmutableSync(),this.immutableMemtable=this.memtable,this.memtable=new I(this.memtable.getEstimatedSize())}flushImmutableSync(){if(!this.immutableMemtable)return;const e=this.immutableMemtable.getAllEntries();if(0===e.length)return void(this.immutableMemtable=null);const t=this.nextSSTableId++,s=new A(this.blockSize);for(const[t,n]of e)s.add(t,n);const{sstableData:n,indexEntries:i}=s.build(),r={id:t,level:0,minKey:e[0][0],maxKey:e[e.length-1][0],blockCount:i.length,totalSize:n.byteLength,bloomData:null};this.sstableCache.set(t,n),this.sstableStore.save(t,n).catch(()=>{}),this.sstableStore.saveMeta(r).catch(()=>{}),this.levels[0].push(r),this.immutableMemtable=null,this.levels[0].length>=4&&!this.compacting&&this.scheduleCompact(0)}scheduleCompact(e){e>=6||this.compacting||(this.compacting=!0,setTimeout(()=>{try{this.compactLevelSync(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)}},0))}get(e){let t=this.memtable.get(e);if(null!==t)return this.unwrapTombstone(t);if(this.immutableMemtable&&(t=this.immutableMemtable.get(e),null!==t))return this.unwrapTombstone(t);for(let t=0;t<7;t++)for(const s of this.levels[t]){if(es.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 D;n.addSource(new N(this.memtable.rangeScan(e,t))),this.immutableMemtable&&n.addSource(new N(this.immutableMemtable.rangeScan(e,t)));for(let s=0;s<7;s++)for(const i of this.levels[s]){if(ti.maxKey)continue;const s=this.loadSSTableReader(i);s&&s.rangeScan(e,t,(e,t)=>{n.addSource(new N([[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(const s of this.levels[t]){const t=this.loadSSTableReader(s);t&&t.scanAll((t,s)=>e.set(t,s))}for(const[t,s]of this.memtable.getAllEntries())e.set(t,s);if(this.immutableMemtable)for(const[t,s]of this.immutableMemtable.getAllEntries())e.set(t,s);return Array.from(e.entries()).filter(([,e])=>!e.__tombstone)}compactLevelSync(e){if(e>=6)return;if(this.levels[e].length<4)return;const t=this.levels[e].splice(0,this.levels[e].length),s=new D;for(const e of t){const t=this.loadSSTableReader(e);if(!t)continue;const n=[];t.scanAll((e,t)=>n.push([e,t])),s.addSource(new N(n))}const n=s.drain();if(0===n.length)return;const i=this.nextSSTableId++,r=new A(this.blockSize);for(const[e,t]of n)r.add(e,t);const{sstableData:o,indexEntries:a}=r.build(),h={id:i,level:e+1,minKey:n[0][0],maxKey:n[n.length-1][0],blockCount:a.length,totalSize:o.byteLength,bloomData:null};this.sstableCache.set(i,o),this.sstableStore.save(i,o).catch(()=>{}),this.sstableStore.saveMeta(h).catch(()=>{}),this.levels[e+1].push(h);for(const e of t)this.sstableCache.delete(e.id),this.sstableStore.delete(e.id).catch(()=>{}),this.sstableStore.deleteMeta(e.id).catch(()=>{})}async flush(){this.immutableMemtable&&this.flushImmutableSync(),this.memtable.getEntryCount()>0&&(this.freezeMemtable(),this.flushImmutableSync()),await Promise.resolve()}async clear(){this.memtable.clear(),this.immutableMemtable=null;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.nextSSTableId=1}getStats(){return{memtableSize:this.memtable.getEntryCount(),sstableCount:this.levels.reduce((e,t)=>e+t.length,0),levelCounts:this.levels.map(e=>e.length)}}isInitialized(){return this.initialized}unwrapTombstone(e){return e?e.__tombstone?null:e:null}loadSSTableReader(e){let t=this.sstableCache.get(e.id);if(!t)return null;try{return new C(t,e)}catch{return null}}async preloadSSTable(e){if(this.sstableCache.has(e))return;const t=await this.sstableStore.load(e);t&&this.sstableCache.set(e,t)}}class _{constructor(e,t=!0,s="batch"){this.lsn=0,this.buffer=[],this.store=e,this.enabled=t,this.syncMode=s}append(e){if(!this.enabled)return;this.lsn++;const t={...e,lsn:this.lsn,checksum:0},s=this.encodeRecord(t);"full"===this.syncMode?this.store.append(s).catch(()=>{}):"batch"===this.syncMode&&this.buffer.push(s)}async flush(){if(!this.enabled||0===this.buffer.length)return;const e=this.buffer.reduce((e,t)=>e+t.byteLength,0),t=new Uint8Array(e);let s=0;for(const e of this.buffer)t.set(e,s),s+=e.byteLength;await this.store.append(t),this.buffer=[]}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)}isEnabled(){return this.enabled}getLSN(){return this.lsn}getBufferedCount(){return this.buffer.length}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),o=11+s.length+2+n.length+4+r.length+4,a=new ArrayBuffer(o),h=new DataView(a);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(a).set(s,c),c+=s.length,h.setUint16(c,n.length,!1),c+=2,new Uint8Array(a).set(n,c),c+=n.length,h.setUint32(c,r.length,!1),c+=4,new Uint8Array(a).set(r,c),c+=r.length;let l=0;const u=new Uint8Array(a,0,c);for(let e=0;e>>0,!1),new Uint8Array(a)}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 o=s.getUint8(n);n+=1;const a=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 d=s.getUint32(n,!1);if(n+=4,n+d>e.byteLength)break;let f;if(d>0){const t=(new TextDecoder).decode(e.slice(n,n+d));try{f=JSON.parse(t)}catch{}}n+=d;const p=s.getUint32(n,!1);n+=4;const m=e.slice(i,n-4);let g=0;for(let e=0;e>>0!==p)continue;t.push({lsn:r,type:o,txnId:a,tableName:c,key:u,data:f,checksum:p})}catch{break}return t}}class v{constructor(e,t,s=null,n=1e3){this.opCount=0,this.lsm=e,this.wal=t,this.flushable=s,this.interval=n}async tick(){this.opCount++,this.opCount>=this.interval&&await this.checkpoint()}async checkpoint(){await this.lsm.flush(),this.flushable&&await this.flushable.flushAll(),await this.wal.checkpoint(),this.opCount=0}async forceCheckpoint(){await this.checkpoint()}setInterval(e){this.interval=e}getOpCount(){return this.opCount}}class M{constructor(){this.db=null,this.dbName="",this.storeName="data"}async open(e){return this.dbName=`aria-${e}`,new Promise((e,t)=>{const s=indexedDB.open(this.dbName,1);s.onupgradeneeded=()=>{const e=s.result;e.objectStoreNames.contains(this.storeName)||e.createObjectStore(this.storeName)},s.onsuccess=()=>{this.db=s.result,e()},s.onerror=()=>t(new n("Failed to open AriaEngine IndexedDB","ARIA_IDB_OPEN_ERROR"))})}async close(){this.db&&(this.db.close(),this.db=null)}isOpen(){return null!==this.db}async read(e){const t=this.ensureDB();return new Promise((s,i)=>{const r=t.transaction(this.storeName,"readonly").objectStore(this.storeName).get(e);r.onsuccess=()=>s(r.result??null),r.onerror=()=>i(new n("Failed to read from AriaEngine store","ARIA_READ_ERROR"))})}async write(e,t){const s=this.ensureDB();return new Promise((i,r)=>{const o=s.transaction(this.storeName,"readwrite");o.objectStore(this.storeName).put(t,e),o.oncomplete=()=>i(),o.onerror=()=>r(new n("Failed to write to AriaEngine store","ARIA_WRITE_ERROR"))})}async delete(e){const t=this.ensureDB();return new Promise((s,i)=>{const r=t.transaction(this.storeName,"readwrite");r.objectStore(this.storeName).delete(e),r.oncomplete=()=>s(),r.onerror=()=>i(new n("Failed to delete from AriaEngine store","ARIA_DELETE_ERROR"))})}async listKeys(){const e=this.ensureDB();return new Promise((t,s)=>{const i=e.transaction(this.storeName,"readonly").objectStore(this.storeName).getAllKeys();i.onsuccess=()=>t(i.result??[]),i.onerror=()=>s(new n("Failed to list keys","ARIA_LIST_ERROR"))})}async exists(e){return null!==await this.read(e)}async clear(){const e=this.ensureDB();return new Promise((t,s)=>{const i=e.transaction(this.storeName,"readwrite");i.objectStore(this.storeName).clear(),i.oncomplete=()=>t(),i.onerror=()=>s(new n("Failed to clear AriaEngine store","ARIA_CLEAR_ERROR"))})}ensureDB(){if(!this.db)throw new n("AriaEngine storage not opened","ARIA_DB_NOT_OPEN");return this.db}}class ${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 delete(e){this.store.delete(e)}async listKeys(){return Array.from(this.store.keys())}async exists(e){return this.store.has(e)}async clear(){this.store.clear()}}class B{constructor(){this.root=null,this.dbDir=null,this.dbName=""}async open(e){this.dbName=e,this.root=await navigator.storage.getDirectory(),this.dbDir=await this.root.getDirectoryHandle(e,{create:!0})}async close(){this.dbDir=null,this.root=null}isOpen(){return null!==this.dbDir}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=await this.dbDir.getFileHandle(e,{create:!0}),n=await s.createWritable();await n.write(t),await n.close()}async delete(e){if(this.dbDir)try{await this.dbDir.removeEntry(e)}catch{}}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{}}}class U{constructor(){this.versionStore=new Map,this.activeTxns=new Map,this.nextTxnId=1,this.globalCommitLsn=0}beginTransaction(){const e=this.nextTxnId++;return this.activeTxns.set(e,{txnId:e,state:w.ACTIVE,snapshotLsn:this.globalCommitLsn,startTime:Date.now()}),e}commitTransaction(e){const t=this.activeTxns.get(e);if(!t)throw new Error(`Transaction ${e} not found`);t.state=w.COMMITTED,this.globalCommitLsn++;for(const[,t]of this.versionStore)for(const s of t)s.txnId===e&&(s.committed=!0);this.activeTxns.delete(e)}rollbackTransaction(e){const t=this.activeTxns.get(e);if(!t)throw new Error(`Transaction ${e} not found`);t.state=w.ABORTED;for(const[t,s]of this.versionStore){const n=s.filter(t=>t.txnId!==e);0===n.length?this.versionStore.delete(t):this.versionStore.set(t,n)}this.activeTxns.delete(e)}isActive(e){const t=this.activeTxns.get(e);return void 0!==t&&t.state===w.ACTIVE}writeVersion(e,t,s,n){const i=`${e}.${t}`,r=this.versionStore.get(i)??[],o={txnId:n,data:s,prevVersion:r.length>0?r[r.length-1]:null,committed:!1};r.push(o),this.versionStore.set(i,r)}readVersion(e,t,s){if(!this.activeTxns.get(s))return null;const n=`${e}.${t}`,i=this.versionStore.get(n);if(!i||0===i.length)return null;for(let e=i.length-1;e>=0;e--){const t=i[e];if(t.txnId===s)return t.data;if(t.committed)return t.data}return null}deleteVersion(e,t,s){this.writeVersion(e,t,{__mvcc_tombstone:!0},s)}getLatestCommittedVersions(e){const t={};for(const[s,n]of this.versionStore){if(!s.startsWith(`${e}.`))continue;const i=s.slice(e.length+1);for(let e=n.length-1;e>=0;e--){const s=n[e];if(s.committed&&!s.data.__mvcc_tombstone){t[i]=s.data;break}}}return t}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)}}getActiveWriteKeys(e,t){const s=new Set,n=`${e}.`;for(const[e,i]of this.versionStore){if(!e.startsWith(n))continue;const r=i[i.length-1];r.txnId!==t||r.committed||s.add(e.slice(n.length))}return s}clearTable(e){const t=`${e}.`;for(const[e]of this.versionStore)e.startsWith(t)&&this.versionStore.delete(e)}getActiveTxnCount(){return this.activeTxns.size}getGlobalLSN(){return this.globalCommitLsn}}class P{constructor(e={}){this.name="aria",this.opened=!1,this.dbName="",this.schemas=new Map,this.tablePKs=new Map,this.opCounter=0,this.secondaryIndexes=new Map,this.mvcc=new U,this.currentTxnId=null,this.txnSnapshot=null,this.gcCounter=0,this.savepoints=new Map,this.config={...E,...e}}async open(e,t){if(this.opened)return;this.dbName=e,"opfs"===this.config.storageBackend?this.backend=new B:"indexeddb"===this.config.storageBackend?this.backend=new M:this.backend=new $,await this.backend.open(e);const s=this.createSSTableStore();this.lsm=new L({memtableSizeThreshold:this.config.memtableSizeThreshold,levelSizeMultiplier:this.config.levelSizeMultiplier,blockSize:this.config.pageSize,bloomBitsPerKey:this.config.bloomFilterBitsPerKey,sstableStore:s}),this.wal=new _({append:async e=>{const t=await this.getWALCount(),s=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),n=s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength);await this.backend.write(`__wal_${t}`,n),await this.setWALCount(t+1)},readAll:async()=>{const e=await this.getWALCount();if(0===e)return new Uint8Array(0);const t=[];for(let s=0;se+t.byteLength,0),n=new Uint8Array(s);let i=0;for(const e of t)n.set(e,i),i+=e.byteLength;return n},truncate:async()=>{const e=await this.getWALCount();for(let t=0;tawait this.getWALCount()>0},this.config.walEnabled,this.config.walSyncMode),await this.loadSchemas(),await this.lsm.init();const n=new Set,i=[];await this.wal.recover(e=>i.push(e));for(const e of i)e.type===b.COMMIT&&n.add(e.txnId),e.type===b.ROLLBACK&&n.delete(e.txnId);for(const e of i)(0===e.txnId||n.has(e.txnId))&&this.applyWALRecord(e);this.checkpointManager=new v(this.lsm,this.wal,{flushAll:async()=>{await this.lsm.flush()}},this.config.checkpointInterval),this.opened=!0}async close(){this.opened&&(await this.persistSchemas(),await this.lsm.flush(),await this.wal.flush(),await this.backend.close(),this.schemas.clear(),this.opened=!1)}isOpen(){return this.opened}async createTable(e){if(this.ensureOpen(),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));const t=this.createSSTableStore();for(const[s,n]of Object.entries(e.columns))if(n.index||n.unique||n.primaryKey){const n=`${e.name}:idx:${s}`;if(!this.secondaryIndexes.has(n)){const e=new L({memtableSizeThreshold:this.config.memtableSizeThreshold,levelSizeMultiplier:this.config.levelSizeMultiplier,blockSize:this.config.pageSize,bloomBitsPerKey:this.config.bloomFilterBitsPerKey,sstableStore:t});await e.init(),this.secondaryIndexes.set(n,e)}}await this.persistSchemas(),this.wal.append({type:b.CREATE_TABLE,txnId:0,tableName:e.name,key:"",data:{schema:JSON.stringify(e)}})}async dropTable(e){this.ensureOpen(),this.ensureTable(e);const t=this.getAllRows(e);for(const s of t){const t=this.tablePKs.get(e);this.lsm.delete(`${e}:${s[t]}`)}this.schemas.delete(e),this.tablePKs.delete(e),await this.persistSchemas(),this.wal.append({type:b.DROP_TABLE,txnId:0,tableName:e,key:""})}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 insert(e,t){this.ensureOpen(),this.ensureTable(e);const s=this.schemas.get(e),i=this.tablePKs.get(e),r=[];for(const o of t){const t=this.validateRow(s,o),a=String(t[i]),h=`${e}:${a}`,c=this.currentTxnId?this.txnSnapshot?.get(h)??this.lsm.get(h):this.lsm.get(h);if(c&&!c.__txn_deleted)throw new n(`Duplicate primary key "${a}" in table "${e}"`,"DUPLICATE_KEY");this.currentTxnId&&this.txnSnapshot?this.txnSnapshot.set(h,t):this.lsm.put(h,t),this.updateSecondaryIndexes(e,a,t,null),r.push(a),this.wal.append({type:b.INSERT,txnId:this.currentTxnId??0,tableName:e,key:a,data:t})}return 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=this.tryIndexLookup(e,t);if(s=null!==n?n:this.getAllRows(e),this.currentTxnId&&this.txnSnapshot){const t=this.tablePKs.get(e),n=`${e}:`;for(const[e,i]of this.txnSnapshot){if(!e.startsWith(n))continue;const r=e.slice(n.length),o=i.__txn_deleted,a=s.findIndex(e=>e[t]===r);if(o)a>=0&&s.splice(a,1);else{const e={...i,[t]:r};a>=0?s[a]=e:s.push(e)}}}t.where&&Object.keys(t.where).length>0&&(s=s.filter(e=>o(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))),s}async update(e,t,s){this.ensureOpen(),this.ensureTable(e);const n=this.schemas.get(e),i=this.getAllRows(e);let r=0;for(const a of i){const i=this.tablePKs.get(e),h=`${e}:${a[i]}`;if(!t.where||0===Object.keys(t.where).length||o(a,t.where)){const t={...a,...s};this.validateRow(n,t),this.currentTxnId&&this.txnSnapshot?this.txnSnapshot.set(h,t):this.lsm.put(h,t),r++,this.wal.append({type:b.UPDATE,txnId:this.currentTxnId??0,tableName:e,key:String(a[i]),data:t}),this.updateSecondaryIndexes(e,String(a[i]),t,a)}}return this.opCounter+=r,await this.checkpointManager.tick(),r}async delete(e,t){this.ensureOpen(),this.ensureTable(e);const s=this.getAllRows(e);let n=0;for(const i of s){const s=this.tablePKs.get(e),r=`${e}:${i[s]}`;t.where&&0!==Object.keys(t.where).length&&!o(i,t.where)||(this.currentTxnId&&this.txnSnapshot?this.txnSnapshot.set(r,{__txn_deleted:!0}):this.lsm.delete(r),n++,this.wal.append({type:b.DELETE,txnId:this.currentTxnId??0,tableName:e,key:String(i[s])}),this.updateSecondaryIndexes(e,String(i[s]),null,i))}return this.opCounter+=n,await this.checkpointManager.tick(),n}async count(e,t){this.ensureOpen();const s=this.getAllRows(e);return t?.where&&0!==Object.keys(t.where).length?s.filter(e=>o(e,t.where)).length:s.length}async clear(e){this.ensureOpen(),this.ensureTable(e);const t=this.getAllRows(e);for(const s of t){const t=this.tablePKs.get(e);this.lsm.delete(`${e}:${s[t]}`)}}async beginTransaction(){if(this.currentTxnId)throw new n("Transaction already in progress","TX_ACTIVE");this.currentTxnId=Date.now(),this.txnSnapshot=new Map,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(this.txnSnapshot)for(const[e,t]of this.txnSnapshot)t.__txn_deleted?this.lsm.delete(e):this.lsm.put(e,t);this.wal.append({type:b.COMMIT,txnId:this.currentTxnId,tableName:"",key:""}),this.currentTxnId=null,this.txnSnapshot=null,await this.wal.flush()}async rollbackTransaction(){if(!this.currentTxnId)throw new n("No active transaction","TX_NONE");this.txnSnapshot=null,this.wal.append({type:b.ROLLBACK,txnId:this.currentTxnId,tableName:"",key:""}),this.currentTxnId=null}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");this.txnSnapshot=t.snapshot?new Map(t.snapshot):null;let s=!1;for(const[t]of this.savepoints)t!==e?s&&this.savepoints.delete(t):s=!0}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]=this.getAllRows(t);return e}getAllRows(e){const t=this.tablePKs.get(e),s=`${e}:`;return this.lsm.rangeScan(s,`${s}￿`).map(([e,n])=>{const i={...n};return i[t]=e.slice(s.length),i})}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 o=t[i];if(void 0===o&&void 0!==r.default&&(o=r.default),r.required&&null==o)throw new n(`Column "${i}" is required in table "${e.name}"`,"VALIDATION_ERROR");null!=o&&this.checkType(i,r.type,o),void 0!==o&&(s[i]=o)}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")}}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(){const e="__aria_lsm_meta";return{save:async(e,t)=>{const s=t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength);await this.backend.write(`sst_${e}`,s)},load:async e=>{const t=await this.backend.read(`sst_${e}`);return t?new Uint8Array(t):null},delete:async e=>{await this.backend.delete(`sst_${e}`)},allocateId:async()=>Date.now(),listMeta:async()=>{const t=await this.backend.read(e);if(!t)return[];try{return JSON.parse((new TextDecoder).decode(t))}catch{return[]}},saveMeta:async t=>{const s=await this.backend.read(e),n=s?JSON.parse((new TextDecoder).decode(s)):[],i=n.findIndex(e=>e.id===t.id);i>=0?n[i]=t:n.push(t);const r=JSON.stringify(n),o=(new TextEncoder).encode(r).buffer;await this.backend.write(e,o)},deleteMeta:async t=>{const s=await this.backend.read(e);if(!s)return;const n=JSON.parse((new TextDecoder).decode(s)).filter(e=>e.id!==t),i=JSON.stringify(n),r=(new TextEncoder).encode(i).buffer;await this.backend.write(e,r)}}}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:case b.DROP_TABLE:}}updateSecondaryIndexes(e,t,s,n){const i=this.schemas.get(e);if(i)for(const[r,o]of Object.entries(i.columns)){if(!o.index&&!o.unique&&!o.primaryKey)continue;const i=`${e}:idx:${r}`,a=this.secondaryIndexes.get(i);if(a){if(n){const e=n[r];null!=e&&a.delete(`${String(e)}:${t}`)}if(s){const e=s[r];null!=e&&a.put(`${String(e)}:${t}`,{pk:t})}}}}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}`,s=this.lsm.get(t);return s?[{...s,[n]:r}]:[]}const t=r;if("$eq"in t){const s=`${e}:${t.$eq}`,i=this.lsm.get(s);return i?[{...i,[n]:t.$eq}]:[]}}const o=`${e}:idx:${i}`,a=this.secondaryIndexes.get(o);if(!a)continue;if("object"!=typeof r||null===r)return this.indexScanToRows(e,n,a,i,String(r),String(r));const h=r;if("$eq"in h){const t=String(h.$eq);return this.indexScanToRows(e,n,a,i,t,t)}if("$in"in h&&Array.isArray(h.$in)){const t=[];for(const s of h.$in){const r=this.indexScanToRows(e,n,a,i,String(s),String(s));t.push(...r)}return t}if("$gt"in h||"$gte"in h||"$lt"in h||"$lte"in h){const t=h.$gt?`${String(Number(h.$gt)+1)}:`:h.$gte?`${String(h.$gte)}:`:`${i}:`,s=h.$lt?`${String(Number(h.$lt)-1)}:￿`:h.$lte?`${String(h.$lte)}:￿`:`${i}:￿`;return this.indexScanToRows(e,n,a,i,t,s)}}return null}indexScanToRows(e,t,s,n,i,r){const o=s.rangeScan(i,r),a=[];for(const[,s]of o){const n=s.pk;if(!n)continue;const i=this.lsm.get(`${e}:${n}`);i&&a.push({...i,[t]:n})}return a}tryGC(){this.gcCounter++,this.gcCounter>=10&&(this.mvcc.gc(100),this.gcCounter=0)}checkMemoryBudget(){const e=1024*this.config.maxMemoryMB*1024;this.lsm.getEstimatedMemory()>e&&(this.lsm.flush().catch(()=>{}),this.mvcc.gc(50))}async analyzeTable(e){this.ensureOpen(),this.ensureTable(e);const t=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}ensureOpen(){if(!this.opened)throw new n("AriaEngine not opened","DB_NOT_OPEN")}ensureTable(e){if(!this.schemas.has(e))throw new n(`Table "${e}" does not exist`,"TABLE_NOT_FOUND")}async getWALCount(){const e=await this.backend.read("__wal_count");if(!e)return 0;try{const t=new TextDecoder;return parseInt(t.decode(e),10)||0}catch{return 0}}async setWALCount(e){const t=(new TextEncoder).encode(String(e)).buffer;await this.backend.write("__wal_count",t)}}class F{constructor(e="indexeddb"){this.name="hybrid",this.memoryEngine=new d,this.diskEngineType=e,this.diskEngine="opfs"===e?new p:new f}async open(e,t){await this.diskEngine.open(e,t),await this.memoryEngine.open(e,t);const s=await this.diskEngine.getTableNames();for(const e of s){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 createTable(e){await this.memoryEngine.createTable(e),await this.diskEngine.createTable(e)}async dropTable(e){await this.memoryEngine.dropTable(e),await this.diskEngine.dropTable(e)}async hasTable(e){return this.memoryEngine.hasTable(e)}async getTableNames(){return this.memoryEngine.getTableNames()}async getTableSchema(e){return this.memoryEngine.getTableSchema(e)}async insert(e,t){const s=await this.memoryEngine.insert(e,t);return await this.diskEngine.insert(e,t),s}async find(e,t){return this.memoryEngine.find(e,t)}async update(e,t,s){const n=await this.memoryEngine.update(e,t,s);return await this.diskEngine.update(e,t,s),n}async delete(e,t){const s=await this.memoryEngine.delete(e,t);return await this.diskEngine.delete(e,t),s}async count(e,t){return this.memoryEngine.count(e,t)}async clear(e){await this.memoryEngine.clear(e),await this.diskEngine.clear(e)}async beginTransaction(){await this.memoryEngine.beginTransaction(),await this.diskEngine.beginTransaction()}async commitTransaction(){await this.diskEngine.commitTransaction();try{await this.memoryEngine.commitTransaction()}catch{throw await this.diskEngine.rollbackTransaction(),new n("Hybrid commit failed: memory engine error after disk commit","TX_COMMIT_ERROR")}}async rollbackTransaction(){await this.memoryEngine.rollbackTransaction(),await this.diskEngine.rollbackTransaction()}getDiskEngineType(){return this.diskEngineType}getMemoryEngine(){return this.memoryEngine}}class j{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 K{constructor(e,t,s){this.engine=e,this.tableName=t,this._updates=s,this._where={}}where(e){return this._where={...this._where,...e},this}async execute(){return this.engine.update(this.tableName,{table:this.tableName,where:this._where},this._updates)}toAST(){return{type:"UPDATE",table:this.tableName,sets:this._updates,where:this._where}}}class z{constructor(e,t){this.engine=e,this.tableName=t,this._where={}}where(e){return this._where={...this._where,...e},this}async execute(){return this.engine.delete(this.tableName,{table:this.tableName,where:this._where})}toAST(){return{type:"DELETE",from:this.tableName,where:this._where}}}class V{constructor(e,t,s){this.schema=null,this.engine=e,this.name=t,this.executor=s}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){return(await this.engine.insert(this.name,[e]))[0]}async insertMany(e){return this.engine.insert(this.name,e)}select(e=["*"]){return new j(this.engine,this.name,e,this.executor)}update(e){return new K(this.engine,this.name,e)}delete(){return new z(this.engine,this.name)}async count(e){return this.engine.count(this.name,e?{table:this.name,where:e}:void 0)}async clear(){return this.engine.clear(this.name)}async drop(){return this.engine.dropTable(this.name)}}function G(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(!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")}(s),{name:e,columns:s}}function q(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}}function J(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")}}class H{constructor(e){this.engine=e}async execute(e){switch(e.type){case"SELECT":return this.executeSelect(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);default:throw new n("Unknown statement type","UNKNOWN_STATEMENT")}}async executeExplain(e){const t=J((e.query.type,e.query)),s=Date.now();let n=null;try{n=await this.execute(e.query)}catch{}const i=Date.now()-s,r=Array.isArray(n)?n.length:0;return{type:e.query.type,table:t.table,columns:t.columns,where:t.where||{},orderBy:t.orderBy||[],limit:t.limit,offset:t.offset,usingIndex:t.table?"auto":"none",estimatedRows:r,actualTimeMs:i}}async executeSelect(e){e.where&&Object.keys(e.where).length>0&&(e.where=await this.resolveSubqueries(e.where));const t=!!(e.groupBy&&e.groupBy.length>0),s=!t&&this._hasAggregateColumn(e.columns);let n;if(e.joins&&0!==e.joins.length)n=await this.executeJoinSelect(e);else{const i=J(t||s?{...e,columns:["*"]}:e);n=await this.engine.find(i.table,i)}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&&(n=n.filter(t=>o(t,e.having))),e.orderBy&&e.orderBy.length>0&&(n=c(n,e.orderBy));const i=e.offset??0,r=e.limit??n.length;return n=n.slice(i,i+r),!t&&!s&&e.columns.length>0&&"*"!==e.columns[0]&&(n=n.map(t=>u(t,e.columns))),n}async executeJoinSelect(e){const t=e.alias??e.from;let s=(await this.engine.find(e.from,{table:e.from})).map(e=>this.prefixRow(e,t));for(const t of e.joins){const e=t.alias??t.table,n=(await this.engine.find(t.table,{table:t.table})).map(t=>this.prefixRow(t,e));s=this.joinRows(s,n,t)}return e.where&&Object.keys(e.where).length>0&&(s=s.filter(t=>o(t,e.where))),s}prefixRow(e,t){const s={};for(const[n,i]of Object.entries(e))s[`${t}.${n}`]=i;return s}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};o(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=>o({...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=[];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 i=n.match(/^(COUNT|SUM|AVG|MIN|MAX)\((.+?)\)(?:\s+AS\s+(\w+))?$/i);if(i){const[,t,r,o]=i;s[o||n]=this.computeAggregate(t.toUpperCase(),e,r.trim())}else t.groupBy.includes(n)||(s[n]=e[0][n])}n.push(s)}return n}computeAggregate(e,t,s){const n=t.map(e=>e[s]).filter(e=>null!=e).map(Number);switch(e){case"COUNT":return"*"===s?t.length:n.length;case"SUM":return n.reduce((e,t)=>e+t,0);case"AVG":return 0===n.length?0:n.reduce((e,t)=>e+t,0)/n.length;case"MIN":return 0===n.length?0:Math.min(...n);case"MAX":return 0===n.length?0:Math.max(...n);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),i=e.values.map(e=>{const t={};for(let n=0;n/^(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,o]=t;s[o||n]=this.computeAggregate(i.toUpperCase(),e,r.trim())}else s[n]=e.length>0?e[0][n]:null}return s}async resolveSubqueries(e){const t={};for(const[s,n]of Object.entries(e))"$and"===s&&Array.isArray(n)?t.$and=await Promise.all(n.map(e=>this.resolveSubqueries(e))):"$or"===s&&Array.isArray(n)?t.$or=await Promise.all(n.map(e=>this.resolveSubqueries(e))):"$not"!==s||"object"!=typeof n||null===n?t[s]="object"==typeof n&&null!==n?await this.resolveOperatorSubqueries(n):n:t.$not=await this.resolveSubqueries(n);return t}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}}var W;!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.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.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"}(W||(W={}));const X={SELECT:W.SELECT,FROM:W.FROM,WHERE:W.WHERE,INSERT:W.INSERT,INTO:W.INTO,VALUES:W.VALUES,UPDATE:W.UPDATE,SET:W.SET,DELETE:W.DELETE,CREATE:W.CREATE,TABLE:W.TABLE,DROP:W.DROP,ORDER:W.ORDER,BY:W.BY,ASC:W.ASC,DESC:W.DESC,LIMIT:W.LIMIT,OFFSET:W.OFFSET,AND:W.AND,OR:W.OR,NOT:W.NOT,LIKE:W.LIKE,IN:W.IN,PRIMARY:W.PRIMARY,KEY:W.KEY,UNIQUE:W.UNIQUE,DEFAULT:W.DEFAULT,NULL:W.NULL,TRUE:W.TRUE,FALSE:W.FALSE,REFERENCES:W.REFERENCES,CASCADE:W.CASCADE,BETWEEN:W.BETWEEN,IF:W.IF,EXISTS:W.EXISTS,INNER:W.INNER,LEFT:W.LEFT,RIGHT:W.RIGHT,CROSS:W.CROSS,JOIN:W.JOIN,ON:W.ON,AS:W.AS,OUTER:W.OUTER,GROUP:W.GROUP,HAVING:W.HAVING,COUNT:W.COUNT,SUM:W.SUM,AVG:W.AVG,MIN:W.MIN,MAX:W.MAX,DISTINCT:W.DISTINCT};class Y{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(W.COMMA,",");break;case"(":e=this.makeToken(W.LPAREN,"(");break;case")":e=this.makeToken(W.RPAREN,")");break;case";":e=this.makeToken(W.SEMICOLON,";");break;case"*":e=this.makeToken(W.STAR,"*");break;case".":e=this.makeToken(W.DOT,".");break;case"=":e=this.makeToken(W.EQ,"=");break;case"!":"="===this.peekChar()?(this.readChar(),e=this.makeToken(W.NEQ,"!=")):e=this.makeToken(W.ILLEGAL,"!");break;case">":"="===this.peekChar()?(this.readChar(),e=this.makeToken(W.GTE,">=")):e=this.makeToken(W.GT,">");break;case"<":"="===this.peekChar()?(this.readChar(),e=this.makeToken(W.LTE,"<=")):">"===this.peekChar()?(this.readChar(),e=this.makeToken(W.NEQ,"<>")):e=this.makeToken(W.LT,"<");break;case"'":case'"':e=this.readString(this.ch);break;case"":e={type:W.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:X[t.toUpperCase()]??W.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:W.NUMBER,value:t,position:this.position-t.length},e}e=this.makeToken(W.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!==e&&""!==this.ch;)"\\"===this.ch&&this.peekChar()===e?(this.readChar(),s+=e):s+=this.ch,this.readChar();return{type:W.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 Q{constructor(e){this.lexer=new Y(e),this.nextToken(),this.nextToken()}parseStatement(){switch(this.curToken.type){case W.SELECT:return this.parseSelect();case W.INSERT:return this.parseInsert();case W.UPDATE:return this.parseUpdate();case W.DELETE:return this.parseDelete();case W.CREATE:return this.parseCreateTable();case W.DROP:return this.parseDropTable();default:throw this.error(`Unexpected token "${this.curToken.value}"`)}}parseSelect(){this.expect(W.SELECT);let e=!1;this.curTokenIs(W.DISTINCT)&&(e=!0,this.nextToken());const t=[];this.curTokenIs(W.STAR)?(t.push("*"),this.nextToken()):t.push(...this.parseColumnList()),this.expect(W.FROM);const s=this.expectIdentifier("table name");let n;this.curTokenIs(W.AS)?(this.nextToken(),n=this.expectIdentifier("alias")):this.curToken.type!==W.IDENTIFIER||this._isReservedAfterFrom()||(n=this.curToken.value,this.nextToken());const i={type:"SELECT",columns:t,distinct:e||void 0,from:s,alias:n,where:{}},r=this.parseJoinClauses();return r.length>0&&(i.joins=r),this.curTokenIs(W.WHERE)&&(this.nextToken(),i.where=this.parseCondition()),this.curTokenIs(W.GROUP)&&(this.nextToken(),this.expect(W.BY),i.groupBy=this.parseIdentifierList()),this.curTokenIs(W.HAVING)&&(this.nextToken(),i.having=this.parseCondition()),this.curTokenIs(W.ORDER)&&(this.nextToken(),this.expect(W.BY),i.orderBy=this.parseOrderByList()),this.curTokenIs(W.LIMIT)&&(this.nextToken(),i.limit=this.expectNumber("LIMIT value")),this.curTokenIs(W.OFFSET)&&(this.nextToken(),i.offset=this.expectNumber("OFFSET value")),i}parseJoinClauses(){const e=[];for(;this._isJoinKeyword();)e.push(this.parseJoinClause());return e}_isJoinKeyword(){return this.curTokenIs(W.INNER)||this.curTokenIs(W.LEFT)||this.curTokenIs(W.RIGHT)||this.curTokenIs(W.CROSS)||this.curTokenIs(W.JOIN)}parseJoinClause(){let e="INNER";this.curTokenIs(W.INNER)?(e="INNER",this.nextToken()):this.curTokenIs(W.LEFT)?(e="LEFT",this.nextToken(),this.curTokenIs(W.OUTER)&&this.nextToken()):this.curTokenIs(W.RIGHT)?(e="RIGHT",this.nextToken(),this.curTokenIs(W.OUTER)&&this.nextToken()):this.curTokenIs(W.CROSS)&&(e="CROSS",this.nextToken()),this.expect(W.JOIN);const t=this.expectIdentifier("table name");let s;this.curTokenIs(W.AS)?(this.nextToken(),s=this.expectIdentifier("alias")):this.curToken.type!==W.IDENTIFIER||this._isJoinReserved()||(s=this.curToken.value,this.nextToken());let n={};return"CROSS"!==e&&this.curTokenIs(W.ON)&&(this.nextToken(),n=this.parseCondition()),{type:e,table:t,alias:s,on:n}}_isReservedAfterFrom(){return this.curTokenIs(W.WHERE)||this.curTokenIs(W.ORDER)||this.curTokenIs(W.LIMIT)||this.curTokenIs(W.OFFSET)||this.curTokenIs(W.GROUP)||this._isJoinKeyword()}_isJoinReserved(){return this.curTokenIs(W.ON)||this.curTokenIs(W.WHERE)||this.curTokenIs(W.ORDER)||this.curTokenIs(W.LIMIT)||this._isJoinKeyword()}parseInsert(){this.expect(W.INSERT),this.expect(W.INTO);const e=this.expectIdentifier("table name");let t;this.curTokenIs(W.LPAREN)&&(this.nextToken(),t=this.parseIdentifierList(),this.expect(W.RPAREN)),this.expect(W.VALUES);const s=[];do{this.curTokenIs(W.COMMA)&&this.nextToken(),this.expect(W.LPAREN);const e=this.parseValueList();this.expect(W.RPAREN),s.push(e)}while(this.curTokenIs(W.COMMA));return{type:"INSERT",into:e,columns:t,values:s}}parseUpdate(){this.expect(W.UPDATE);const e=this.expectIdentifier("table name");this.expect(W.SET);const t={};do{this.curTokenIs(W.COMMA)&&this.nextToken();const e=this.expectIdentifier("column name");this.expect(W.EQ),t[e]=this.parseValue()}while(this.curTokenIs(W.COMMA));let s={};return this.curTokenIs(W.WHERE)&&(this.nextToken(),s=this.parseCondition()),{type:"UPDATE",table:e,sets:t,where:s}}parseDelete(){this.expect(W.DELETE),this.expect(W.FROM);const e=this.expectIdentifier("table name");let t={};return this.curTokenIs(W.WHERE)&&(this.nextToken(),t=this.parseCondition()),{type:"DELETE",from:e,where:t}}parseCreateTable(){this.expect(W.CREATE),this.expect(W.TABLE);let e=!1;this.curTokenIs(W.IF)&&(this.nextToken(),this.expect(W.NOT),this.expect(W.EXISTS),e=!0);const t=this.expectIdentifier("table name");this.expect(W.LPAREN);const s=[];do{this.curTokenIs(W.COMMA)&&this.nextToken(),s.push(this.parseColumnDef())}while(this.curTokenIs(W.COMMA));return this.expect(W.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(W.PRIMARY)||this.curTokenIs(W.UNIQUE)||this.curTokenIs(W.NOT)||this.curTokenIs(W.DEFAULT)||this.curTokenIs(W.REFERENCES);)if(this.curTokenIs(W.PRIMARY))this.nextToken(),this.expect(W.KEY),e.primaryKey=!0;else if(this.curTokenIs(W.UNIQUE))this.nextToken(),e.unique=!0;else if(this.curTokenIs(W.NOT))this.nextToken(),this.expect(W.NULL),e.required=!0;else if(this.curTokenIs(W.DEFAULT))this.nextToken(),e.default=this.parseValue();else{if(!this.curTokenIs(W.REFERENCES))break;{this.nextToken();const t=this.expectIdentifier("referenced table");this.expect(W.LPAREN);const s=this.expectIdentifier("referenced column");for(this.expect(W.RPAREN),e.references=`${t}.${s}`;this.curTokenIs(W.ON);)if(this.nextToken(),this.curTokenIs(W.DELETE))this.nextToken(),e.onDelete=this.parseCascadeAction();else{if(!this.curTokenIs(W.UPDATE))break;this.nextToken(),e.onUpdate=this.parseCascadeAction()}}}return e}parseCascadeAction(){return this.curTokenIs(W.CASCADE)?(this.nextToken(),"CASCADE"):this.curTokenIs(W.SET)?(this.nextToken(),this.expect(W.NULL),"SET NULL"):this.curToken.type===W.IDENTIFIER&&"RESTRICT"===this.curToken.value.toUpperCase()?(this.nextToken(),"RESTRICT"):"RESTRICT"}parseDropTable(){this.expect(W.DROP),this.expect(W.TABLE);let e=!1;return this.curTokenIs(W.IF)&&(this.nextToken(),this.expect(W.EXISTS),e=!0),{type:"DROP_TABLE",name:this.expectIdentifier("table name"),ifExists:e||void 0}}parseCondition(){let e=this.parseSimpleCondition();for(;this.curTokenIs(W.AND)||this.curTokenIs(W.OR);){const t=this.curTokenIs(W.AND);this.nextToken();const s=this.parseSimpleCondition();e=t?{$and:[e,s]}:{$or:[e,s]}}return e}parseSimpleCondition(){if(this.curTokenIs(W.NOT)&&!this._isNotInOrLike())return this.nextToken(),{$not:this.parseSimpleCondition()};if(this.curTokenIs(W.LPAREN)){this.nextToken();const e=this.parseCondition();return this.expect(W.RPAREN),e}const e=this.parseColumnRef();if(this.curTokenIs(W.IDENTIFIER)&&"IS"===this.curToken.value.toUpperCase()){this.nextToken();const t=this.curTokenIs(W.NOT);t&&this.nextToken(),this.expect(W.NULL);const s={};return s[e]=t?{$ne:null}:{$eq:null},s}if(this.curTokenIs(W.BETWEEN)){this.nextToken();const t=this.parseValue();this.expect(W.AND);const s=this.parseValue(),n={};return n[e]={$gte:t,$lte:s},n}if(this.curTokenIs(W.NOT)&&this.peekTokenIs(W.BETWEEN)){this.nextToken(),this.nextToken();const t=this.parseValue();this.expect(W.AND);const s=this.parseValue(),n={};return n[e]={$not:{$gte:t,$lte:s}},n}if(this.curTokenIs(W.NOT)){if(this.peekTokenIs(W.IN)){if(this.nextToken(),this.nextToken(),this.expect(W.LPAREN),this.curTokenIs(W.SELECT)){const t=this.parseSelect();this.expect(W.RPAREN);const s={};return s[e]={$nin:{$subquery:t}},s}const t=this.parseValueList();this.expect(W.RPAREN);const s={};return s[e]={$nin:t},s}if(this.peekTokenIs(W.LIKE)){this.nextToken(),this.nextToken();const t=this.parseValue(),s={};return s[e]={$not:{$like:t}},s}}if(this.curTokenIs(W.LIKE)){this.nextToken();const t=this.parseValue(),s={};return s[e]={$like:t},s}if(this.curTokenIs(W.IN)){if(this.nextToken(),this.expect(W.LPAREN),this.curTokenIs(W.SELECT)){const t=this.parseSelect();this.expect(W.RPAREN);const s={};return s[e]={$in:{$subquery:t}},s}const t=this.parseValueList();this.expect(W.RPAREN);const s={};return s[e]={$in:t},s}const t=this.parseComparisonOp();if(this.curTokenIs(W.LPAREN)&&this.peekTokenIs(W.SELECT)){this.nextToken();const s=this.parseSelect();this.expect(W.RPAREN);const n={};return n[e]={[t]:{$subquery:s}},n}let s;s=(this.curToken.type===W.IDENTIFIER||this._isKeywordAsIdent())&&this.peekTokenIs(W.DOT)?{$col:this.parseColumnRef()}:this.parseValue();const n={};return n[e]={[t]:s},n}_isNotInOrLike(){return this.peekTokenIs(W.IN)||this.peekTokenIs(W.LIKE)}peekTokenIs(e){return this.peekToken.type===e}parseComparisonOp(){switch(this.curToken.type){case W.EQ:return this.nextToken(),"$eq";case W.NEQ:return this.nextToken(),"$ne";case W.GT:return this.nextToken(),"$gt";case W.GTE:return this.nextToken(),"$gte";case W.LT:return this.nextToken(),"$lt";case W.LTE:return this.nextToken(),"$lte";default:throw this.error(`Expected comparison operator, got "${this.curToken.value}"`)}}parseColumnList(){const e=[];for(e.push(this.parseColumnRef());this.curTokenIs(W.COMMA);)this.nextToken(),e.push(this.parseColumnRef());return e}parseColumnRef(){if(this.curTokenIs(W.COUNT)||this.curTokenIs(W.SUM)||this.curTokenIs(W.AVG)||this.curTokenIs(W.MIN)||this.curTokenIs(W.MAX))return this.parseAggregateCall();const e=this.expectIdentifier("column name");return this.curTokenIs(W.DOT)?(this.nextToken(),`${e}.${this.expectIdentifier("column name")}`):e}parseAggregateCall(){const e=this.curToken.value.toUpperCase();let t;this.nextToken(),this.expect(W.LPAREN),this.curTokenIs(W.STAR)?(t="*",this.nextToken()):t=this.parseColumnRef(),this.expect(W.RPAREN);let s="";return this.curTokenIs(W.AS)?(this.nextToken(),s=this.expectIdentifier("alias")):this.curToken.type===W.IDENTIFIER&&this._isAggregateAlias()&&(s=this.curToken.value,this.nextToken()),s?`${e}(${t}) AS ${s}`:`${e}(${t})`}_isAggregateAlias(){return!this._isReservedAfterFrom()&&!this._isJoinKeyword()}parseIdentifierList(){const e=[];for(e.push(this.expectIdentifier("identifier"));this.curTokenIs(W.COMMA);)this.nextToken(),e.push(this.expectIdentifier("identifier"));return e}parseValueList(){const e=[];for(e.push(this.parseValue());this.curTokenIs(W.COMMA);)this.nextToken(),e.push(this.parseValue());return e}parseOrderByList(){const e=[];for(e.push(this.parseOrderBy());this.curTokenIs(W.COMMA);)this.nextToken(),e.push(this.parseOrderBy());return e}parseOrderBy(){const e=this.expectIdentifier("column name");let t="asc";return this.curTokenIs(W.ASC)?this.nextToken():this.curTokenIs(W.DESC)&&(t="desc",this.nextToken()),{column:e,direction:t}}parseValue(){switch(this.curToken.type){case W.STRING:{const e=this.curToken.value;return this.nextToken(),e}case W.NUMBER:{const e=Number(this.curToken.value);return this.nextToken(),e}case W.TRUE:return this.nextToken(),!0;case W.FALSE:return this.nextToken(),!1;case W.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===W.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!==W.EOF&&this.curToken.type!==W.ILLEGAL&&this.curToken.type!==W.STRING&&this.curToken.type!==W.NUMBER&&this.curToken.type!==W.COMMA&&this.curToken.type!==W.LPAREN&&this.curToken.type!==W.RPAREN&&this.curToken.type!==W.SEMICOLON&&this.curToken.type!==W.EQ&&this.curToken.type!==W.NEQ&&this.curToken.type!==W.GT&&this.curToken.type!==W.GTE&&this.curToken.type!==W.LT&&this.curToken.type!==W.LTE&&this.curToken.type!==W.DOT&&this.curToken.type!==W.STAR}expectNumber(e){if(this.curToken.type===W.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 Z(e){return new Q(e).parseStatement()}class ee{constructor(e){this.tables=new Map,this.completed=!1,this.engine=e}table(e){let t=this.tables.get(e);return t||(t=new V(this.engine,e),this.tables.set(e,t)),t}_markCompleted(){this.completed=!0}isCompleted(){return this.completed}}class te{constructor(e){this.engine=e}async execute(e){const t=new ee(this.engine);await this.engine.beginTransaction();try{const s=await e(t);return await this.engine.commitTransaction(),t._markCompleted(),s}catch(e){if(await this.engine.rollbackTransaction(),e instanceof n)throw e;throw new n(`Transaction failed: ${e.message}`,"TRANSACTION_ERROR",e)}}}class se{constructor(){this.plugins=[],this.hooks=new Map}register(e){const t=e.priority??0,s=this.plugins.findIndex(e=>(e.priority??0)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 ne{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.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 se}async init(){if(this.engine=this.createEngine(),await this.engine.open(this.name,this.version),this.executor=new H(this.engine),this.transactionManager=new te(this.engine),this.config.plugins)for(const e of this.config.plugins)this.pluginManager.register(e);this.ready=!0,this.config.onReady&&this.config.onReady(this)}isReady(){return this.ready}async defineTable(e,t){this.ensureReady();const s=G(e,t);await this.pluginManager.trigger("beforeCreateTable",s),await this.engine.createTable(s),await this.pluginManager.trigger("afterCreateTable",s),this.tableCache.delete(e)}table(e){this.ensureReady();let t=this.tableCache.get(e);return t||(t=new V(this.engine,e,this.executor),this.tableCache.set(e,t)),t}async dropTable(e){this.ensureReady(),await this.pluginManager.trigger("beforeDropTable",e),await this.engine.dropTable(e),await this.pluginManager.trigger("afterDropTable",e),this.tableCache.delete(e)}async getTableNames(){return this.ensureReady(),this.engine.getTableNames()}async query(e){this.ensureReady();const t=this.debug?Date.now():0;await this.pluginManager.trigger("beforeQuery",e);const s=Z(e),n=await this.executor.execute(s);if(await this.pluginManager.trigger("afterQuery",e,n),this.debug){const s=Date.now()-t,i=Array.isArray(n)?n.length:0;this._debug(`query [${s}ms] ${i} rows: ${e.slice(0,100)}`)}return n}async transaction(e){this.ensureReady(),await this.pluginManager.trigger("beforeTransaction");const t=await this.transactionManager.execute(e);return await this.pluginManager.trigger("afterTransaction"),t}async exportTable(e){return this.ensureReady(),this.engine.find(e,{table:e})}async importTable(e,t){return this.ensureReady(),this.engine.insert(e,t)}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}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))}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)}getPluginManager(){return this.pluginManager}on(e,t){this.pluginManager.on(e,t)}async close(){this.pluginManager.destroy(),await this.engine.close(),this.tableCache.clear(),this.ready=!1}getEngine(){return this.engine}createEngine(){const e=this.mode,t=this.config.diskEngine??"indexeddb";switch(e){case"memory":return new d;case"disk":return"opfs"===t?new p:new f;case"aria":return new P({storageBackend:"opfs"===t?"memory":"indexeddb"});case"hybrid":return new F(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 ie=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 ne(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())}getRefCount(e){return this.refCount.get(e)??0}},re=ne;async function oe(e){const t=new ne(e);return await t.init(),t}re.connect=e=>ie.connect(e),re.disconnect=e=>ie.release(e),re.disconnectAll=()=>ie.closeAll(),re.getActiveConnections=()=>ie.getActiveConnections();const ae={VERSION:i,version:i,create:oe,MetonaSqlark:ne,MeSqlark:ne};"undefined"!=typeof window&&(window.MetonaSqlark=ae,window.MeSqlark=ae);const he=ne;e.AriaEngine=P,e.HybridEngine=F,e.IndexedDBEngine=f,e.MeSqlark=he,e.MemoryEngine=d,e.MetonaSqlark=ne,e.OPFSBackend=B,e.OPFSEngine=p,e.Table=V,e.VERSION=i,e.api=ae,e.create=oe,e.default=ae,e.parse=Z,e.tokenize=function(e){const t=new Y(e),s=[];let n=t.nextToken();for(;n.type!==W.EOF;)s.push(n),n=t.nextToken();return s.push(n),s},Object.defineProperty(e,"__esModule",{value:!0})});