@dqcai/sqlite
Version:
Universal SQLite adapter for Node.js, Browser, Deno, Bun, and React Native with a unified API and query builder.
7 lines • 120 kB
JavaScript
const R=(...h)=>h.map(e=>typeof e=="object"?JSON.stringify(e,null,2):String(e)).join(" ");class M{constructor(e){this.transports=new Map,this.transportFactory=null,this.config=e,this.sessionId=e.sessionId||this.generateSessionId()}generateSessionId(){return`session_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}getSessionId(){return this.sessionId}renewSession(){return this.sessionId=this.generateSessionId(),this.sessionId}setTransportFactory(e){this.transportFactory=e}addTransport(e){this.transports.set(e.name,e)}removeTransport(e){return this.transports.delete(e)}getTransport(e){return this.transports.get(e)}listTransports(){return Array.from(this.transports.keys())}setModuleConfig(e,t){this.config.modules[e]=t}getModuleConfig(e){return this.config.modules[e]}setGlobalEnabled(e){this.config.enabled=e}isGlobalEnabled(){return this.config.enabled}setDefaultLevel(e){this.config.defaultLevel=e}getConfig(){return JSON.parse(JSON.stringify(this.config))}setMetadata(e){this.config.metadata=Object.assign(Object.assign({},this.config.metadata),e)}shouldLog(e,t){if(!this.config.enabled)return!1;const a=this.config.modules[e];return a?a.enabled&&a.levels.includes(t):this.isLevelEnabled(t,this.config.defaultLevel)}isLevelEnabled(e,t){const a=["trace","debug","info","warn","error"],s=a.indexOf(e),r=a.indexOf(t);return s===-1||r===-1?!1:s>=r}getTransportsForModule(e){const t=this.config.modules[e];return((t==null?void 0:t.transports)||["console"]).map(a=>this.transports.get(a)).filter(a=>a!==void 0)}async sendToTransports(e,t){if(t.length===0)return;const a=t.map(async s=>{try{await s.log(e)}catch(r){console.error(`[UniversalLogger] Transport ${s.name} failed:`,r)}});await Promise.allSettled(a)}async log(e,t,a,s){if(!this.shouldLog(e,t))return;const r={timestamp:new Date().toISOString(),level:t,module:e,message:a,data:s,metadata:this.config.metadata,sessionId:this.sessionId},i=this.getTransportsForModule(e);await this.sendToTransports(r,i)}async trace(e,...t){const a=R(...t);await this.log(e,"trace",a)}async debug(e,...t){const a=R(...t);await this.log(e,"debug",a)}async info(e,...t){const a=R(...t);await this.log(e,"info",a)}async warn(e,...t){const a=R(...t);await this.log(e,"warn",a)}async error(e,...t){const a=R(...t);await this.log(e,"error",a)}async flush(){const e=Array.from(this.transports.values()).filter(t=>typeof t.flush=="function").map(t=>t.flush());await Promise.allSettled(e)}async cleanup(){const e=Array.from(this.transports.values()).filter(t=>typeof t.cleanup=="function").map(t=>t.cleanup());await Promise.allSettled(e)}createModuleLogger(e){return new L(e,this)}}class L{constructor(e,t){this.module=e,this.logger=t}async flush(){await this.logger.flush()}async trace(...e){const t=R(...e);await this.logger.trace(this.module,t)}async debug(...e){const t=R(...e);await this.logger.debug(this.module,t)}async info(...e){const t=R(...e);await this.logger.info(this.module,t)}async warn(...e){const t=R(...e);await this.logger.warn(this.module,t)}async error(...e){const t=R(...e);await this.logger.error(this.module,t)}getModuleName(){return this.module}}class ${constructor(e={}){this.name="console",this.config=Object.assign({colorize:!0,timestamp:!0,prefix:""},e)}log(e){const t=[];this.config.timestamp&&t.push(`[${e.timestamp}]`),this.config.prefix&&t.push(`[${this.config.prefix}]`),t.push(`[${e.module}]`,`[${e.level.toUpperCase()}]`,e.message);const a=t.join(" "),s=e.data?[e.data]:[];this.config.colorize?this.logWithColor(e.level,a,s):this.logWithoutColor(e.level,a,s)}logWithColor(e,t,a){const s={trace:"#999999",debug:"#0066cc",info:"#00cc66",warn:"#ff9900",error:"#cc0000"}[e];console.log(`%c${t}`,`color: ${s}`,...a)}logWithoutColor(e,t,a){switch(e){case"error":console.error(t,...a);break;case"warn":console.warn(t,...a);break;case"info":console.info(t,...a);break;default:console.log(t,...a)}}}class T{constructor(){this.config={enabled:!0,defaultLevel:"info",modules:{}}}setEnabled(e){return this.config.enabled=e,this}setDefaultLevel(e){return this.config.defaultLevel=e,this}setSessionId(e){return this.config.sessionId=e,this}setMetadata(e){return this.config.metadata=e,this}addModule(e,t=!0,a=["info","warn","error"],s=["console"]){return this.config.modules[e]={enabled:t,levels:a,transports:s},this}build(){return JSON.parse(JSON.stringify(this.config))}}class k{static createDevelopmentConfig(){return new T().setEnabled(!0).setDefaultLevel("debug").addModule("DatabaseManager",!0,["debug","info","warn","error"],["console"]).addModule("ApiClient",!0,["info","warn","error"],["console"]).addModule("Cache",!0,["debug","info","warn","error"],["console"]).build()}static createProductionConfig(){return new T().setEnabled(!0).setDefaultLevel("warn").addModule("DatabaseManager",!0,["error"],["console"]).addModule("ApiClient",!0,["warn","error"],["console"]).addModule("Cache",!1,[],[]).build()}static createCustomConfig(e=!1){return e?k.createDevelopmentConfig():k.createProductionConfig()}}const _=h=>{const e=h||k.createDevelopmentConfig(),t=new M(e);return t.addTransport(new $),t};var b;(function(h){h.DATABASE_MANAGER="DatabaseManager",h.DATABASE_FACTORY="DatabaseFactory",h.UNIVERSAL_DAO="UniversalDAO",h.BASE_SERVICE="BaseService",h.SERVICE_MANAGER="ServiceManager",h.QUERY_BUILDER="QueryBuilder",h.BASE_ADAPTER="BaseAdapter",h.UNIVERSAL_SQLITE="UniversalSQLite",h.TRANSACTION="Transaction",h.CONNECTION="Connection"})(b||(b={}));class z{constructor(e){this.moduleName=e}trace(e,...t){u.getInstance().trace(this.moduleName,e,...t)}debug(e,...t){u.getInstance().debug(this.moduleName,e,...t)}info(e,...t){u.getInstance().info(this.moduleName,e,...t)}warn(e,...t){u.getInstance().warn(this.moduleName,e,...t)}error(e,...t){u.getInstance().error(this.moduleName,e,...t)}}class u{static createDefaultConfig(){return new T().setEnabled(!0).setDefaultLevel("warn").addModule(b.UNIVERSAL_SQLITE,!0,["warn","error"],["console"]).addModule(b.DATABASE_MANAGER,!0,["warn","error"],["console"]).addModule(b.DATABASE_FACTORY,!0,["warn","error"],["console"]).addModule(b.UNIVERSAL_DAO,!0,["warn","error"],["console"]).addModule(b.BASE_SERVICE,!0,["warn","error"],["console"]).addModule(b.SERVICE_MANAGER,!0,["warn","error"],["console"]).addModule(b.QUERY_BUILDER,!0,["warn","error"],["console"]).addModule(b.BASE_ADAPTER,!0,["warn","error"],["console"]).build()}static initialize(e){const t=e||u.createDefaultConfig();return u.currentConfig=t,t.enabled&&(t.defaultLevel==="trace"||t.defaultLevel==="debug")&&console.debug(`SQLiteLoggerConfig.initialize() with ${e?"CUSTOM":"default"} config`),u.instance=_(t),u.instance}static getInstance(){return u.instance?u.instance:u.initialize()}static updateConfiguration(e){e&&e.enabled&&(e.defaultLevel==="trace"||e.defaultLevel==="debug")&&console.debug("SQLiteLoggerConfig.updateConfiguration()",JSON.stringify(e,null,2)),u.currentConfig=e,u.instance=_(e),e&&e.enabled&&(e.defaultLevel==="trace"||e.defaultLevel==="debug"||e.defaultLevel==="info")&&console.log("SQLiteLoggerConfig.updateConfiguration() - Configuration updated. Proxy loggers will use new settings automatically.",`Active proxies: ${Array.from(u.proxyInstances.keys())}`)}static setEnabled(e){u.currentConfig&&(u.currentConfig.enabled=e,u.updateConfiguration(u.currentConfig))}static enableModule(e,t,a){u.currentConfig&&u.currentConfig.modules&&(u.currentConfig.modules[e]={enabled:!0,levels:t||["debug","info","warn","error"],appenders:a||["console"]},u.updateConfiguration(u.currentConfig))}static disableModule(e){u.currentConfig&&u.currentConfig.modules&&(u.currentConfig.modules[e]={enabled:!1},u.updateConfiguration(u.currentConfig))}static createDebugConfig(){return new T().setEnabled(!0).setDefaultLevel("trace").addModule(b.UNIVERSAL_SQLITE,!0,["trace","debug","info","warn","error"],["console"]).addModule(b.DATABASE_MANAGER,!0,["trace","debug","info","warn","error"],["console"]).addModule(b.DATABASE_FACTORY,!0,["trace","debug","info","warn","error"],["console"]).addModule(b.UNIVERSAL_DAO,!0,["trace","debug","info","warn","error"],["console"]).addModule(b.BASE_SERVICE,!0,["trace","debug","info","warn","error"],["console"]).addModule(b.SERVICE_MANAGER,!0,["trace","debug","info","warn","error"],["console"]).addModule(b.QUERY_BUILDER,!0,["trace","debug","info","warn","error"],["console"]).addModule(b.BASE_ADAPTER,!0,["trace","debug","info","warn","error"],["console"]).build()}static createProductionConfig(){return new T().setEnabled(!0).setDefaultLevel("error").addModule(b.UNIVERSAL_SQLITE,!0,["error"],["console"]).addModule(b.DATABASE_MANAGER,!0,["error"],["console"]).addModule(b.DATABASE_FACTORY,!0,["error"],["console"]).addModule(b.UNIVERSAL_DAO,!0,["error"],["console"]).addModule(b.BASE_SERVICE,!0,["error"],["console"]).addModule(b.SERVICE_MANAGER,!0,["error"],["console"]).addModule(b.QUERY_BUILDER,!0,["error"],["console"]).addModule(b.BASE_ADAPTER,!0,["error"],["console"]).build()}static reset(){return u.initialize()}static getActiveProxyModules(){return Array.from(u.proxyInstances.keys())}static getCurrentConfig(){return u.currentConfig?Object.assign({},u.currentConfig):null}}u.instance=null,u.currentConfig=null,u.proxyInstances=new Map;const j=u.getInstance(),w=h=>{if(u.proxyInstances.has(h))return u.proxyInstances.get(h);const e=new z(h);return u.proxyInstances.set(h,e),e};class x{constructor(e,t,a){var s,r;this.adapter=e,this.dbPath=t,this.options=a,this.connection=null,this.isConnected=!1,this.inTransaction=!1,this.typeMappingConfig=null,this.createIfNotExists=!1,this.forceRecreate=!1,this.logger=w(b.UNIVERSAL_DAO),this.createIfNotExists=(s=a==null?void 0:a.createIfNotExists)!==null&&s!==void 0?s:!1,this.forceRecreate=(r=a==null?void 0:a.forceRecreate)!==null&&r!==void 0?r:!1,this.logger.trace("UniversalDAO constructor initialized",{dbPath:this.dbPath,createIfNotExists:this.createIfNotExists,forceRecreate:this.forceRecreate})}async connect(){if(this.logger.trace("Attempting to connect to database",{dbPath:this.dbPath}),this.isConnected){this.logger.debug("Already connected to database, skipping connection");return}try{this.connection=await this.adapter.connect(this.dbPath),this.isConnected=!0,this.logger.info("Successfully connected to database",{dbPath:this.dbPath})}catch(e){throw this.logger.error("Failed to connect to database",{dbPath:this.dbPath,error:e instanceof Error?e.message:e}),e}}async disconnect(){if(this.logger.trace("Attempting to disconnect from database"),this.connection&&this.isConnected)try{await this.connection.close(),this.connection=null,this.isConnected=!1,this.logger.info("Successfully disconnected from database")}catch(e){throw this.logger.error("Error during database disconnection",{error:e instanceof Error?e.message:e}),e}else this.logger.debug("Database was not connected, nothing to disconnect")}async close(){this.logger.trace("Closing database connection"),await this.disconnect()}setTypeMappingConfig(e){this.logger.trace("Setting type mapping configuration",{config:e}),this.typeMappingConfig=e,this.logger.debug("Type mapping configuration updated")}convertToSQLiteType(e){if(this.logger.trace("Converting generic type to SQLite type",{genericType:e}),!this.typeMappingConfig||!this.typeMappingConfig.sqlite){const a=this.getDefaultSQLiteType(e);return this.logger.debug("Using default type mapping",{genericType:e,sqliteType:a}),a}const t=this.typeMappingConfig.sqlite[e.toLowerCase()]||"TEXT";return this.logger.debug("Using custom type mapping",{genericType:e,sqliteType:t}),t}getDefaultSQLiteType(e){return{string:"TEXT",varchar:"TEXT",char:"TEXT",email:"TEXT",url:"TEXT",uuid:"TEXT",integer:"INTEGER",bigint:"INTEGER",smallint:"INTEGER",tinyint:"INTEGER",decimal:"REAL",numeric:"REAL",float:"REAL",double:"REAL",boolean:"INTEGER",timestamp:"TEXT",datetime:"TEXT",date:"TEXT",time:"TEXT",json:"TEXT",array:"TEXT",blob:"BLOB",binary:"BLOB"}[e.toLowerCase()]||"TEXT"}processColumnDefinition(e){this.logger.trace("Processing column definition",{columnName:e.name,originalType:e.type});const t=Object.assign({},e);t.type=this.convertToSQLiteType(e.type);const a=[];if(e.constraints){this.logger.trace("Processing column constraints",{columnName:e.name,constraints:e.constraints});const s=e.constraints.toUpperCase().split(" ");s.includes("PRIMARY")&&(a.push("PRIMARY KEY"),t.primary_key=!0),(s.includes("AUTO_INCREMENT")||s.includes("AUTOINCREMENT"))&&(t.primary_key&&a.push("AUTOINCREMENT"),t.auto_increment=!0),s.includes("NOT")&&s.includes("NULL")&&(a.push("NOT NULL"),t.nullable=!1),s.includes("UNIQUE")&&(t.primary_key||a.push("UNIQUE"),t.unique=!0);const r=s.indexOf("DEFAULT");if(r!==-1&&s.length>r+1){const i=s[r+1];a.push(`DEFAULT ${i}`),t.default=i}}return t.option_key=a.join(" ").trim(),this.logger.debug("Column definition processed",{columnName:e.name,finalType:t.type,options:t.option_key}),t}async initializeFromSchema(e){var t,a;this.logger.info("Initializing database schema",{schemaVersion:e.version,tableCount:Object.keys(e.schemas).length}),this.ensureConnected();let s=!1;try{const r=await this.execute("SELECT version FROM _schema_info ORDER BY applied_at DESC LIMIT 1");s=r.rows.length>0,s&&this.logger.debug("Existing schema detected",{currentVersion:(t=r.rows[0])===null||t===void 0?void 0:t.version})}catch(r){this.logger.debug("The first time for init from Schema! No existing schema detected"),s=!1}if(s&&!this.createIfNotExists&&!this.forceRecreate){this.logger.info("Schema exists and no recreation options set, using existing schema"),e.type_mapping&&this.setTypeMappingConfig(e.type_mapping);return}s&&this.forceRecreate&&(this.logger.warn("Force recreate option enabled, dropping all existing tables"),await this.dropAllTables()),e.type_mapping&&this.setTypeMappingConfig(e.type_mapping);try{this.logger.debug("Enabling foreign key constraints"),await this.execute("PRAGMA foreign_keys = ON")}catch(r){this.logger.warn("Failed to enable foreign key constraints",{error:r instanceof Error?r.message:r})}await this.beginTransaction();try{this.logger.info("Creating tables from schema");for(const[r,i]of Object.entries(e.schemas)){this.logger.debug("Creating table",{tableName:r,columnCount:i.cols.length});const o={name:r,cols:i.cols.map(l=>this.processColumnDefinition(l)),description:i.description,indexes:i.indexes,foreign_keys:i.foreign_keys};await this.createTableWithForeignKeys(o)}this.logger.info("Creating indexes for tables");for(const[r,i]of Object.entries(e.schemas))!((a=i.indexes)===null||a===void 0)&&a.length&&(this.logger.debug("Creating indexes for table",{tableName:r,indexCount:i.indexes.length}),await this.createIndexesForTable(r,i.indexes));await this.setSchemaVersion(e.version),await this.commitTransaction(),this.logger.info("Schema initialization completed successfully",{version:e.version})}catch(r){throw this.logger.error("Schema initialization failed, rolling back transaction",{error:r instanceof Error?r.message:r}),await this.rollbackTransaction(),r}}async dropAllTables(){this.logger.info("Dropping all existing tables");const e=await this.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'");this.logger.debug("Found tables to drop",{tableCount:e.rows.length}),await this.beginTransaction();try{for(const t of e.rows)this.logger.trace("Dropping table",{tableName:t.name}),await this.execute(`DROP TABLE IF EXISTS ${t.name}`);await this.commitTransaction(),this.logger.info("All tables dropped successfully")}catch(t){throw this.logger.error("Failed to drop tables, rolling back",{error:t instanceof Error?t.message:t}),await this.rollbackTransaction(),t}}async createTableWithForeignKeys(e){this.logger.trace("Creating table with foreign keys",{tableName:e.name});const t=e.cols.map(i=>`${i.name} ${i.type} ${i.option_key||""}`.trim()),a=[];if(e.foreign_keys){this.logger.debug("Processing foreign keys",{tableName:e.name,fkCount:e.foreign_keys.length});for(const i of e.foreign_keys){let o=`FOREIGN KEY (${i.column}) REFERENCES ${i.references.table}(${i.references.column})`;i.on_delete&&(o+=` ON DELETE ${i.on_delete}`),i.on_update&&(o+=` ON UPDATE ${i.on_update}`),a.push(o)}}const s=[...t,...a],r=`CREATE TABLE IF NOT EXISTS ${e.name} (${s.join(", ")})`;try{await this.execute(r),this.logger.debug("Table created successfully",{tableName:e.name})}catch(i){throw this.logger.error("Failed to create table",{tableName:e.name,sql:r,error:i instanceof Error?i.message:i}),i}}async createIndexesForTable(e,t){this.logger.trace("Creating indexes for table",{tableName:e,indexCount:t.length});for(const a of t){const s=a.columns.join(", "),r=a.unique||!1,i=`CREATE ${r?"UNIQUE":""} INDEX IF NOT EXISTS ${a.name} ON ${e} (${s})`;try{await this.execute(i),this.logger.debug("Index created successfully",{indexName:a.name,tableName:e,columns:a.columns,unique:r})}catch(o){throw this.logger.error("Failed to create index",{indexName:a.name,tableName:e,sql:i,error:o instanceof Error?o.message:o}),o}}}async beginTransaction(){if(this.logger.trace("Beginning transaction"),this.inTransaction){const e=new Error("Transaction already in progress");throw this.logger.error("Cannot begin transaction",{error:e.message}),e}try{await this.execute("BEGIN TRANSACTION"),this.inTransaction=!0,this.logger.debug("Transaction started successfully")}catch(e){throw this.logger.error("Failed to begin transaction",{error:e instanceof Error?e.message:e}),e}}async commitTransaction(){if(this.logger.trace("Committing transaction"),!this.inTransaction){const e=new Error("No transaction in progress");throw this.logger.error("Cannot commit transaction",{error:e.message}),e}try{await this.execute("COMMIT"),this.inTransaction=!1,this.logger.debug("Transaction committed successfully")}catch(e){throw this.logger.error("Failed to commit transaction",{error:e instanceof Error?e.message:e}),e}}async rollbackTransaction(){if(this.logger.trace("Rolling back transaction"),!this.inTransaction){const e=new Error("No transaction in progress");throw this.logger.error("Cannot rollback transaction",{error:e.message}),e}try{await this.execute("ROLLBACK"),this.inTransaction=!1,this.logger.debug("Transaction rolled back successfully")}catch(e){throw this.logger.error("Failed to rollback transaction",{error:e instanceof Error?e.message:e}),e}}async getSchemaVersion(){this.logger.trace("Getting schema version");try{const e=(await this.getRst("SELECT version FROM _schema_info ORDER BY applied_at DESC LIMIT 1")).version||"0";return this.logger.debug("Schema version retrieved",{version:e}),e}catch(e){return this.logger.debug("No schema version found, returning default",{defaultVersion:"0"}),"0"}}async setSchemaVersion(e){this.logger.trace("Setting schema version",{version:e});try{await this.execute(`CREATE TABLE IF NOT EXISTS _schema_info (
version TEXT NOT NULL,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)`),await this.execute("INSERT INTO _schema_info (version) VALUES (?)",[e]),this.logger.info("Schema version set successfully",{version:e})}catch(t){throw this.logger.error("Failed to set schema version",{version:e,error:t instanceof Error?t.message:t}),t}}async insert(e){this.logger.trace("Performing insert operation",{tableName:e.name});const t=e.cols.filter(o=>o.value!==void 0&&o.value!==null);if(t.length===0){const o=new Error("No valid columns to insert");throw this.logger.error("Insert operation failed",{tableName:e.name,error:o.message}),o}const a=t.map(o=>o.name).join(", "),s=t.map(()=>"?").join(", "),r=t.map(o=>typeof o.value=="object"?JSON.stringify(o.value):o.value),i=`INSERT INTO ${e.name} (${a}) VALUES (${s})`;this.logger.debug("Executing insert query",{tableName:e.name,columnCount:t.length,sql:i});try{const o=await this.execute(i,r);return this.logger.info("Insert operation completed successfully",{tableName:e.name,rowsAffected:o.rowsAffected,lastInsertRowid:o.lastInsertRowId}),o}catch(o){throw this.logger.error("Insert operation failed",{tableName:e.name,sql:i,error:o instanceof Error?o.message:o}),o}}async update(e){var t;this.logger.trace("Performing update operation",{tableName:e.name});const a=e.cols.filter(l=>{var m;return l.value!==void 0&&!(!((m=e.wheres)===null||m===void 0)&&m.some(f=>f.name===l.name))});if(a.length===0){const l=new Error("No columns to update");throw this.logger.error("Update operation failed",{tableName:e.name,error:l.message}),l}const s=a.map(l=>`${l.name} = ?`).join(", "),r=a.map(l=>typeof l.value=="object"?JSON.stringify(l.value):l.value);let i=`UPDATE ${e.name} SET ${s}`;const o=this.buildWhereClause(e.wheres);if(!o.sql){const l=new Error("WHERE clause is required for UPDATE operation");throw this.logger.error("Update operation failed",{tableName:e.name,error:l.message}),l}i+=o.sql,r.push(...o.params),this.logger.debug("Executing update query",{tableName:e.name,updateColumnCount:a.length,whereConditions:((t=e.wheres)===null||t===void 0?void 0:t.length)||0,sql:i});try{const l=await this.execute(i,r);return this.logger.info("Update operation completed successfully",{tableName:e.name,rowsAffected:l.rowsAffected}),l}catch(l){throw this.logger.error("Update operation failed",{tableName:e.name,sql:i,error:l instanceof Error?l.message:l}),l}}async delete(e){var t;this.logger.trace("Performing delete operation",{tableName:e.name});let a=`DELETE FROM ${e.name}`;const s=this.buildWhereClause(e.wheres);if(!s.sql){const r=new Error("WHERE clause is required for DELETE operation");throw this.logger.error("Delete operation failed",{tableName:e.name,error:r.message}),r}a+=s.sql,this.logger.debug("Executing delete query",{tableName:e.name,whereConditions:((t=e.wheres)===null||t===void 0?void 0:t.length)||0,sql:a});try{const r=await this.execute(a,s.params);return this.logger.info("Delete operation completed successfully",{tableName:e.name,rowsAffected:r.rowsAffected}),r}catch(r){throw this.logger.error("Delete operation failed",{tableName:e.name,sql:a,error:r instanceof Error?r.message:r}),r}}async select(e){this.logger.trace("Performing select single operation",{tableName:e.name});const{sql:t,params:a}=this.buildSelectQuery(e," LIMIT 1");this.logger.debug("Executing select single query",{tableName:e.name,sql:t});try{const s=await this.execute(t,a),r=s.rows[0]||{};return this.logger.debug("Select single operation completed",{tableName:e.name,hasResult:!!s.rows[0]}),r}catch(s){throw this.logger.error("Select single operation failed",{tableName:e.name,sql:t,error:s instanceof Error?s.message:s}),s}}async selectAll(e){this.logger.trace("Performing select all operation",{tableName:e.name});const{sql:t,params:a}=this.buildSelectQuery(e);this.logger.debug("Executing select all query",{tableName:e.name,sql:t});try{const s=await this.execute(t,a);return this.logger.debug("Select all operation completed",{tableName:e.name,rowCount:s.rows.length}),s.rows}catch(s){throw this.logger.error("Select all operation failed",{tableName:e.name,sql:t,error:s instanceof Error?s.message:s}),s}}buildSelectQuery(e,t=""){var a;let s=`SELECT ${e.cols.length>0?e.cols.map(i=>i.name).join(", "):"*"} FROM ${e.name}`;const r=this.buildWhereClause(e.wheres);if(s+=r.sql,!((a=e.orderbys)===null||a===void 0)&&a.length){const i=e.orderbys.map(o=>`${o.name} ${o.direction||"ASC"}`).join(", ");s+=` ORDER BY ${i}`}return e.limitOffset&&(e.limitOffset.limit&&(s+=` LIMIT ${e.limitOffset.limit}`),e.limitOffset.offset&&(s+=` OFFSET ${e.limitOffset.offset}`)),s+=t,{sql:s,params:r.params}}buildWhereClause(e,t="WHERE"){if(!e||e.length===0)return{sql:"",params:[]};const a=[],s=[];for(const r of e){const i=r.operator||"=";a.push(`${r.name} ${i} ?`),s.push(r.value)}return{sql:` ${t} ${a.join(" AND ")}`,params:s}}convertJsonToQueryTable(e,t,a=["id"]){var s,r;this.logger.trace("Converting JSON to QueryTable",{tableName:e,fieldCount:Object.keys(t).length,idFields:a});const i={name:e,cols:[],wheres:[]};for(const[o,l]of Object.entries(t))i.cols.push({name:o,value:l}),a.includes(o)&&l!==void 0&&((s=i.wheres)===null||s===void 0||s.push({name:o,value:l}));return this.logger.debug("JSON converted to QueryTable",{tableName:e,columnCount:i.cols.length,whereCount:((r=i.wheres)===null||r===void 0?void 0:r.length)||0}),i}async importData(e){this.logger.info("Starting data import operation",{tableName:e.tableName,totalRows:e.data.length,batchSize:e.batchSize||1e3,validateData:e.validateData,updateOnConflict:e.updateOnConflict,skipErrors:e.skipErrors});const t=Date.now(),a={totalRows:e.data.length,successRows:0,errorRows:0,errors:[],executionTime:0};if(!this.isConnected){const m=new Error("Database is not connected");throw this.logger.error("Import failed - database not connected"),m}if(!e.data||e.data.length===0)return this.logger.warn("No data provided for import, returning empty result"),a.executionTime=Date.now()-t,a;const s=await this.getTableInfo(e.tableName);if(s.length===0){const m=new Error(`Table '${e.tableName}' does not exist`);throw this.logger.error("Import failed - table does not exist",{tableName:e.tableName}),m}this.logger.debug("Table info retrieved for import",{tableName:e.tableName,columnCount:s.length});const r=new Map(s.map(m=>[m.name.toLowerCase(),m])),i=e.batchSize||1e3;let o=0;const l=!e.includeAutoIncrementPK;try{await this.beginTransaction();for(let m=0;m<e.data.length;m+=i){const f=e.data.slice(m,m+i);this.logger.debug("Processing import batch",{batchNumber:Math.floor(m/i)+1,batchSize:f.length,totalBatches:Math.ceil(e.data.length/i)});for(let y=0;y<f.length;y++){const N=m+y,A=f[y];try{const C=e.validateData?this.validateAndTransformRow(A,r,e.tableName,l):this.transformRowData(A,r,l);e.updateOnConflict&&e.conflictColumns?await this.insertOrUpdate(e.tableName,C,e.conflictColumns):await this.insertRow(e.tableName,C),a.successRows++}catch(C){a.errorRows++;const F={rowIndex:N,error:C instanceof Error?C.message:String(C),rowData:A};if(a.errors.push(F),this.logger.warn("Row import failed",{rowIndex:N,tableName:e.tableName,error:C instanceof Error?C.message:C}),e.onError&&e.onError(C instanceof Error?C:new Error(String(C)),N,A),!e.skipErrors)throw this.logger.error("Import operation stopped due to error and skipErrors=false"),C}o++,e.onProgress&&o%100===0&&e.onProgress(o,e.data.length)}}await this.commitTransaction(),this.logger.info("Data import completed successfully",{tableName:e.tableName,totalRows:a.totalRows,successRows:a.successRows,errorRows:a.errorRows,executionTime:Date.now()-t})}catch(m){throw this.logger.error("Import operation failed, rolling back transaction",{tableName:e.tableName,processedCount:o,error:m instanceof Error?m.message:m}),await this.rollbackTransaction(),m}return e.onProgress&&e.onProgress(o,e.data.length),a.executionTime=Date.now()-t,a}async importDataWithMapping(e,t,a,s={}){this.logger.info("Starting data import with column mapping",{tableName:e,dataRows:t.length,mappingCount:a.length});const r=t.map((i,o)=>{this.logger.trace("Transforming row with column mappings",{rowIndex:o});const l={};return a.forEach(m=>{if(i.hasOwnProperty(m.sourceColumn)){let f=i[m.sourceColumn];if(m.transform)try{f=m.transform(f)}catch(y){this.logger.warn("Column transformation failed",{rowIndex:o,sourceColumn:m.sourceColumn,targetColumn:m.targetColumn,error:y instanceof Error?y.message:y})}l[m.targetColumn]=f}}),l});return this.logger.debug("Data transformation completed",{originalRowCount:t.length,transformedRowCount:r.length}),await this.importData(Object.assign({tableName:e,data:r},s))}async importFromCSV(e,t,a={}){this.logger.info("Starting CSV import",{tableName:e,csvLength:t.length,delimiter:a.delimiter||",",hasHeader:a.hasHeader!==!1});const s=a.delimiter||",",r=a.hasHeader!==!1,i=t.split(`
`).filter(f=>f.trim());if(i.length===0){const f=new Error("CSV data is empty");throw this.logger.error("CSV import failed - empty data"),f}let o=[],l=0;if(r)o=i[0].split(s).map(f=>f.trim().replace(/^["']|["']$/g,"")),l=1,this.logger.debug("CSV headers extracted",{headers:o,headerCount:o.length});else{const f=i[0].split(s).length;o=Array.from({length:f},(y,N)=>`column_${N+1}`),this.logger.debug("Generated column headers for headerless CSV",{columnCount:f,headers:o})}const m=[];for(let f=l;f<i.length;f++){const y=i[f].split(s).map(A=>A.trim().replace(/^["']|["']$/g,"")),N={};o.forEach((A,C)=>{N[A]=y[C]||null}),m.push(N)}return this.logger.debug("CSV data parsed",{totalLines:i.length,dataRows:m.length,skipHeader:r}),a.columnMappings?(this.logger.debug("Using column mappings for CSV import"),await this.importDataWithMapping(e,m,a.columnMappings,a)):await this.importData(Object.assign({tableName:e,data:m},a))}validateAndTransformRow(e,t,a,s=!0){this.logger.trace("Validating and transforming row data",{tableName:a});const r={};for(const[i,o]of t.entries()){const l=o.notnull===1&&!o.dflt_value,m=o.pk===1&&o.type.toLowerCase().includes("integer");if(s&&m)continue;const f=this.findValueForColumn(e,i);if(l&&f==null){const y=new Error(`Required column '${i}' is missing or null in table '${a}'`);throw this.logger.error("Row validation failed",{tableName:a,columnName:i,error:y.message}),y}if(f!=null)try{r[i]=this.convertValueToColumnType(f,o.type)}catch(y){throw this.logger.error("Value conversion failed during validation",{tableName:a,columnName:i,value:f,columnType:o.type,error:y instanceof Error?y.message:y}),y}}return r}transformRowData(e,t,a=!0){this.logger.trace("Transforming row data without validation");const s={};for(const[r,i]of Object.entries(e)){const o=r.toLowerCase(),l=t.get(o);if(!l){this.logger.trace("Column not found in table schema, skipping",{columnName:r});continue}const m=l.pk===1&&l.type.toLowerCase().includes("integer");if(!(a&&m)&&i!=null)try{s[r]=this.convertValueToColumnType(i,l.type)}catch(f){this.logger.warn("Value conversion failed during transformation",{columnName:r,value:i,columnType:l.type,error:f instanceof Error?f.message:f})}}return s}findValueForColumn(e,t){if(e.hasOwnProperty(t))return e[t];const a=t.toLowerCase();for(const[s,r]of Object.entries(e))if(s.toLowerCase()===a)return r}convertValueToColumnType(e,t){if(e==null)return null;const a=t.toLowerCase();try{if(a.includes("integer")||a.includes("int")){if(typeof e=="boolean")return e?1:0;const s=parseInt(String(e));return isNaN(s)?null:s}if(a.includes("real")||a.includes("float")||a.includes("decimal")){const s=parseFloat(String(e));return isNaN(s)?null:s}if(a.includes("boolean")){if(typeof e=="boolean")return e?1:0;if(typeof e=="string"){const s=e.toLowerCase();return s==="true"||s==="1"||s==="yes"?1:0}return e?1:0}if(a.includes("json")){if(typeof e=="object")return JSON.stringify(e);if(typeof e=="string")try{return JSON.parse(e),e}catch(s){throw new Error(`Invalid JSON format for column type '${t}'`)}return JSON.stringify(e)}if(a.includes("timestamp")||a.includes("datetime")){if(e instanceof Date)return e.toISOString();if(typeof e=="string"||typeof e=="number"){const s=new Date(e);return isNaN(s.getTime())?e:s.toISOString()}return String(e)}return String(e)}catch(s){throw new Error(`Cannot convert value '${e}' to column type '${t}'`)}}async insertRow(e,t){const a=Object.keys(t),s=Object.values(t),r=a.map(()=>"?").join(", "),i=`INSERT INTO ${e} (${a.join(", ")}) VALUES (${r})`;try{await this.execute(i,s)}catch(o){throw this.logger.trace("Insert row failed",{tableName:e,columns:a,error:o instanceof Error?o.message:o}),o}}async insertOrUpdate(e,t,a){this.logger.trace("Attempting insert or update",{tableName:e,conflictColumns:a});try{await this.insertRow(e,t)}catch(s){if(this.isConflictError(s))this.logger.debug("Insert conflict detected, attempting update",{tableName:e}),await this.updateRowByColumns(e,t,a);else throw s}}async updateRowByColumns(e,t,a){const s=Object.keys(t).filter(N=>!a.includes(N)),r=a;if(s.length===0){this.logger.debug("No columns to update, skipping update operation",{tableName:e});return}const i=s.map(N=>`${N} = ?`).join(", "),o=r.map(N=>`${N} = ?`).join(" AND "),l=s.map(N=>t[N]),m=r.map(N=>t[N]),f=[...l,...m],y=`UPDATE ${e} SET ${i} WHERE ${o}`;try{await this.execute(y,f),this.logger.trace("Update by columns completed",{tableName:e,updateColumns:s,whereColumns:r})}catch(N){throw this.logger.error("Update by columns failed",{tableName:e,sql:y,error:N instanceof Error?N.message:N}),N}}isConflictError(e){return e.code==="SQLITE_CONSTRAINT_UNIQUE"||e.code==="SQLITE_CONSTRAINT_PRIMARYKEY"||e.message&&e.message.includes("UNIQUE constraint failed")}async getDatabaseInfo(){this.logger.trace("Getting database information");try{const e=await this.execute("SELECT name FROM sqlite_master WHERE type='table'"),t=await this.getSchemaVersion(),a={name:this.dbPath,tables:e.rows.map(s=>s.name),isConnected:this.isConnected,version:t};return this.logger.debug("Database information retrieved",{tableCount:a.tables.length,isConnected:a.isConnected,version:a.version}),a}catch(e){throw this.logger.error("Failed to get database information",{error:e instanceof Error?e.message:e}),e}}async getTableInfo(e){this.logger.trace("Getting table information",{tableName:e});try{const t=await this.execute(`PRAGMA table_info(${e})`);return this.logger.debug("Table information retrieved",{tableName:e,columnCount:t.rows.length}),t.rows}catch(t){throw this.logger.error("Failed to get table information",{tableName:e,error:t instanceof Error?t.message:t}),t}}async dropTable(e){this.logger.info("Dropping table",{tableName:e});const t=`DROP TABLE IF EXISTS ${e}`;try{await this.execute(t),this.logger.info("Table dropped successfully",{tableName:e})}catch(a){throw this.logger.error("Failed to drop table",{tableName:e,error:a instanceof Error?a.message:a}),a}}isConnectionOpen(){const e=this.isConnected&&!!this.connection;return this.logger.trace("Connection status checked",{isOpen:e}),e}async ensureConnected(){this.isConnectionOpen()||(this.logger.debug("Connection not open, attempting to connect"),await this.connect())}async execute(e,t=[]){var a;this.logger.trace("Executing SQL query",{sql:e.substring(0,100)+(e.length>100?"...":""),paramCount:t.length}),this.ensureConnected();try{const s=await this.connection.execute(e,t);return this.logger.trace("SQL query executed successfully",{rowsAffected:s.rowsAffected,rowsReturned:((a=s.rows)===null||a===void 0?void 0:a.length)||0}),s}catch(s){throw this.logger.error("SQL query execution failed",{sql:e.substring(0,200)+(e.length>200?"...":""),paramCount:t.length,error:s}),s}}async getRst(e,t=[]){return(await this.execute(e,t)).rows[0]||{}}async getRsts(e,t=[]){return(await this.execute(e,t)).rows}}const g=w(b.DATABASE_FACTORY);class v{static registerAdapter(e){g.info(`Registering SQLite adapter: ${e.constructor.name}`,{adapterName:e.constructor.name,totalAdapters:this.adapters.length+1}),this.adapters.push(e),g.debug(`Successfully registered adapter. Total adapters: ${this.adapters.length}`)}static getEnvironmentInfo(){g.trace("Detecting runtime environment");let e;return typeof navigator!="undefined"&&navigator.product==="ReactNative"?e="React Native":typeof globalThis.Bun!="undefined"?e="Bun":typeof globalThis.Deno!="undefined"?e="Deno":typeof window!="undefined"?e="Browser":typeof process!="undefined"?e="Node.js":e="Unknown",g.debug(`Detected runtime environment: ${e}`),e}static detectBestAdapter(){g.trace("Detecting best available SQLite adapter",{totalAdapters:this.adapters.length,environment:this.getEnvironmentInfo()});for(const e of this.adapters){if(g.trace(`Testing adapter: ${e.constructor.name}`),e.isSupported())return g.info(`Selected adapter: ${e.constructor.name}`,{adapterName:e.constructor.name,environment:this.getEnvironmentInfo()}),e;g.debug(`Adapter ${e.constructor.name} is not supported in current environment`)}throw g.error("No supported SQLite adapter found",{totalAdapters:this.adapters.length,environment:this.getEnvironmentInfo()}),new Error("No supported SQLite adapter found")}static async validateSchemaVersion(e,t){g.trace("Validating schema version compatibility",{databaseName:t.database_name,configVersion:t.version});try{const a=await e.getDatabaseInfo();if(g.debug("Retrieved database info",{databaseVersion:a.version,configVersion:t.version}),a.version!==t.version){const s=`Schema version mismatch: database (${a.version}) vs config (${t.version})`;throw g.error("Schema version mismatch",{databaseName:t.database_name,databaseVersion:a.version,configVersion:t.version}),new Error(s)}g.debug("Schema version validation successful",{databaseName:t.database_name,version:t.version})}catch(a){throw g.error("Error during schema version validation",{databaseName:t.database_name,error:a.message}),new Error(`Error validating schema version for ${t.database_name}: ${a.message}`)}}static validateSchema(e){if(g.trace("Validating database schema configuration"),!e)throw g.error("Schema validation failed: null or undefined schema"),new Error("Schema configuration is null or undefined.");if(typeof e.database_name!="string"||e.database_name.trim()==="")throw g.error("Schema validation failed: invalid database_name",{databaseName:e.database_name,type:typeof e.database_name}),new Error("Invalid or missing 'database_name' in schema. This is required to name the database file.");if(typeof e.schemas!="object"||e.schemas===null||Object.keys(e.schemas).length===0)throw g.error("Schema validation failed: invalid schemas object",{databaseName:e.database_name,schemasType:typeof e.schemas,schemasCount:e.schemas?Object.keys(e.schemas).length:0}),new Error("Invalid or missing 'schemas' object in schema. At least one table definition is required.");return g.debug("Schema validation successful",{databaseName:e.database_name,tablesCount:Object.keys(e.schemas).length,version:e.version}),!0}static createDAO(e,t){var a,s,r,i;g.info("Creating new UniversalDAO instance",{dbPath:e,hasCustomAdapter:!!(t!=null&&t.adapter),createIfNotExists:(a=t==null?void 0:t.createIfNotExists)!==null&&a!==void 0?a:!1,forceRecreate:(s=t==null?void 0:t.forceRecreate)!==null&&s!==void 0?s:!1});let o;t!=null&&t.adapter?(g.debug("Using provided custom adapter",{adapterName:t.adapter.constructor.name}),o=t.adapter):(g.debug("Detecting best adapter automatically"),o=this.detectBestAdapter());const l=new x(o,e,{createIfNotExists:(r=t==null?void 0:t.createIfNotExists)!==null&&r!==void 0?r:!1,forceRecreate:(i=t==null?void 0:t.forceRecreate)!==null&&i!==void 0?i:!1});return g.debug("UniversalDAO instance created successfully",{dbPath:e,adapterName:o.constructor.name}),l}static async openExisting(e,t={}){g.info("Opening existing database",{dbName:e,options:t});const a=e.endsWith(".db")?e:`${e}.db`;g.debug("Resolved database filename",{originalName:e,resolvedName:a});const s=this.createDAO(a,t);try{return g.debug("Connecting to database",{dbFileName:a}),await s.connect(),g.debug("Running integrity check",{dbFileName:a}),await s.execute("PRAGMA integrity_check"),g.info("Database opened successfully",{dbFileName:a}),s}catch(r){g.error("Error opening database",{dbFileName:a,error:r.message});try{await s.close()}catch(i){g.warn("Error closing DAO after failed open",{dbFileName:a,closeError:i.message})}throw new Error(`Error opening database '${a}': ${r.message}`)}}static async createOrOpenInternal(e,t=!1,a=!1){g.info("Creating or opening database internally",{isForceInit:t,isForceDelete:a,hasConfig:!!e.config,hasConfigAsset:!!e.configAsset});let s;if(g.trace("Loading database schema"),e.config)g.debug("Using provided config object"),s=e.config;else if(e.configAsset)g.debug("Using provided config asset"),s=e.configAsset;else throw g.error("No database schema configuration provided"),new Error("Either 'config', 'configAsset', or 'configPath' must be provided to the factory.");g.trace("Validating schema configuration"),this.validateSchema(s);const r=s.database_name.endsWith(".db")?s.database_name:`${s.database_name}.db`;g.debug("Database filename resolved",{originalName:s.database_name,resolvedName:r}),g.debug("Creating DAO instance",{dbFileName:r,hasCustomAdapter:!!e.adapter,createIfNotExists:t,forceRecreate:a});const i=this.createDAO(r,{adapter:e.adapter,createIfNotExists:t,forceRecreate:a});try{g.debug("Connecting to database",{dbFileName:r}),await i.connect(),g.debug("Initializing database schema",{dbFileName:r}),await i.initializeFromSchema(s),g.debug("Validating schema version compatibility");try{await this.validateSchemaVersion(i,s)}catch(o){throw g.error("Schema version validation failed",{dbFileName:r,error:o.message}),await i.close(),new Error(`Schema mismatch in existing database. Use forceRecreate=true to recreate with updated schema. Error: ${o.message}`)}return g.info("Database created/opened successfully",{dbFileName:r,databaseName:s.database_name,version:s.version}),i}catch(o){if(g.error("Error during database creation/opening",{dbFileName:r,error:o.message}),i.isConnectionOpen())try{await i.close()}catch(l){g.warn("Error closing DAO after failed operation",{dbFileName:r,closeError:l.message})}throw o}}static async create(e){var t,a;return g.warn("Creating database with force recreate - this will delete existing database",{databaseName:((t=e.config)===null||t===void 0?void 0:t.database_name)||((a=e.configAsset)===null||a===void 0?void 0:a.database_name)}),this.createOrOpenInternal(e,!0,!0)}static async createOrOpen(e,t=!1){var a,s;return g.info("Smart create or open database",{databaseName:((a=e.config)===null||a===void 0?void 0:a.database_name)||((s=e.configAsset)===null||s===void 0?void 0:s.database_name),isForceInit:t}),this.createOrOpenInternal(e,t)}static async createFromAsset(e,t={}){g.info("Creating database from asset",{databaseName:e.database_name,version:e.version});try{return await this.create(Object.assign(Object.assign({},t),{configAsset:e}))}catch(a){throw g.error("Error creating database from asset",{databaseName:e.database_name,error:a.message}),new Error(`Error creating database from asset: ${a.message}`)}}static async createFromConfig(e,t={}){g.info("Creating database from config",{databaseName:e.database_name,version:e.version});try{return await this.create(Object.assign(Object.assign({},t),{config:e}))}catch(a){throw g.error("Error creating database from config",{databaseName:e.database_name,error:a.message}),new Error(`Error creating database from config: ${a.message}`)}}}v.adapters=[];const n=w(b.DATABASE_MANAGER);class p{static getMaxConnections(){return n.trace("Getting max connections",{maxConnections:this.maxConnections}),this.maxConnections}static setMaxConnections(e){if(n.debug("Setting max connections",{newMaxConnections:e,currentMax:this.maxConnections}),e<=0)throw n.error("Invalid max connections value",{maxConnections:e}),new Error("Maximum connections must be a positive number");const t=Object.keys(this.connections).length;if(t>e)throw n.error("Cannot set max connections - would exceed current active connections",{requestedMax:e,currentActiveConnections:t,activeConnectionKeys:Object.keys(this.connections)}),new Error(`Cannot set maximum connections to ${e}. Current active connections (${t}) exceed the new limit. Please close some connections first.`);this.maxConnections=e,n.info("Max connections updated successfully",{newMaxConnections:e,currentActiveConnections:t})}static setSchemaManager(e){n.debug("Setting schema manager",{hadPreviousManager:this.schemaManager!==null}),this.schemaManager=e,n.info("Schema manager set successfully")}static registerSchema(e,t){n.debug("Registering schema",{key:e,schemaName:t.database_name}),this.schemaConfigurations[e]=t,n.info("Schema registered successfully",{key:e,schemaName:t.database_name})}static registerSchemas(e){const t=Object.keys(e);n.debug("Registering multiple schemas",{count:t.length,keys:t}),Object.entries(e).forEach(([a,s])=>{this.registerSchema(a,s)}),n.info("Multiple schemas registered successfully",{count:t.length})}static getSchema(e){if(n.trace("Getting schema",{key:e}),this.schemaConfigurations[e])return n.trace("Schema found in internal configurations",{key:e}),this.schemaConfigurations[e];if(this.schemaManager){n.trace("Checking external schema manager",{key:e});const t=this.schemaManager.getSchema(e);if(t)return n.trace("Schema found in external manager",{key:e}),t}n.warn("Schema not found",{key:e})}static getAvailableSchemas(){var e;const t=Object.keys(this.schemaConfigurations),a=((e=this.schemaManager)===null||e===void 0?void 0:e.getAllSchemaKeys())||[],s=[...new Set([...t,...a])];return n.trace("Getting available schemas",{internalCount:t.length,externalCount:a.length,totalUnique:s.length}),s}static registerRole(e){n.debug("Registering role",{roleName:e.roleName,requiredDatabases:e.requiredDatabases,optionalDatabases:e.optionalDatabases,priority:e.priority}),this.roleRegistry[e.roleName]=e,n.info("Role registered successfully",{roleName:e.roleName})}static registerRoles(e){n.debug("Registering multiple roles",{count:e.length}),e.forEach(t=>this.registerRole(t)),n.info("Multiple roles registered successfully",{count:e.length})}static getRegisteredRoles(){return n.trace("Getting registered roles",{count:Object.keys(this.roleRegistry).length}),Object.assign({},this.roleRegistry)}static getRoleDatabases(e){n.trace("Getting role databases",{roleName:e});const t=this.roleRegistry[e];if(!t)throw n.error("Role not found in registry",{roleName:e,availableRoles:Object.keys(this.roleRegistry)}),new Error(`Role '${e}' is not registered.`);const a=[...t.requiredDatabases,...t.optionalDatabases||[]];return n.trace("Role databases retrieved",{roleName:e,databases:a}),a}static getCurrentUserDatabases(){n.trace("Getting current user databases",{currentUserRoles:this.currentUserRoles});const e=new Set;e.add("core");for(const a of this.currentUserRoles){const s=this.roleRegistry[a];s?(s.requiredDatabases.forEach(r=>e.add(r)),s.optionalDatabases&&s.optionalDatabases.forEach(r=>e.add(r))):n.warn("Role config not found for current user role",{roleName:a})}const t=Array.from(e);return n.debug("Current user databases calculated",{userRoles:this.currentUserRoles,databases:t}),t}static async initializeCoreConnection(){if(n.debug("Initializing core database connection"),this.connections.core){n.debug("Core connection already exists");return}try{const e=this.getSchema("core");if(!e)throw n.error("Core database schema not found"),new Error("Core database schema not found.");n.debug("Creating core database connection",{schemaName:e.database_name});const t=await v.createOrOpen({config:e},!1);await t.execute("PRAGMA integrity_check"),this.connections.core=t,n.info("Core database connection initialized successfully")}catch(e){throw n.error("Error initializing core database",{error:e.message}),new Error(`Error initializing core database: ${e.message}`)}}static async setCurrentUserRoles(e,t){n.debug("Setting current user roles",{userRoles:e,primaryRole:t});for(const s of e)if(!this.roleRegistry[s])throw n.error("Role not registered",{roleName:s,availableRoles:Object.keys(this.roleRegistry)}),new Error(`Role '${s}' is not registered. Please register it first.`);const a=[...this.currentUserRoles];this.currentUserRoles=e,this.currentRole=t||e[0]||null,n.info("User roles updated",{previousRoles:a,newRoles:e,primaryRole:this.currentRole});try{await this.initializeUserRoleConnections(),await this.cleanupUnusedConnections(a),n.info("User role connections initialized successfully")}catch(s){throw n.error("Failed to initialize user role connections",{error:s.message}),s}}static getCurrentUserRoles(){return n.trace("Getting current user roles",{roles:this.currentUserRoles}),[...this.currentUserRoles]}static getCurrentRole(){return n.trace("Getting current primary role",{role:this.currentRole}),this.currentRole}static async initializeUserRoleConnections(){const e=this.getCurrentUserDatabases();n.debug("Initializing user role connections",{requiredDatabases:e});const t=[],a=e.map(async s=>{if(this.connections[s]){n.trace("Database already connected",{dbKey:s});return}try{n.debug("Initializing database connection",{dbKey:s});const r=this.getSchema(s);if(!r)throw new Error(`Database key '${s}' not found in schema configurations.`);const i=await v.createOrOpen({config:r},!1);await i.execute("PRAGMA integrity_check"),this.connections[s]=i,n.info("Database connection initialized",{dbKey:s,schemaName:r.database_name})}catch(r){const i=r instanceof Error?r:new Error(String(r));n.error("Failed to initialize database connection",{dbKey:s,error:i.message}),this.currentUserRoles.some(o=>{const l=this.roleRegistry[o];return l&&l.requiredDatabases.includes(s)})?t.push({key:s,error:i}):n.warn("Optional database initialization failed",{dbKey:s,error:i.message})}});if(await Promise.all(a),t.length>0){const s=t.map(r=>` - ${r.key}: ${r.error.message}`).join(`
`);throw n.error("Failed to initialize required databases",{failedDatabases:t.map(r=>r.key),errorSummary:s}),new Error(`Failed to initialize required databases for user roles:
${s}`)}}static async cleanupUnusedConnections(e){n.debug("Cleaning up unused connections",{previousRoles:e});const t=new Set;t.add("core");for(const r of e){const i=this.roleRegistry[r];i&&(i.requiredDatabases.forEach(o=>t.add(o)),i.optionalDatabases&&i.optionalDatabases.forEach(o=>t.add(o)))}const a=new Set(this.getCurrentUserDatabases()),s=Array.from(t).filter(r=>!a.has(r));if(n.debug("Databases to cleanup",{databasesToClose:s,previousDatabaseCount:t.size,currentDatabaseCount:a.size}),s.length>0){for(const r of s)if(this.connections[r])try{n.debug("Closing unused database connection",{dbKey:r}),await this.connections[r].close(),delete this.connections[r],n.info("Database connection closed",{dbKey:r})}catch(i){n.error("Error closing database connection during cleanup",{dbKey:r,error:i.message})}n.info("Cleanup completed",{closedConnections:s})}else n.debug("No connections to cleanup")}static hasAccessToDatabase(e){const t=this.getSchema(e)!==void 0;return n.trace("Checking database access",{dbKey:e,hasAccess:t}),t}static get(e){if(n.trace("Getting database connection",{key:e}),!this.hasAccessToDatabase(e))throw n.error("Access denied to database",{key:e}),new Error(`Access denied: Database '${e}' is not accessible.`);const t=this.connections[e];if(!t)throw n.error("Database not connect