@xwxfox/foxdb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +274 -0
- package/dist/index.d.mts +1463 -0
- package/dist/index.mjs +48 -0
- package/package.json +67 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{Database as nA,constants as dA}from"bun:sqlite";import{existsSync as pA,unlinkSync as cA}from"fs";class f{db;constructor(A={}){let $=A.path??":memory:";this.db=new nA($,{create:!0}),this.db.run("PRAGMA journal_mode = WAL;");let X=A.synchronous??"NORMAL",Z=A.cacheSize??-64000,Y=A.busyTimeout??5000,G=A.mmapSize??268435456;this.db.run(`PRAGMA synchronous = ${X};`),this.db.run(`PRAGMA cache_size = ${Z};`),this.db.run(`PRAGMA busy_timeout = ${Y};`),this.db.run(`PRAGMA mmap_size = ${G};`),this.db.run("PRAGMA foreign_keys = ON;"),this.db.run("PRAGMA temp_store = MEMORY;")}exec(A){this.db.run(A)}transaction(A){return this.db.transaction(A)()}close(){for(let A of this._stmtCache.values())try{A.finalize()}catch{}this._stmtCache.clear();try{this.db.fileControl(dA.SQLITE_FCNTL_PERSIST_WAL,0),this.db.run("PRAGMA wal_checkpoint(TRUNCATE);")}catch{}this.db.close()}static _MAX_CACHE_SIZE=256;_stmtCache=new Map;prepare(A){let $=this._stmtCache.get(A);if(!$){if($=this.db.prepare(A),this._stmtCache.size>=f._MAX_CACHE_SIZE){let X=this._stmtCache.keys().next().value;if(X!==void 0){let Z=this._stmtCache.get(X);try{Z?.finalize()}catch{}this._stmtCache.delete(X)}}this._stmtCache.set(A,$)}return $}clearCache(){for(let A of this._stmtCache.values())try{A.finalize()}catch{}this._stmtCache.clear()}}function iA(A){if(A===":memory:")return[];return[A,`${A}-wal`,`${A}-shm`,`${A}-journal`].filter(($)=>pA($))}function o(A){for(let $ of iA(A))try{cA($)}catch{}}import{Compile as G$}from"typebox/compile";class b extends Error{code;trace;context;constructor(A,$){super(A);this.name="ORMError",this.code=$.code,this.trace=$.trace,this.context=$.context??{}}}var YA=[];function lA(A,$){YA.push({label:A,time:Date.now(),details:$})}function oA(){YA.pop()}function HA(){return YA.slice()}function x(A,$,X){lA(A,$);try{return X()}finally{oA()}}function O(A,$,X){throw new b($,{code:A,trace:HA(),context:X})}import{IsObject as p,IsArray as s,IsString as sA,IsNumber as rA,IsInteger as tA,IsBoolean as aA,IsLiteral as eA,IsOptional as A$}from"typebox";function LA(A){if(A$(A))return{schema:A,optional:!0};return{schema:A,optional:!1}}function MA(A){if(tA(A))return"INTEGER";if(rA(A))return"REAL";if(aA(A))return"INTEGER";if(sA(A))return"TEXT";if(eA(A)){let $=A.const;if(typeof $==="number")return Number.isInteger($)?"INTEGER":"REAL";if(typeof $==="boolean")return"INTEGER";return"TEXT"}return"TEXT"}function $$(A){let $=[];for(let[X,Z]of Object.entries(A)){if(s(Z))continue;if(p(Z))continue;let{schema:Y,optional:G}=LA(Z);$.push({name:X,sqlType:p(Y)?"TEXT":MA(Y),nullable:G,optional:G})}for(let[X,Z]of Object.entries(A))if(!s(Z)&&p(Z))$.push({name:X,sqlType:"TEXT",nullable:!1,optional:!1});return $}function m(A,$){let X=[],Z=[];for(let[Y,G]of Object.entries($.properties))if(s(G)&&p(G.items)){let H=G.items,Q=`${A}__${Y}`;Z.push({fieldName:Y,tableName:Q,itemSchema:H,columns:$$(H.properties)})}else if(p(G))X.push({name:Y,sqlType:"TEXT",nullable:!1,optional:!1});else if(!s(G)){let{schema:H,optional:Q}=LA(G);X.push({name:Y,sqlType:MA(H),nullable:Q,optional:Q})}return{tableName:A,columns:X,subTables:Z}}function GA(A,$){let X=[],Z=A.columns.map((Y)=>{let G=!Y.nullable?" NOT NULL":"",H=Y.name===$?" PRIMARY KEY":"";return` "${Y.name}" ${Y.sqlType}${H}${G}`});X.push(`CREATE TABLE IF NOT EXISTS "${A.tableName}" (
|
|
3
|
+
${Z.join(`,
|
|
4
|
+
`)}
|
|
5
|
+
)`);for(let Y of A.subTables){let G=[' "_id" INTEGER PRIMARY KEY AUTOINCREMENT',` "_owner_id" ${A.columns.find((H)=>H.name===$)?.sqlType??"TEXT"} NOT NULL`,' "_index" INTEGER NOT NULL',...Y.columns.map((H)=>{let Q=!H.nullable?" NOT NULL":"";return` "${H.name}" ${H.sqlType}${Q}`})];X.push(`CREATE TABLE IF NOT EXISTS "${Y.tableName}" (
|
|
6
|
+
${G.join(`,
|
|
7
|
+
`)}
|
|
8
|
+
)`),X.push(`CREATE INDEX IF NOT EXISTS "idx_${Y.tableName}__owner" ON "${Y.tableName}" ("_owner_id")`)}return X}function PA(A,$,X,Z){let Y=Z??`idx_${A}__${$.join("_")}`,G=X?"UNIQUE ":"",H=$.map((Q)=>`"${Q}"`).join(", ");return`CREATE ${G}INDEX IF NOT EXISTS "${Y}" ON "${A}" (${H})`}function c(A,$){let X={};for(let Z of $.columns){let Y=A[Z.name];if(Y===void 0||Y===null)X[Z.name]=null;else if(Z.sqlType==="TEXT"&&typeof Y==="object")X[Z.name]=JSON.stringify(Y);else if(Z.sqlType==="INTEGER"&&typeof Y==="boolean")X[Z.name]=Y?1:0;else X[Z.name]=CA(Y)}return X}function i(A,$,X){return $.map((Z,Y)=>{let G={_owner_id:A,_index:Y};for(let H of X.columns){let Q=Z[H.name];if(Q===void 0||Q===null)G[H.name]=null;else if(H.sqlType==="TEXT"&&typeof Q==="object")G[H.name]=JSON.stringify(Q);else if(H.sqlType==="INTEGER"&&typeof Q==="boolean")G[H.name]=Q?1:0;else G[H.name]=CA(Q)}return G})}function CA(A){if(A===null||A===void 0)return null;if(typeof A==="string"||typeof A==="number"||typeof A==="boolean"||typeof A==="bigint")return A;if(typeof A==="object")return JSON.stringify(A);return String(A)}function jA(A,$,X){let Z={};for(let Y of $.columns){let G=A[Y.name];if(Y.sqlType==="TEXT"&&typeof G==="string")try{let H=JSON.parse(G);Z[Y.name]=typeof H==="object"?H:G}catch{Z[Y.name]=G}else if(Y.sqlType==="INTEGER"&&typeof G==="number")Z[Y.name]=G;else Z[Y.name]=G??null}for(let Y of $.subTables)Z[Y.fieldName]=X.get(Y.tableName)??[];return Z}function X$(A){return typeof A==="object"&&A!==null}function Z$(A,$){if("eq"in $)return{sql:`"${A}" = ?`,params:[$.eq]};if("ne"in $)return{sql:`"${A}" != ?`,params:[$.ne]};if("gt"in $)return{sql:`"${A}" > ?`,params:[$.gt]};if("gte"in $)return{sql:`"${A}" >= ?`,params:[$.gte]};if("lt"in $)return{sql:`"${A}" < ?`,params:[$.lt]};if("lte"in $)return{sql:`"${A}" <= ?`,params:[$.lte]};if("like"in $)return{sql:`"${A}" LIKE ?`,params:[$.like]};if("between"in $){let[X,Z]=$.between;return{sql:`"${A}" BETWEEN ? AND ?`,params:[X,Z]}}if("in"in $){let X=$.in,Z=X.map(()=>"?").join(", ");return{sql:`"${A}" IN (${Z})`,params:[...X]}}if("notIn"in $){let X=$.notIn,Z=X.map(()=>"?").join(", ");return{sql:`"${A}" NOT IN (${Z})`,params:[...X]}}if("isNull"in $)return{sql:`"${A}" IS NULL`,params:[]};if("isNotNull"in $)return{sql:`"${A}" IS NOT NULL`,params:[]};O("UNKNOWN_FILTER",`foxdb: unknown filter operator for column "${A}"`,{column:A})}function r(A){if(!A||Object.keys(A).length===0)return{sql:"",params:[]};let $=[],X=[];for(let[Z,Y]of Object.entries(A)){if(!X$(Y))continue;let G=Z$(Z,Y);$.push(G.sql),X.push(...G.params)}if($.length===0)return{sql:"",params:[]};return{sql:`WHERE ${$.join(" AND ")}`,params:X}}function Y$(A){if(!A)return"";let $=globalThis.Array.isArray(A)?A:[A];if($.length===0)return"";return`ORDER BY ${$.map((Z)=>`"${Z.column}" ${Z.direction??"ASC"}`).join(", ")}`}function H$(A,$){let X=[],Z=[];if(A!==void 0)X.push("LIMIT ?"),Z.push(A);if($!==void 0)X.push("OFFSET ?"),Z.push($);return{sql:X.join(" "),params:Z}}function t(A,$){let{sql:X,params:Z}=r($.where),Y=Y$($.orderBy),{sql:G,params:H}=H$($.limit,$.offset),Q=[`SELECT * FROM "${A}"`,X,Y,G].filter(Boolean).join(" "),_=[`SELECT COUNT(*) as "_count" FROM "${A}"`,X].filter(Boolean).join(" ");return{sql:Q,params:[...Z,...H],countSql:_,countParams:Z}}function u(A,$){let X=Object.keys($),Z=X.map((G)=>`"${G}"`).join(", "),Y=X.map(()=>"?").join(", ");return{sql:`INSERT INTO "${A}" (${Z}) VALUES (${Y})`,params:X.map((G)=>$[G])}}function DA(A,$,X,Z){let Y=Object.keys($),G=Y.map((K)=>`"${K}"`).join(", "),H=Y.map(()=>"?").join(", "),Q=X.map((K)=>`"${K}"`).join(", "),_=Z.map((K)=>`"${K}" = excluded."${K}"`).join(", ");return{sql:`INSERT INTO "${A}" (${G}) VALUES (${H}) ON CONFLICT (${Q}) DO UPDATE SET ${_}`,params:Y.map((K)=>$[K])}}function OA(A,$,X,Z){let Y=Object.entries(Z).filter(([H])=>H!==$);if(Y.length===0)O("NO_COLUMNS_TO_UPDATE","foxdb: no columns to update",{table:A});let G=Y.map(([H])=>`"${H}" = ?`).join(", ");return{sql:`UPDATE "${A}" SET ${G} WHERE "${$}" = ?`,params:[...Y.map(([,H])=>H),X]}}var JA={createdAt:"createdAt",updatedAt:"updatedAt"};function QA(A,$){if(A===!1||!A)return{createdAt:null,updatedAt:null};let X=typeof A==="object"&&A.createdAt!==void 0?A.createdAt:JA.createdAt,Z=typeof A==="object"&&A.updatedAt!==void 0?A.updatedAt:JA.updatedAt,Y=new Set($.columns.map((G)=>G.name));return{createdAt:Y.has(X)?null:X,updatedAt:Y.has(Z)?null:Z}}class a{tableName;meta;validator;db;descriptor;_entityProto=null;_timestampNames;_materialize;_materializeMany;_events;setEventBus(A){this._events=A}constructor(A,$,X){this.tableName=A,this.descriptor=$,this.db=X,this.meta=m(A,$.schema),this._timestampNames=QA($.timestamps,this.meta),this.validator=G$($.schema),this._migrate()}setMaterializer(A,$){this._materialize=A,this._materializeMany=$;let X=Object.create(null);Object.defineProperty(X,"materialize",{value:function(){return A(this)},writable:!1,enumerable:!1,configurable:!1}),this._entityProto=X}_wrap(A){if(!this._entityProto)return A;let $=Object.create(this._entityProto);return Object.assign($,A),$}_record(A){return A}_emit(A,$){if(!this._events)return;let X=Date.now(),Y={...{table:this.tableName,operation:A,timestamp:X},...$},G=`${this.tableName}.${A}`;if(this._events.has(G))this._events.emit(G,Y);let H;if(A.startsWith("find")||A==="count")H="read";else if(A==="delete"||A==="deleteWhere"||A==="flush")H="delete";else H="write";let Q=`${this.tableName}.${H}`;if(this._events.has(Q))this._events.emit(Q,{...Y,operation:H})}_migrate(){let A=this.descriptor.primaryKey.name,$=GA(this.meta,A);this.db.transaction(()=>{for(let X of $)this.db.exec(X);for(let X of this.descriptor.indexes??[])this.db.exec(PA(this.tableName,X.columns.map((Z)=>Z.name),X.unique??!1,X.name))}),this.db.clearCache()}parse(A){return this.validator.Parse(A)}check(A){return this.validator.Check(A)}insert(A){return x("repository.insert",{table:this.tableName},()=>{let $=this.parse(A),X=this._record($),Z=Date.now();if(this._timestampNames.createdAt)X[this._timestampNames.createdAt]=Z;if(this._timestampNames.updatedAt)X[this._timestampNames.updatedAt]=Z;return this.db.transaction(()=>{let Y=c(X,this.meta),{sql:G,params:H}=u(this.tableName,Y);this.db.prepare(G).run(...H);let Q=X[this.descriptor.primaryKey.name];for(let _ of this.meta.subTables){let K=X[_.fieldName];if(!globalThis.Array.isArray(K)||K.length===0)continue;let C=i(Q,K,_);for(let J of C){let{sql:E,params:T}=u(_.tableName,J);this.db.prepare(E).run(...T)}}}),this._emit("insert",{data:$}),this._wrap(this._record($))})}insertMany(A){return x("repository.insertMany",{table:this.tableName},()=>{let $=A.map((X)=>this.parse(X));return this.db.transaction(()=>{for(let X of $)this._insertParsed(this._record(X))}),this._emit("insertMany",{data:$}),$.map((X)=>this._wrap(this._record(X)))})}_insertParsed(A){let $=Date.now();if(this._timestampNames.createdAt)A[this._timestampNames.createdAt]=$;if(this._timestampNames.updatedAt)A[this._timestampNames.updatedAt]=$;let X=c(A,this.meta),{sql:Z,params:Y}=u(this.tableName,X);this.db.prepare(Z).run(...Y);let G=A[this.descriptor.primaryKey.name];for(let H of this.meta.subTables){let Q=A[H.fieldName];if(!globalThis.Array.isArray(Q)||Q.length===0)continue;let _=i(G,Q,H);for(let K of _){let{sql:C,params:J}=u(H.tableName,K);this.db.prepare(C).run(...J)}}}upsert(A){return x("repository.upsert",{table:this.tableName},()=>{let $=this.parse(A.data),X=this._record($),Z=Date.now();if(this._timestampNames.createdAt)X[this._timestampNames.createdAt]=Z;if(this._timestampNames.updatedAt)X[this._timestampNames.updatedAt]=Z;let Y=c(X,this.meta),G=globalThis.Array.isArray(A.conflictTarget)?A.conflictTarget:[A.conflictTarget],H=Object.keys(Y),Q=A.update??H.filter((_)=>!G.includes(_));return this.db.transaction(()=>{let{sql:_,params:K}=DA(this.tableName,Y,G,Q);this.db.prepare(_).run(...K);let C=X[this.descriptor.primaryKey.name];for(let J of this.meta.subTables){this.db.prepare(`DELETE FROM "${J.tableName}" WHERE "_owner_id" = ?`).run(C);let E=X[J.fieldName];if(!globalThis.Array.isArray(E)||E.length===0)continue;let T=i(C,E,J);for(let k of T){let{sql:v,params:d}=u(J.tableName,k);this.db.prepare(v).run(...d)}}}),this._emit("upsert",{data:$}),this._wrap(this._record($))})}findById(A){return x("repository.findById",{table:this.tableName},()=>{let $=this._findByIdRaw(A);return this._emit("findById",{id:A,result:$}),$})}_findByIdRaw(A){let $=this.descriptor.primaryKey.name,Z=this.db.prepare(`SELECT * FROM "${this.tableName}" WHERE "${$}" = ? LIMIT 1`).get(A);if(!Z)return null;return this._wrap(this._hydrateOne(Z))}findMany(A={}){return x("repository.findMany",{table:this.tableName},()=>{let{sql:$,params:X}=t(this.tableName,A),G=this.db.prepare($).all(...X).map((H)=>this._wrap(this._hydrateOne(H,A.include)));return this._emit("findMany",{options:A,result:G}),G})}findPage(A={}){return x("repository.findPage",{table:this.tableName},()=>{let{sql:$,params:X,countSql:Z,countParams:Y}=t(this.tableName,A),G=this.db.prepare($).all(...X).map((_)=>this._wrap(this._hydrateOne(_,A.include))),H=this.db.prepare(Z).get(...Y),Q={data:G,total:H._count,limit:A.limit??G.length,offset:A.offset??0};return this._emit("findPage",{options:A,result:Q}),Q})}findOne(A={}){return x("repository.findOne",{table:this.tableName},()=>{let{sql:$,params:X}=t(this.tableName,{...A,limit:1}),Y=this.db.prepare($).get(...X),G=Y?this._wrap(this._hydrateOne(Y,A.include)):null;return this._emit("findOne",{options:A,result:G}),G})}findManyMaterialized(A={}){let $=this.findMany(A);if(!this._materializeMany)return $;let X=this._materializeMany($);if(this._entityProto){for(let Z of X)if(Object.getPrototypeOf(Z)!==this._entityProto)Object.setPrototypeOf(Z,this._entityProto)}return X}count(A){return x("repository.count",{table:this.tableName},()=>{let{sql:$,params:X}=r(A),Z=`SELECT COUNT(*) as "_count" FROM "${this.tableName}" ${$}`.trim(),Y=this.db.prepare(Z).get(...X);return this._emit("count",{where:A,result:Y._count}),Y._count})}update(A){return x("repository.update",{table:this.tableName},()=>{let $=this._record(A),X=this.descriptor.primaryKey.name,Z=$[X];if(Z===void 0||Z===null)O("UPDATE_MISSING_PK",`foxdb: update() requires primary key "${X}"`,{table:this.tableName,column:X});let Y=this._findByIdRaw(Z);if(!Y)return null;let G=this.parse({...Y,...A}),H=this._record(G);if(this._timestampNames.updatedAt)H[this._timestampNames.updatedAt]=Date.now();let Q=c(H,this.meta),_=Object.fromEntries(Object.entries(Q).filter(([C])=>C!==X));this.db.transaction(()=>{let{sql:C,params:J}=OA(this.tableName,X,Z,_);this.db.prepare(C).run(...J);for(let E of this.meta.subTables){this.db.prepare(`DELETE FROM "${E.tableName}" WHERE "_owner_id" = ?`).run(Z);let T=H[E.fieldName];if(!globalThis.Array.isArray(T)||T.length===0)continue;let k=i(Z,T,E);for(let v of k){let{sql:d,params:l}=u(E.tableName,v);this.db.prepare(d).run(...l)}}});let K=this._wrap(this._record(G));return this._emit("update",{id:Z,data:{...A}}),K})}deleteById(A){return x("repository.deleteById",{table:this.tableName},()=>{let $=this.descriptor.primaryKey.name,X=this.db.transaction(()=>{for(let Y of this.meta.subTables)this.db.prepare(`DELETE FROM "${Y.tableName}" WHERE "_owner_id" = ?`).run(A);return this.db.prepare(`DELETE FROM "${this.tableName}" WHERE "${$}" = ?`).run(A).changes>0});return this._emit("delete",{id:A}),X})}deleteWhere(A){return x("repository.deleteWhere",{table:this.tableName},()=>{let{sql:$,params:X}=r(A),Z=this.descriptor.primaryKey.name,Y=this.db.transaction(()=>{for(let Q of this.meta.subTables){let _=`DELETE FROM "${Q.tableName}" WHERE "_owner_id" IN (SELECT "${Z}" FROM "${this.tableName}" ${$})`.trim();this.db.prepare(_).run(...X)}let G=`DELETE FROM "${this.tableName}" ${$}`.trim();return this.db.prepare(G).run(...X).changes});return this._emit("deleteWhere",{where:A,result:Y}),Y})}flush(){x("repository.flush",{table:this.tableName},()=>{this.db.exec(`DELETE FROM "${this.tableName}"`);for(let A of this.meta.subTables)this.db.exec(`DELETE FROM "${A.tableName}"`);this._emit("flush",{})})}drop(){for(let A of this.meta.subTables)this.db.exec(`DROP TABLE IF EXISTS "${A.tableName}"`);this.db.exec(`DROP TABLE IF EXISTS "${this.tableName}"`)}_hydrateOne(A,$){let X=new Map,Z=this.descriptor.primaryKey.name,Y=A[Z];for(let G of this.meta.subTables){if($&&!$.includes(G.fieldName)){X.set(G.tableName,[]);continue}let Q=this.db.prepare(`SELECT * FROM "${G.tableName}" WHERE "_owner_id" = ? ORDER BY "_index" ASC`).all(Y).map((_)=>{let{_id:K,_owner_id:C,_index:J,...E}=_;return E});X.set(G.tableName,Q)}return jA(A,this.meta,X)}raw(A,...$){return this.db.prepare(A).all(...$)}}class TA{tables;relations=[];constructor(A){this.tables=A}from(A){let $=A;return{scalar:(X)=>({to:(Z,Y,G)=>{let H={ownerTable:$,ownerField:X,targetTable:Z,targetField:Y,kind:"scalar",as:G?.as};return this.relations.push(H),H}}),subTable:(X,Z)=>({to:(Y,G,H)=>{let Q={ownerTable:$,ownerField:`${X}.${Z}`,targetTable:Y,targetField:G,kind:"subTable",as:H?.as};return this.relations.push(Q),Q}})}}build(){return this.relations}}function WA(A){return new TA(A)}import{Type as j}from"typebox";import n from"typebox/schema";var J$=j.Object({key:j.String(),value:j.String(),encoding:j.String(),updatedAt:j.Integer()}),qA=n.Compile(J$),Q$=j.String(),gA=j.Record(j.String(),j.Unknown()),W$=j.Array(j.String()),z$=j.Array(j.Object({ownerTable:j.String(),ownerField:j.String(),targetTable:j.String(),targetField:j.String(),kind:j.Union([j.Literal("scalar"),j.Literal("subTable")]),as:j.Optional(j.String())})),U$=j.String(),LX=n.Compile(Q$),IA=n.Compile(gA),RA=n.Compile(W$),xA=n.Compile(z$),MX=n.Compile(U$),F$="plain",NA="json",SA="deflate-base64";class N{db;static KEY_SCHEMA_HASH="schemaHash";static KEY_SCHEMA_JSON="schemaJSON";static KEY_TABLES="tables";static KEY_RELATIONS="relations";static KEY_VERSION="version";constructor(A){this.db=A,this.db.exec(`
|
|
9
|
+
CREATE TABLE IF NOT EXISTS _foxdb_meta (
|
|
10
|
+
key TEXT PRIMARY KEY,
|
|
11
|
+
value TEXT NOT NULL,
|
|
12
|
+
encoding TEXT NOT NULL,
|
|
13
|
+
updatedAt INTEGER NOT NULL
|
|
14
|
+
)
|
|
15
|
+
`)}getRow(A){let X=this.db.prepare("SELECT key, value, encoding, updatedAt FROM _foxdb_meta WHERE key = ?").get(A);if(X==null)return null;try{return qA.Parse(X)}catch{let[,Z]=qA.Errors(X);throw Error(`MetaStore: row validation failed for key "${A}". Errors: ${JSON.stringify(Z)}`)}}setRow(A,$,X){this.db.prepare(`
|
|
16
|
+
INSERT INTO _foxdb_meta (key, value, encoding, updatedAt)
|
|
17
|
+
VALUES (?, ?, ?, ?)
|
|
18
|
+
ON CONFLICT (key) DO UPDATE SET
|
|
19
|
+
value = excluded.value,
|
|
20
|
+
encoding = excluded.encoding,
|
|
21
|
+
updatedAt = excluded.updatedAt
|
|
22
|
+
`).run(A,$,X,Date.now())}getValidatedJSON(A,$){let X=this.getRow(A);if(X==null)return null;let Z=JSON.parse(X.value);try{return $.Parse(Z)}catch{let[,Y]=$.Errors(Z);throw Error(`MetaStore: JSON validation failed for key "${A}". Errors: ${JSON.stringify(Y)}`)}}setValidatedJSON(A,$,X){try{$.Parse(X)}catch{let[,Z]=$.Errors(X);throw Error(`MetaStore: JSON validation failed for key "${A}" before write. Errors: ${JSON.stringify(Z)}`)}this.setRow(A,JSON.stringify(X),NA)}getString(A){let $=this.getRow(A);if($==null)return null;return $.value}setString(A,$){this.setRow(A,$,F$)}getJSON(A){let $=this.getRow(A);if($==null)return null;try{return JSON.parse($.value)}catch{return null}}setJSON(A,$){this.setRow(A,JSON.stringify($),NA)}getCompressed(A){let $=this.getRow(A);if($==null)return null;if($.encoding!==SA)return null;let X=Uint8Array.fromBase64($.value);return Bun.inflateSync(X)}setCompressed(A,$){let X=new Uint8Array($),Y=Bun.deflateSync(X).toBase64();this.setRow(A,Y,SA)}delete(A){this.db.prepare("DELETE FROM _foxdb_meta WHERE key = ?").run(A)}getSchemaHash(){return this.getString(N.KEY_SCHEMA_HASH)}setSchemaHash(A){this.setString(N.KEY_SCHEMA_HASH,A)}getSchemaJSON(){return this.getValidatedJSON(N.KEY_SCHEMA_JSON,IA)}setSchemaJSON(A){this.setValidatedJSON(N.KEY_SCHEMA_JSON,IA,A)}getTables(){return this.getValidatedJSON(N.KEY_TABLES,RA)}setTables(A){this.setValidatedJSON(N.KEY_TABLES,RA,A)}getRelations(){return this.getValidatedJSON(N.KEY_RELATIONS,xA)}setRelations(A){this.setValidatedJSON(N.KEY_RELATIONS,xA,A)}getVersion(){return this.getString(N.KEY_VERSION)}setVersion(A){this.setString(N.KEY_VERSION,A)}}function _$(A){return A.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '_foxdb_%' ORDER BY name").all().map((Z)=>Z.name)}function K$(A,$){return A.prepare(`SELECT name, "unique" AS "unique" FROM sqlite_master WHERE type = 'index' AND tbl_name = ? AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlite_autoindex_%'`).all($)}function B$(A,$){return A.prepare(`PRAGMA index_info("${$}")`).all().map((Y)=>Y.name).filter((Y)=>Y!=null)}function kA(A,$){let Z=A.prepare(`PRAGMA table_info("${$}")`).all(),Y=[];for(let G of K$(A,$)){let H=B$(A,G.name);Y.push({name:G.name,unique:G.unique,columns:H})}return{name:$,columns:Z,indexes:Y}}function zA(A){return _$(A).map((X)=>kA(A,X))}function E$(A){return A.toUpperCase().trim()}function wA(A){let $=E$(A);if($.includes("INT"))return"INTEGER";if($.includes("CHAR")||$.includes("CLOB")||$.includes("TEXT"))return"TEXT";if($.includes("BLOB"))return"BLOB";if($.includes("REAL")||$.includes("FLOA")||$.includes("DOUB"))return"REAL";return"NUMERIC"}function V$(A){return A==="_id"||A==="_owner_id"||A==="_index"}function L$(A,$){return A.columns.find((X)=>X.name===$)}function M$(A,$,X){let Z=[...$].sort().join(",");return A.indexes.find((Y)=>{if(Boolean(Y.unique)!==X)return!1;return[...Y.columns].sort().join(",")===Z})}function P$(A){return A.columns.filter(($)=>$.pk>0).sort(($,X)=>$.pk-X.pk).map(($)=>$.name)}function UA(A,$){let X=[],Z=[],Y=new Map($.map((H)=>[H.name,H]));for(let H of A){let Q=Y.get(H.name);if(!Q){if(H.name.includes("__"))X.push({kind:"add-subtable",table:H.name.split("__")[0],subTable:{fieldName:H.name.split("__")[1],tableName:H.name,columns:H.columns.map((J)=>({name:J.name,sqlType:J.sqlType,nullable:J.nullable,optional:J.optional}))}});else X.push({kind:"add-table",table:H.name});continue}for(let J of H.columns){let E=L$(Q,J.name);if(!E){if(J.nullable)X.push({kind:"add-column",table:H.name,column:{name:J.name,sqlType:J.sqlType,nullable:J.nullable,optional:J.optional},hasDefault:!1});else Z.push({kind:"add-column",table:H.name,column:{name:J.name,sqlType:J.sqlType,nullable:J.nullable,optional:J.optional},hasDefault:!1});continue}if(wA(J.sqlType)!==wA(E.type))Z.push({kind:"change-type",table:H.name,column:J.name,from:E.type,to:J.sqlType});let T=!J.nullable,k=E.notnull===1;if(T!==k)if(k&&!T)X.push({kind:"change-nullable",table:H.name,column:J.name,to:!0});else Z.push({kind:"change-nullable",table:H.name,column:J.name,to:!1})}for(let J of Q.columns){if(V$(J.name))continue;if(!H.columns.find((E)=>E.name===J.name))Z.push({kind:"drop-column",table:H.name,column:J.name})}let _=P$(Q),K=H.primaryKey.split(",").map((J)=>J.trim());if(_.length!==K.length||!_.every((J,E)=>J===K[E]))Z.push({kind:"change-pk",table:H.name});let C=Q.indexes.filter((J)=>!J.name.startsWith("sqlite_")&&!J.name.startsWith("idx_sqlite_"));for(let J of H.indexes)if(!M$(Q,J.columns,J.unique??!1))X.push({kind:"add-index",table:H.name,index:{name:J.name??`idx_${H.name}__${J.columns.join("_")}`,unique:J.unique?1:0,columns:J.columns}});for(let J of C)if(!H.indexes.some((T)=>{let k=[...T.columns].sort().join(","),v=[...J.columns].sort().join(",");return k===v&&Boolean(T.unique)===Boolean(J.unique)}))Z.push({kind:"drop-index",table:H.name,index:{name:J.name,unique:J.unique,columns:J.columns}})}let G=new Set(A.map((H)=>H.name));for(let H of $)if(!G.has(H.name))Z.push({kind:"drop-table",table:H.name});return{safe:X,unsafe:Z}}function _A(A,$){return A.find((X)=>X.name===$)}function C$(A){let $=A.columns.map((X)=>{let Z=!X.nullable?" NOT NULL":"",Y=X.name===A.primaryKey?" PRIMARY KEY":"";return` "${X.name}" ${X.sqlType}${Y}${Z}`});return`CREATE TABLE IF NOT EXISTS "${A.name}" (
|
|
23
|
+
${$.join(`,
|
|
24
|
+
`)}
|
|
25
|
+
)`}function j$(A,$){let X=!$.nullable?" NOT NULL":"";return`ALTER TABLE "${A}" ADD COLUMN "${$.name}" ${$.sqlType}${X}`}function D$(A,$){let X=$.unique?"UNIQUE ":"",Z=$.columns.map((Y)=>`"${Y}"`).join(", ");return`CREATE ${X}INDEX IF NOT EXISTS "${$.name}" ON "${A}" (${Z})`}function O$(A,$){let X=`${$.name}_foxdb_temp`,Z=$.columns.map((Y)=>{let G=!Y.nullable?" NOT NULL":"",H=Y.name===$.primaryKey?" PRIMARY KEY":"";return` "${Y.name}" ${Y.sqlType}${H}${G}`});A.transaction(()=>{A.exec(`CREATE TABLE "${X}" (
|
|
26
|
+
${Z.join(`,
|
|
27
|
+
`)}
|
|
28
|
+
)`);let Y=$.columns.map((G)=>`"${G.name}"`).join(", ");A.exec(`INSERT INTO "${X}" (${Y}) SELECT ${Y} FROM "${$.name}"`),A.exec(`DROP TABLE "${$.name}"`),A.exec(`ALTER TABLE "${X}" RENAME TO "${$.name}"`)})}function T$(A,$,X){let{table:Z,subTable:Y}=X,G=_A($,Z);if(!G)throw Error(`foxdb sync: cannot find owner table "${Z}" for sub-table "${Y.tableName}"`);let _=[' "_id" INTEGER PRIMARY KEY AUTOINCREMENT',` "_owner_id" ${G.columns.find((K)=>K.name===G.primaryKey)?.sqlType??"TEXT"} NOT NULL`,' "_index" INTEGER NOT NULL',...Y.columns.map((K)=>{let C=!K.nullable?" NOT NULL":"";return` "${K.name}" ${K.sqlType}${C}`})];A.transaction(()=>{A.exec(`CREATE TABLE IF NOT EXISTS "${Y.tableName}" (
|
|
29
|
+
${_.join(`,
|
|
30
|
+
`)}
|
|
31
|
+
)`),A.exec(`CREATE INDEX IF NOT EXISTS "idx_${Y.tableName}__owner" ON "${Y.tableName}" ("_owner_id")`)})}function FA(A,$,X){for(let Z of A.safe)switch(Z.kind){case"add-table":{let Y=_A(X,Z.table);if(!Y)throw Error(`foxdb sync: missing desired schema for table "${Z.table}"`);$.exec(C$(Y));break}case"add-subtable":{T$($,X,Z);break}case"add-column":{if(!Z.column.nullable)throw Error(`foxdb sync: cannot auto-apply required column "${Z.column.name}" without default. Use a migration.`);$.exec(j$(Z.table,Z.column));break}case"add-index":{$.exec(D$(Z.table,Z.index));break}case"change-nullable":{if(!Z.to)throw Error(`foxdb sync: cannot auto-apply nullable \u2192 NOT NULL change on "${Z.table}.${Z.column}". Use a migration.`);let Y=_A(X,Z.table);if(!Y)throw Error(`foxdb sync: missing desired schema for table "${Z.table}"`);O$($,Y);break}case"drop-index":{$.exec(`DROP INDEX IF EXISTS "${Z.index.name}"`);break}}}function q$(A,$,X){if(A.unsafe.length===0&&A.safe.length===0)return!0;if(X==="ignore")return!0;if(X==="warn"){if(A.unsafe.length>0){console.warn(`[foxdb] ${A.unsafe.length} unsafe schema change(s) detected:`);for(let Z of A.unsafe)console.warn(` - ${Z.kind}: ${JSON.stringify(Z)}`)}return!0}if(X==="error"){if(A.unsafe.length>0||A.safe.length>0)throw Error(`foxdb sync: schema drift detected. Safe=${A.safe.length}, Unsafe=${A.unsafe.length}`);return!0}if(X==="auto")return!0;if(typeof X==="function")return X(A,$)!==!1;return!0}function KA(A,$,X,Z){if(A.safe.length===0&&A.unsafe.length===0)return;if(!q$(A,$,X))return;if(X==="auto"){if(FA(A,$,Z),A.unsafe.length>0)throw Error(`foxdb sync: ${A.unsafe.length} unsafe change(s) cannot be auto-applied. Use migrations.
|
|
32
|
+
`+A.unsafe.map((G)=>` - ${G.kind}: ${JSON.stringify(G)}`).join(`
|
|
33
|
+
`));return}if(X==="ignore")return;if(X==="warn"||X==="error"){if(A.unsafe.length===0)FA(A,$,Z);return}if(typeof X==="function"){if(A.unsafe.length===0)FA(A,$,Z);return}}import{readdirSync as I$,existsSync as R$}from"fs";import{join as x$,resolve as N$}from"path";function S$(A){A.exec(`
|
|
34
|
+
CREATE TABLE IF NOT EXISTS "_foxdb_migrations" (
|
|
35
|
+
"name" TEXT PRIMARY KEY,
|
|
36
|
+
"appliedAt" INTEGER NOT NULL
|
|
37
|
+
)
|
|
38
|
+
`)}function g$(A){let X=A.prepare('SELECT "name" FROM "_foxdb_migrations"').all();return new Set(X.map((Z)=>Z.name))}function k$(A,$){A.prepare('INSERT INTO "_foxdb_migrations" ("name", "appliedAt") VALUES (?, ?)').run($,Date.now())}function w$(A){if(!R$(A))return[];return I$(A,{withFileTypes:!0}).filter((Z)=>Z.isFile()&&Z.name.endsWith(".ts")).map((Z)=>({name:Z.name.slice(0,-3),path:N$(x$(A,Z.name))})).sort((Z,Y)=>Z.name.localeCompare(Y.name))}async function e(A){let $=new f({path:A.path});try{S$($);let X=g$($),Y=w$(A.migrationsDir).filter((G)=>!X.has(G.name));if(Y.length===0)return;for(let G of Y){if(A.target&&G.name>A.target)break;let Q=(await import(G.path)).default;if(!Q)throw Error(`foxdb migrate: file "${G.path}" does not export a default Migration`);if(typeof Q.up!=="function")throw Error(`foxdb migrate: migration "${Q.name}" is missing an up() function`);$.transaction(()=>{Q.up($),k$($,G.name)})}}finally{$.close()}}class AA{listeners=new Map;tableActive=new Set;has(A){let $=this.listeners.get(A);return $!==void 0&&$.size>0}hasAny(A){return this.tableActive.has(A)}on(A,$){if(!this.listeners.has(A))this.listeners.set(A,new Set);this.listeners.get(A).add($);let X=A.split(".")[0];if(X&&X!=="*")this.tableActive.add(X);return()=>{let Z=this.listeners.get(A);if(Z){if(Z.delete($),Z.size===0)this.listeners.delete(A)}}}emit(A,$){let X=this.listeners.get(A);if(X)for(let Y of X)try{Y($)}catch(G){console.error(`[foxdb] event listener error for "${A}":`,G)}let Z=A.indexOf(".");if(Z>0){let G=`${A.slice(0,Z)}.*`,H=this.listeners.get(G);if(H)for(let Q of H)try{Q($)}catch(_){console.error(`[foxdb] event listener error for "${G}":`,_)}}}emitIf(A,$){let X=A.indexOf("."),Z=X>0&&this.has(`${A.slice(0,X)}.*`);if(this.has(A)||Z)this.emit(A,$)}}function v$(A){return typeof A==="object"&&A!==null&&"then"in A&&typeof A.then==="function"}function $A(A,$,X){for(let Z of A)try{let Y=Z($);if(Y&&v$(Y))Y.catch((G)=>{console.error(`[foxdb] async ${X} hook error:`,G)})}catch(Y){console.error(`[foxdb] ${X} hook error:`,Y)}}class XA{startHooks=[];readyHooks=[];shutdownHooks=[];exitHooks=[];_ready=!1;_shutdown=!1;get isReady(){return this._ready}get isShutdown(){return this._shutdown}onStart(A){this.startHooks.push(A)}onReady(A){this.readyHooks.push(A)}onShutdown(A){this.shutdownHooks.push(A)}onExit(A){this.exitHooks.push(A)}runStart(A){$A(this.startHooks,A,"onStart")}runReady(A){$A(this.readyHooks,A,"onReady"),this._ready=!0}runShutdown(A){if(this._shutdown)return;this._shutdown=!0,$A(this.shutdownHooks,A,"onShutdown")}runExit(A){$A(this.exitHooks,A,"onExit")}}function y$(A){let $=A.path??":memory:";if(A.rebuildOnLaunch&&$!==":memory:"&&$.length>0)o($);let X=new f(A),Z,Y=new AA;try{let BA=function(W,F){let L=K.filter((U)=>U.ownerTable===W);if(L.length===0)return F;let z={};for(let[U,B]of Object.entries(F))z[U]=B;let D=L.filter((U)=>U.kind==="scalar");if(D.length>0){let U=new Proxy({},{get(B,V){let M=D.find((P)=>P.as===V||P.ownerField===V);if(!M)return;let I=H.get(M.targetTable);if(!I)return null;let q=F[M.ownerField];if(q==null)return null;return I.raw(`SELECT * FROM "${M.targetTable}" WHERE "${M.targetField}" = ? LIMIT 1`,q)[0]??null}});Object.defineProperty(z,"related",{value:U,writable:!1,enumerable:!1,configurable:!1});for(let B of D)if(B.as)Object.defineProperty(z,B.as,{get(){return z.related[B.as]},enumerable:!1,configurable:!1})}let S=L.filter((U)=>U.kind==="subTable");for(let U of S){let[B,V]=U.ownerField.split("."),M=z[B];if(!globalThis.Array.isArray(M))continue;let I=H.get(U.targetTable);if(!I)continue;let q=M.map((P)=>P[V]).filter((P)=>P!=null),y=new Map;if(q.length>0){let P=q.map(()=>"?").join(", "),R=I.raw(`SELECT * FROM "${U.targetTable}" WHERE "${U.targetField}" IN (${P})`,...q);y=new Map(R.map((g)=>[g[U.targetField],g]))}z[B]=M.map((P)=>{let R=y.get(P[V])??null,g=Object.create(null);Object.assign(g,P);let w=new Proxy({},{get(ZA,h){if(h===U.as||h===U.ownerField)return R;return}});if(Object.defineProperty(g,"related",{value:w,writable:!1,enumerable:!1,configurable:!1}),U.as)Object.defineProperty(g,U.as,{value:R,writable:!1,enumerable:!1,configurable:!1});return g})}return z},EA=function(W,F){if(F.length===0)return[];let L=K.filter((U)=>U.ownerTable===W);if(L.length===0)return F;let z=F.map((U)=>{let B=Object.getPrototypeOf(U),V=B?Object.create(B):{};return Object.assign(V,U),V}),D=L.filter((U)=>U.kind==="scalar"),S=L.filter((U)=>U.kind==="subTable");for(let U of D){let B=H.get(U.targetTable);if(!B)continue;let V=U.ownerField,M=[...new Set(z.map((P)=>P[V]).filter((P)=>P!==null&&P!==void 0))];if(M.length===0)continue;let I=M.map(()=>"?").join(", "),q=B.raw(`SELECT * FROM "${U.targetTable}" WHERE "${U.targetField}" IN (${I})`,...M),y=new Map(q.map((P)=>[P[U.targetField],P]));for(let P of z){let R=y.get(P[V]);if(R)Object.defineProperty(P,`_${V}_resolved`,{value:R,writable:!1,enumerable:!1,configurable:!1})}}for(let U of S){let B=H.get(U.targetTable);if(!B)continue;let[V,M]=U.ownerField.split("."),I=[...new Set(z.flatMap((R)=>{let g=R[V];if(!globalThis.Array.isArray(g))return[];return g.map((w)=>w[M]).filter((w)=>w!==null&&w!==void 0)}))];if(I.length===0)continue;let q=I.map(()=>"?").join(", "),y=B.raw(`SELECT * FROM "${U.targetTable}" WHERE "${U.targetField}" IN (${q})`,...I),P=new Map(y.map((R)=>[R[U.targetField],R]));for(let R of z){let g=R[V];if(!globalThis.Array.isArray(g))continue;R[V]=g.map((w)=>{let ZA=P.get(w[M])??null,h=Object.create(null);Object.assign(h,w);let mA=new Proxy({},{get(a$,VA){if(VA===U.as||VA===U.ownerField)return ZA;return}});if(Object.defineProperty(h,"related",{value:mA,writable:!1,enumerable:!1,configurable:!1}),U.as)Object.defineProperty(h,U.as,{value:ZA,writable:!1,enumerable:!1,configurable:!1});return h})}}if(D.length>0)for(let U of z){let B=new Proxy({},{get(V,M){let I=D.find((q)=>q.as===M||q.ownerField===M);if(!I)return;return U[`_${I.ownerField}_resolved`]??null}});Object.defineProperty(U,"related",{value:B,writable:!1,enumerable:!1,configurable:!1});for(let V of D)if(V.as)Object.defineProperty(U,V.as,{get(){return U[`_${V.ownerField}_resolved`]??null},enumerable:!1,configurable:!1})}return z},yA=function(W){for(let F of H.values())F.flush();if(W?.includeMeta)for(let F of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])J.delete(F)},bA=function(){if(Q.runShutdown(_),A.flushOnExit)for(let F of A.flushOnExit)H.get(F)?.flush();if(A.dropOnExit)for(let F of A.dropOnExit)H.get(F)?.drop();if(A.flushMetaOnExit)for(let F of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])J.delete(F);X.close(),Q.runExit(_),Y.emit("exit",{phase:"exit",timestamp:Date.now()});let W=A.unlinkDbFilesOnExit;if(W===!0||W==="onlyGraceful")o($)},G=Object.entries(A.tables);if(G.length===0)O("NO_TABLES","foxdb: at least one table must be defined in `tables`");let H=new Map;for(let[W,F]of G){let L=m(W,F.schema),z=new Set(L.columns.map((U)=>U.name)),D=F.primaryKey.name;if(!z.has(D))O("INVALID_PK",`foxdb: primary key "${D}" is not a scalar column in table "${W}"`,{table:W,column:D});for(let U of F.indexes??[])for(let B of U.columns)if(!z.has(B.name))O("INVALID_INDEX",`foxdb: index column "${B.name}" not found in table "${W}"`,{table:W,column:B.name});let S=new a(W,F,X);H.set(W,S)}for(let[W,F]of H)F.setEventBus(Y);let Q=new XA;if(A.onStart)Q.onStart(A.onStart);if(A.onReady)Q.onReady(A.onReady);if(A.onShutdown)Q.onShutdown(A.onShutdown);if(A.onExit)Q.onExit(A.onExit);let _,K=[];if(typeof A.relations==="function"){let W=WA(A.tables),F=A.relations(W);for(let L of F)K.push(L)}else for(let[W,F]of Object.entries(A.relations??{})){if(!F)continue;let L=H.get(W);if(!L)O("INVALID_RELATION",`foxdb: relation owner table "${W}" not found in tables`,{table:W});for(let z of F){let D=H.get(z.targetTableName);if(!D)O("INVALID_RELATION",`foxdb: relation target table "${z.targetTableName}" not found in tables`,{table:z.targetTableName});let S=z.ownerField.split(".");if(S.length===1){let[B=""]=S;if(!new Set(L.meta.columns.map((M)=>M.name)).has(B))O("INVALID_RELATION",`foxdb: relation ownerField "${z.ownerField}" is not a scalar column in table "${W}"`,{table:W,field:z.ownerField})}else if(S.length===2){let[B="",V=""]=S,M=L.meta.subTables.find((q)=>q.fieldName===B);if(!M)O("INVALID_RELATION",`foxdb: relation ownerField "${z.ownerField}" references unknown sub-table "${B}" in table "${W}"`,{table:W,field:z.ownerField});if(!new Set(M.columns.map((q)=>q.name)).has(V))O("INVALID_RELATION",`foxdb: relation ownerField "${z.ownerField}" references unknown column "${V}" in sub-table "${B}" of table "${W}"`,{table:W,field:z.ownerField})}else O("INVALID_RELATION",`foxdb: relation ownerField "${z.ownerField}" has too many dot segments (max 2 allowed)`,{table:W,field:z.ownerField});if(!new Set(D.meta.columns.map((B)=>B.name)).has(z.targetField))O("INVALID_RELATION",`foxdb: relation targetField "${z.targetField}" is not a scalar column in table "${z.targetTableName}"`,{table:z.targetTableName,field:z.targetField});K.push({ownerTable:W,ownerField:z.ownerField,targetTable:z.targetTableName,targetField:z.targetField,kind:S.length===1?"scalar":"subTable",as:void 0})}}let C=[];for(let[W,F]of G){let L=m(W,F.schema);C.push({name:W,columns:L.columns,indexes:(F.indexes??[]).map((z)=>({name:z.name,columns:z.columns.map((D)=>D.name),unique:z.unique})),primaryKey:F.primaryKey.name});for(let z of L.subTables)C.push({name:z.tableName,columns:z.columns,indexes:(F.subTables?.[z.fieldName]?.indexes??[]).map((D)=>({name:D.name,columns:D.columns.map((S)=>S.name),unique:D.unique})),primaryKey:"_id"})}let J=new N(X),E=Object.fromEntries(G.map(([W,F])=>[W,F.schema])),T=JSON.stringify(E),k=Bun.hash(T),v=new TextEncoder().encode(T),d=J.getString("_schema_hash"),l=String(k);if(d!==l&&A.sync&&A.sync!=="ignore"){let W=zA(X),F=UA(C,W);KA(F,X,A.sync,C)}J.setString("_schema_hash",l),J.setCompressed("_schema_compressed",v),J.setJSON("_tables",Object.keys(A.tables)),J.setJSON("_relations",K),J.setString("_foxdb_version","0.0.2");let hA={get schemaHash(){return J.getString("_schema_hash")},get schemaJSON(){let W=J.getCompressed("_schema_compressed");return W?new TextDecoder().decode(W):null},get tables(){return J.getJSON("_tables")},get relations(){return J.getJSON("_relations")},get version(){return J.getString("_foxdb_version")}};for(let[W,F]of H){if(K.filter((z)=>z.ownerTable===W).length===0)continue;F.setMaterializer((z)=>BA(W,z),(z)=>EA(W,z))}Z=Object.create(null);for(let W of Object.keys(A.tables))Object.defineProperty(Z,W,{get(){return H.get(W)},enumerable:!0,configurable:!0});let fA=async()=>{if(!A.migrations)O("MIGRATIONS_NOT_CONFIGURED","foxdb: migrations dir not configured. Pass `migrations: { dir: ... }` to createORM().");await e({path:$,migrationsDir:A.migrations.dir})},uA={on(W,F,L){if(typeof F==="string"&&typeof L==="function"){let z=`${W}.${F}`;return Y.on(z,L)}if(typeof F==="function")return Y.on(W,F);O("INVALID_EVENT_LISTENER","foxdb: invalid event listener arguments")}};if(_={orm:Z,db:X,meta:J,tables:Object.keys(A.tables),repos:H,logger:{log:(...W)=>{console.log("[foxdb]",...W)},error:(...W)=>{console.error("[foxdb]",...W)}}},A.unlinkDbFilesOnExit==="any"){let W=()=>{try{o($)}catch{}},F=()=>{Q.runExit(_),W(),process.exit(1)};process.on("exit",W),process.on("SIGINT",F),process.on("SIGTERM",F),process.on("uncaughtException",(L)=>{Y.emit("fail",{phase:"fail",error:L,timestamp:Date.now()}),F()})}if(Object.assign(Z,{_transaction:X.transaction.bind(X),_close:bA,_meta:hA,_materialize:BA,_materializeMany:EA,_flush:yA,_migrate:fA,_events:uA}),Q.runStart(_),A.flushOnStart)for(let W of A.flushOnStart)H.get(W)?.flush();if(A.dropOnStart)for(let W of A.dropOnStart)H.get(W)?.drop();if(A.flushMetaOnStart)for(let W of["_schema_hash","_schema_compressed","_tables","_relations","_foxdb_version"])J.delete(W);if(A.autoMigrate&&A.migrations)e({path:$,migrationsDir:A.migrations.dir}).catch((W)=>{console.error("[foxdb] autoMigrate failed:",W)});if(A.seed)A.seed(Z);Q.runReady(_),Y.emit("ready",{phase:"ready",timestamp:Date.now()})}catch(G){if(G instanceof b)Y.emit("fail",{phase:"fail",error:G,timestamp:Date.now()});else{let H=new b(String(G),{code:"UNEXPECTED",trace:HA()});Y.emit("fail",{phase:"fail",error:H,timestamp:Date.now()})}throw G}return Z}import{IsString as h$,IsNumber as f$,IsInteger as u$,IsBoolean as b$,IsLiteral as m$}from"typebox";function n$(A){return h$(A)||f$(A)||u$(A)||b$(A)||m$(A)}function vA(A){let $={};for(let X of Object.keys(A.properties)){let Z=A.properties[X];if(Z&&n$(Z))$[X]={_tag:"ColumnRef",name:X,schema:Z}}return $}function d$(A,$){let X=vA(A),Z=$(X);return{schema:A,...Z}}import{existsSync as p$,mkdirSync as c$,writeFileSync as i$}from"fs";import{join as l$,resolve as o$}from"path";function s$(A,$){return`import type { Migration } from "@xwxfox/foxdb";
|
|
39
|
+
|
|
40
|
+
export default {
|
|
41
|
+
name: "${A}",
|
|
42
|
+
date: "${$}",
|
|
43
|
+
|
|
44
|
+
up(db) {
|
|
45
|
+
// Your migration logic here
|
|
46
|
+
},
|
|
47
|
+
} satisfies Migration;
|
|
48
|
+
`}function r$(A,$){if(!p$($))c$($,{recursive:!0});let X=new Date,Z=X.getFullYear(),Y=String(X.getMonth()+1).padStart(2,"0"),G=String(X.getDate()).padStart(2,"0"),H=String(X.getHours()).padStart(2,"0"),Q=String(X.getMinutes()).padStart(2,"0"),_=String(X.getSeconds()).padStart(2,"0"),C=`${`${Z}${Y}${G}_${H}${Q}${_}`}_${A}.ts`,J=o$(l$($,C)),E=X.toISOString(),T=s$(A,E);return i$(J,T,"utf-8"),J}export{x as withTrace,d$ as table,QA as resolveTimestampNames,O as raise,e as migrate,m as introspectTable,kA as inspectSchema,zA as inspectAllTables,WA as createRelationBuilder,y$ as createORM,r$ as createMigration,UA as computeDiff,GA as buildCreateTableSQL,KA as applySync,gA as SchemaJSONSchema,a as Repository,b as ORMError,N as MetaStore,XA as LifecycleManager,AA as EventBus,JA as DEFAULT_TIMESTAMP_NAMES,f as BunDatabase};
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xwxfox/foxdb",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "itty bitty e2e typed orm for bun :3",
|
|
5
|
+
"main": "dist/index.mjs",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"types": "dist/index.d.mts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "bunup",
|
|
12
|
+
"docs": "bun run docs.ts",
|
|
13
|
+
"release": "bun run publish.ts"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"orm",
|
|
17
|
+
"typescript",
|
|
18
|
+
"typescript-orm",
|
|
19
|
+
"sqlite",
|
|
20
|
+
"bun:sqlite",
|
|
21
|
+
"bun",
|
|
22
|
+
"bun.js",
|
|
23
|
+
"typebox"
|
|
24
|
+
],
|
|
25
|
+
"tags": [
|
|
26
|
+
"orm",
|
|
27
|
+
"typescript",
|
|
28
|
+
"typescript-orm",
|
|
29
|
+
"sqlite",
|
|
30
|
+
"bun:sqlite",
|
|
31
|
+
"bun",
|
|
32
|
+
"bun.js",
|
|
33
|
+
"typebox"
|
|
34
|
+
],
|
|
35
|
+
"author": "xwxfox",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/xwxfox/foxdb.git"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/xwxfox/foxdb/issues"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"files": [
|
|
45
|
+
"dist/**/*",
|
|
46
|
+
"package.json",
|
|
47
|
+
"README.md",
|
|
48
|
+
"LICENSE.md"
|
|
49
|
+
],
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@catppuccin/vitepress": "^0.1.2",
|
|
52
|
+
"@types/bun": "latest",
|
|
53
|
+
"bunup": "^0.16.31",
|
|
54
|
+
"typedoc": "^0.28.19",
|
|
55
|
+
"typedoc-plugin-coverage": "^4.0.3",
|
|
56
|
+
"typedoc-plugin-extras": "^4.0.1",
|
|
57
|
+
"typedoc-plugin-markdown": "^4.11.0",
|
|
58
|
+
"typedoc-plugin-mdn-links": "^5.1.1",
|
|
59
|
+
"typedoc-plugin-merge-modules": "^7.0.0",
|
|
60
|
+
"typedoc-vitepress-theme": "^1.1.2",
|
|
61
|
+
"typescript": "^5.9.3",
|
|
62
|
+
"vitepress": "^1.6.4"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"typebox": "^1.1.34"
|
|
66
|
+
}
|
|
67
|
+
}
|