@idb-orm/core 1.0.15 → 1.1.0

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.
@@ -12,10 +12,9 @@ export default class PrimaryKey<AutoGenerate extends boolean, KeyType extends Va
12
12
  autoIncrement(): PrimaryKey<true, number>;
13
13
  uuid(): PrimaryKey<true, string>;
14
14
  date(): PrimaryKey<true, Date>;
15
- genKey(): KeyType;
15
+ genKey(...args: unknown[]): KeyType;
16
16
  /**
17
17
  * If the internal objectStore "autoIncrement" utility is being used
18
- * @returns
19
18
  */
20
19
  isAutoIncremented(): boolean;
21
20
  static is(value: object): value is PrimaryKey<any, any>;
@@ -56,7 +56,7 @@ export declare class BaseRelation<To extends string, Name extends string = never
56
56
  * Gets the key on the corresponding model this relation points to
57
57
  */
58
58
  getRelatedKey(): string;
59
- toString(): string;
59
+ tostring(): string;
60
60
  getBaseSymbol(): symbol;
61
61
  static is(value: object): value is BaseRelation<any, any>;
62
62
  }
package/dist/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class e extends Error{code;constructor(e,t){super(`(${e}) ${t}`),this.code=e}}function t(t,n){return class extends e{static code;constructor(e=n){super(t,e)}static of(e){new this(e)}}}const n=t("INVALID_CONFIG","Configuration is invalid"),r=t("INVALID_TX","Transaction is invalid"),s=t("INVALID_ITEM","Item is invalid"),o=t("ASSERTION_FAILED","Assertion failed"),a=t("UNKNOWN","An unknown error occurred"),i=t("DELETE_FAILED","Item could not be deleted"),c=t("NOT_FOUND","Object Store Not Found"),u=t("NOT_FOUND","Document Not Found"),l=t("UPDATE_FAILED","Item could not be updated"),f=t("ADD_FAILED","Item could not be added"),y=t("OPEN_CURSOR","Cursor could not be opened"),d=t("GET_FAILED","Item could not be retrieved"),h=t("OVERWRITE_RELATION","Relation cannot be overwritten"),p=t("EXPORT","Export failed"),w=t("SERIALIZATION_FAILED","Seralization failed"),m=t("DESERIALIZATION_FAILED","De-seralization failed");function g(e,t){return new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function b(e){return Object.keys(e)}function S(e){return Array.isArray(e)||(e=[e]),e}function A(){return crypto.randomUUID()}function v(){return new Date}function $(e){return e}function k(e,t){for(const n of t.keys())e.add(n);return e}var R=(e=>(e[e.string=0]="string",e[e.number=1]="number",e[e.date=2]="date",e[e.boolean=3]="boolean",e[e.symbol=4]="symbol",e[e.bigint=5]="bigint",e[e.file=6]="file",e[e.void=7]="void",e[e.float=8]="float",e[e.int=9]="int",e[e.unknown=10]="unknown",e[e.literal=11]="literal",e[e.array=12]="array",e[e.set=13]="set",e[e.union=14]="union",e[e.optional=15]="optional",e[e.default=16]="default",e[e.object=17]="object",e[e.tuple=18]="tuple",e[e.custom=19]="custom",e))(R||{});const O={};function j(e){const t=O[e];return t||(O[e]={tag:e})}function K(){return j(R.string)}function N(){return j(R.number)}function T(){return j(R.boolean)}function D(){return j(R.bigint)}function M(){return j(R.symbol)}function I(){return j(R.file)}function x(){return j(R.date)}function P(){return j(R.unknown)}function _(e){return{tag:R.literal,value:e}}function F(e){return{tag:R.array,of:e}}function E(e,t){return{tag:R.default,of:e,value:t}}function L(e){return{tag:R.set,of:e}}function C(e){return{tag:R.union,options:e}}function B(e){return{tag:R.optional,of:e}}function V(e){return{tag:R.custom,...e}}const q=Object.freeze(Object.defineProperty({__proto__:null,Array:F,BigInt:D,Boolean:T,Custom:V,Date:x,Default:E,File:I,Float:function(){return j(R.float)},Int:function(){return j(R.int)},Literal:_,Number:N,Object:function(e){return{tag:R.object,props:e}},Optional:B,Set:L,String:K,Symbol:M,Tuple:function(e){return{tag:R.tuple,elements:e}},Union:C,Unknown:P,Void:function(){return j(R.void)},getType:j},Symbol.toStringTag,{value:"Module"}));function z(e){switch(e.tag){case R.void:return"void";case R.literal:return String(e.value);case R.boolean:return"boolean";case R.number:return"number";case R.float:return"float";case R.int:return"integer";case R.bigint:return"bigint";case R.string:return"string";case R.symbol:return"symbol";case R.unknown:return"unknown";case R.date:return"Date";case R.tuple:return`Tuple<${e.elements.map(e=>z(e)).join(", ")}>`;case R.array:return`Array<${z(e.of)}>`;case R.set:return`Set<${z(e.of)}>`;case R.default:case R.optional:return`${z(e.of)} | undefined`;case R.union:return`Union<${e.options.map(e=>z(e)).join(", ")}>`;case R.file:return"File";case R.object:return`{${Object.keys(e.props).map(t=>`${t}: ${z(e.props[t])}`).join(",\n")}}`;case R.custom:return"custom"}}async function U(e,t){if(!W(e,t))throw new w(`Value not of the proper type, expected type '${z(e)}', received '${JSON.stringify(t)}'`);switch(e.tag){case R.literal:case R.boolean:case R.number:case R.float:case R.int:case R.string:return t;case R.void:return;case R.bigint:return Number(t);case R.symbol:return t.description;case R.unknown:return JSON.stringify(t);case R.date:return t.getTime();case R.tuple:{const n=[];for(let r=0;r<t.length;r++)n.push(await U(e.elements[r],t[r]));return n}case R.array:{const n=[];for(const r of t)n.push(U(e.of,r));return await Promise.all(n)}case R.set:{const n=[];for(const r of t.keys())n.push(U(e.of,r));return await Promise.all(n)}case R.optional:if(void 0===t)return;return await U(e.of,t);case R.union:for(const n of e.options)try{return await U(n,t)}catch{}throw new w("Value union could not be serialized");case R.file:if(!(t instanceof File))throw new w("Value is not a valid file");return{data:new Promise((e,n)=>{const r=new FileReader;r.onload=()=>e(r.result),r.onerror=n,r.readAsDataURL(t)}),name:t.name,type:t.type};case R.object:{const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional&&s.tag!==R.default&&s.tag!==R.void)throw new w(`Required property '${r}' not found`);n[r]=await U(s,t[r])}return n}case R.default:return await U(e.of,void 0===t?"function"==typeof e.value?e.value():e.value:t);case R.custom:return e.serialize?await e.serialize(t):JSON.stringify(t)}}async function G(e,t){switch(e.tag){case R.void:return;case R.literal:if(t!==e.value)throw new m(`'${t}' is not equal to literal '${t}'`);return t;case R.boolean:if("boolean"!=typeof t)throw new m(`'${t}' is not a boolean`);return t;case R.int:if("number"!=typeof t||!Number.isInteger(t))throw new m(`'${t}' is not an integer`);return t;case R.float:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a float`);return t;case R.number:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a number`);return t;case R.bigint:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a bigint`);return BigInt(t);case R.string:if("string"!=typeof t)throw new m(`'${t}' is not a string`);return t;case R.symbol:if("string"!=typeof t)throw new m(`'${t}' is not a symbol`);return Symbol.for(t);case R.date:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a date timestamp`);return new Date(t);case R.tuple:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(let r=0;r<t.length;r++)n.push(await G(e.elements[r],t[r]));return n}case R.array:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(G(e.of,r));return await Promise.all(n)}case R.set:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(G(e.of,r));return new Set(await Promise.all(n))}case R.optional:if(void 0===t)return;return G(e.of,t);case R.unknown:return"string"!=typeof t?t:JSON.parse(t);case R.union:for(const n of e.options)try{return await G(n,t)}catch{}throw new m("Value did not match the union");case R.file:{if(!(t&&"object"==typeof t&&"data"in t&&"name"in t&&"type"in t&&"string"==typeof t.data&&"string"==typeof t.name&&"string"==typeof t.type))throw new m("Value is not a valid file schema");const e=Buffer.from(t.data.replace(/^data:.+;base64,/,""),"base64");return new File([e],t.name,{type:t.type})}case R.default:return void 0===t?e.value:G(e.of,t);case R.custom:if(e.isType(t))return e.deserialize?await e.deserialize(t):JSON.parse(String(t));throw new m("Value is not valid");case R.object:{if(!t||"object"!=typeof t)throw new m("Value is not an object");const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional)throw new m(`Required property '${r}' not found`);n[r]=await G(s,t[r])}return n}}}function Y(e,t){if(e.tag!==t.tag)return!1;switch(e.tag){case R.literal:return e.value===t.value;case R.optional:case R.default:case R.set:case R.array:return Y(e.of,t.of);case R.union:if(e.options.length!==t.options.length)return!1;for(let n=0;n<e.options.length;n++)if(!Y(e.options[n],t.options[n]))return!1;return!0;case R.tuple:if(e.elements.length!==t.elements.length)return!1;for(let n=0;n<e.elements.length;n++)if(!Y(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(Object.keys(e.props).length!==Object.keys(t.props).length)return!1;for(const n in e.props){if(!(n in t.props))return!1;if(!Y(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t;default:return!0}}function J(e,t){switch(e.tag){case R.literal:return t.tag===R.literal&&t.value===e.value;case R.number:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===z(e)||t.tag===R.float||t.tag===R.int;case R.boolean:case R.symbol:case R.string:case R.bigint:case R.int:case R.float:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===z(e);case R.unknown:return!0;case R.date:case R.file:case R.void:return t.tag===e.tag;case R.optional:case R.default:case R.set:case R.array:return t.tag===e.tag&&J(e.of,t.of);case R.union:if(t.tag===R.union){for(const n of t.options)if(!J(e,n))return!1;return!0}return e.options.some(e=>J(e,t));case R.tuple:if(t.tag!==R.tuple)return!1;for(let n=0;n<e.elements.length;n++)if(!J(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(t.tag!==R.object)return!1;for(const n in t.props){if(!e.props[n])return!1;if(!J(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t}}function W(e,t){switch(e.tag){case R.void:return void 0===t;case R.literal:return t===e.value;case R.boolean:return"boolean"==typeof t;case R.number:return"number"==typeof t;case R.bigint:return"bigint"==typeof t;case R.string:return"string"==typeof t;case R.symbol:return"symbol"==typeof t;case R.unknown:return!0;case R.float:return"number"==typeof t&&!isNaN(t);case R.int:return"number"==typeof t&&Number.isInteger(t);case R.date:return t instanceof Date&&!isNaN(t.getTime());case R.tuple:return Array.isArray(t)&&t.length===e.elements.length&&t.every((t,n)=>W(e.elements[n],t));case R.array:return Array.isArray(t)&&t.every(t=>W(e.of,t));case R.set:return t instanceof Set&&Array.from(t).every(t=>W(e.of,t));case R.optional:case R.default:return void 0===t||W(e.of,t);case R.union:return e.options.some(e=>W(e,t));case R.file:return t instanceof File;case R.object:return!(!t||"object"!=typeof t)&&Object.keys(e.props).every(n=>W(e.props[n],t[n]));case R.custom:return e.isType(t)}}function H(e,t){if(W(e,t)){switch(e.tag){case R.custom:if(e.parse)try{return{success:!0,data:e.parse(t)}}catch(n){return{success:!1,error:String(n)}}break;case R.default:return void 0===t?{success:!0,data:e.value}:{success:!0,data:t}}return{success:!0,data:t}}return{success:!1,error:`Value is not a valid '${z(e)}'`}}const Q=Object.freeze(Object.defineProperty({__proto__:null,Tag:R,Type:q,deserializeType:G,isExactType:Y,isSubtype:J,isType:W,parseType:H,serializeType:U,typeToString:z},Symbol.toStringTag,{value:"Module"})),X=Symbol.for("primaryKey");class Z{symbol=X;genFn;autoGenerate;type;constructor(e,t){if(e){if(e.tag>R.date)throw new n("Invalid Primary Key Type");this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1}else this.autoGenerate=!1,this.type=N()}getType(){return this.type}generator(e){return this.genFn=e,this.autoGenerate=!0,this}autoIncrement(){if(this.type.tag===R.number)return this.genFn=void 0,this.autoGenerate=!0,this;throw new n("Primary key must be a number to use autoIncrement()")}uuid(){if(!window.isSecureContext)throw new Error("Window is not in a secure context");return new Z(K(),A)}date(){return new Z(x(),v)}genKey(){if(this.genFn)return this.genFn();throw new Error("Generator function not defined")}isAutoIncremented(){return this.autoGenerate&&!this.genFn}static is(e){return e?.symbol===X}static compareKeyValue(e,t){if(typeof e!=typeof t)return!1;switch(typeof e){case"string":case"number":return e===t;case"object":return e.getTime()===t.getTime();default:return!1}}static validKeyTag=C([K(),N(),x()])}class ee{constructor(e,t="",n=!1,r=!1,s){this.to=e,this.name=t,this.isOptional=n,this.isArray=r,this.relatedKey="",this.actions={onDelete:s||"Restrict"}}static SYMBOL=Symbol.for("baseRelation");BASE_SYMBOL=ee.SYMBOL;actions;relatedKey;getActions(){return{...this.actions}}isNullable(){return this.isArray||this.isOptional}setRelatedKey(e){this.relatedKey=e}getRelatedKey(){return this.relatedKey}toString(){return`${this.isArray?"Array":this.isOptional?"Optional":"Standard"} relation from this model to model '${this.to}' on key '${this.relatedKey}'`}getBaseSymbol(){return this.BASE_SYMBOL}static is(e){return"getBaseSymbol"in e&&e.getBaseSymbol()===ee.SYMBOL}}class te extends ee{static R_SYMBOL=Symbol.for("relation");symbol=te.R_SYMBOL;constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new ne(this.to,this.name,e)}optional({onDelete:e}={}){return new re(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}static is(e){return e?.symbol===this.R_SYMBOL}}class ne extends ee{static A_SYMBOL=Symbol.for("arrayRelation");symbol=ne.A_SYMBOL;constructor(e,t,n="None"){super(e,t,!1,!0,n)}static is(e){return e?.symbol===this.A_SYMBOL}}class re extends ee{static O_SYMBOL=Symbol.for("optionalRelation");symbol=re.O_SYMBOL;constructor(e,t,n="None"){super(e,t,!0,!1,n)}static is(e){return e?.symbol===this.O_SYMBOL}}var se=(e=>(e[e.Property=0]="Property",e[e.Relation=1]="Relation",e[e.PrimaryKey=2]="PrimaryKey",e[e.Invalid=3]="Invalid",e))(se||{});const oe=Symbol.for("property");class ae{constructor(e,t){this.type=e,this.options={unique:t?.unique??!1}}symbol=oe;hasDefault=!1;options;unique(){switch(this.type.tag){case R.boolean:case R.string:case R.number:case R.symbol:return this.options.unique=!0,this;default:throw new Error("A non-primitive cannot be a unique value")}}hasDefaultValue(){return this.hasDefault}static relation(e,t){return new te(e,t)}static primaryKey(e="number"){return new Z(this.nameToType(e))}static nameToType(e){switch(e){case"boolean":return T();case"bigint":return D();case"number":return N();case"string":return K();case"symbol":return M();default:return P()}}static is(e){return"object"==typeof e&&e?.symbol===oe}array(){return new ae(F(this.type),this.options)}default(e){return this.hasDefault=!0,new ae(E(this.type,e),this.options)}optional(){return new ae(B(this.type),this.options)}static array(e,t){return new ae(F(e.type),t)}static boolean(e){return new ae(T(),e)}static custom(e,t){return new ae(V({isType:t=>e(t).success,serialize:t?.serialize,deserialize:t?.deserialize}),t)}static date(e){return new ae(x(),e)}static file(e){return new ae(I(),e)}static literal(e,t){return new ae(_(e),t)}static number(e){return new ae(N(),e)}static string(e){return new ae(K(),e)}static set(e,t){return new ae(L(e.type),t)}static union(e,t){return new ae(C(e.map(e=>e.type)),t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const n=[];for(const r of t){const t=e(r);if(!t.success)return t;n.push(t.data)}return{success:!0,data:n}}return{success:!1,error:"Value is not an array"}}}}const ie=Symbol.for("model");class ce{constructor(t,n){this.name=t,this.fields=n,this.fieldKeys=b(n);for(const e of this.fieldKeys){const t=this.fields[e];ee.is(t)&&t.to!==this.name&&this.relationLinks.add(t.to)}const r=this.fieldKeys.find(e=>Z.is(this.fields[e]));if(!r)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=r}symbol=ie;fieldKeys;relationLinks=new Set;cache={};primaryKey;get(e){return this.fields[e]}getPrimaryKey(){return this.fields[this.primaryKey]}defineKeyGen(e){return this.getPrimaryKey().generator(e),this}getRelation(e){const t=this.fields[e];if(t&&ee.is(t))return t}keyType(e){const t=this.fields[e];return t?ae.is(t)?se.Property:ee.is(t)?se.Relation:Z.is(t)?se.PrimaryKey:se.Invalid:se.Invalid}links(){return this.relationLinks.keys()}*relations(){for(const e of this.fieldKeys)ee.is(this.fields[e])&&(yield[e,this.fields[e]])}*entries(){for(const e of this.fieldKeys)yield[e,this.fields[e]]}keys(){return this.fieldKeys}parseField(e,t){return ae.is(this.fields[e])?H(this.fields[e].type,t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=new Set,n=[this.name];let r;for(;n.length>0;){const s=n.shift();if(t.has(s))continue;r=e.getModel(s);const o=r.cache.delete;if(o)k(t,o);else{t.add(s);for(const e of r.links())t.has(e)||n.push(e)}}return this.cache.delete=t,t}static is(e){return e?.symbol===ie}}class ue{constructor(e,t){this.tx=e,this.internal=t}add(e){return this.handleRequest(this.internal.add(e),()=>new f)}get(e){return this.handleRequest(this.internal.get(e),()=>new d)}async assertGet(e){const t=await this.handleRequest(this.internal.get(e),()=>new d);if(!t)throw this.tx.abort(new u);return t}put(e){return this.handleRequest(this.internal.put(e),()=>new l)}delete(e){return this.handleRequest(this.internal.delete(e),()=>new i)}async openCursor(t,n={}){const r=n.onError||(()=>new y),s=this.internal.openCursor(n.query,n.direction);await new Promise((n,o)=>{s.onsuccess=async s=>{try{s.target||o(this.tx.abort(r()));const e=s.target.result;e&&await t(e,this.tx)||n()}catch(i){o(this.tx.abort(i instanceof e?i:new a(String(i))))}},s.onerror=()=>{o(this.tx.abort(r()))}})}handleRequest(e,t){return new Promise(n=>{e.onsuccess=()=>{n(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class le{internal;status;error=null;storeNames;inWrap=!1;onRejection=t=>{throw t instanceof e?this.abort(t):this.abort(new a(String(t)))};objectStores;constructor(e,t,n,r={}){e instanceof le?(this.internal=e.getInternal(),this.storeNames=e.storeNames,this.status=e.status,this.error=e.error,this.objectStores=e.getAllStores()):(this.internal=e.transaction(t,n),this.status=0,this.storeNames=Array.from(this.internal.objectStoreNames),this.objectStores=new Map(this.storeNames.map(e=>[e,this.getObjectstore(e)])),this.internal.onabort=this.registerHandler(1,r.onAbort),this.internal.onerror=this.registerHandler(3,r.onError),this.internal.oncomplete=this.registerHandler(2,r.onComplete))}static create(e,t,n,r){return r||new le(e,t,n)}abort(e){return 1!==this.status&&this.internal.abort(),this.status=1,this.error=e,this.error}commit(){this.internal.commit()}getInternal(){return this.internal}getStore(e){const t=this.objectStores.get(e);if(!t)throw this.abort(new r(`Store '${e}' is not a part of this transaction`));return t}getAllStores(){return this.objectStores}get mode(){return this.internal.mode}is(e){return this.status===e}contains(e){Array.isArray(e)||(e=[e]);for(const t of e)if(!this.internal.objectStoreNames.contains(t))return!1;return!0}assertIsArray(e,t="Value is not an array"){if(!Array.isArray(e))throw this.abort(new o(t))}getObjectstore(e){try{return new ue(this,this.internal.objectStore(e))}catch{throw this.abort(new c(`No ObjectStore with the name '${e}' found`))}}registerHandler(e,t=()=>{}){return n=>{this.status=e,t(this,n)}}async wrap(t){if(this.inWrap)return await t(this);this.inWrap=!0;try{const e=await t(this);return this.inWrap=!1,e}catch(n){throw this.inWrap=!1,n instanceof e?this.abort(n):this.abort(new a(JSON.stringify(n)))}}}function fe(e){if(!e)return[];const t=[];for(const n in e)if(Object.hasOwn(e,n))switch(typeof e[n]){case"function":t.push([n,!0,e[n]]);break;case"object":if(e[n]instanceof Date){const r=e[n];t.push([n,!0,e=>e instanceof Date&&e.getTime()===r.getTime()])}break;default:t.push([n,!1,e[n]])}return t}function ye(e,t){if(!t||"object"!=typeof t)return!1;for(const n of e)if(n[1]){if(!n[2](t[n[0]]))return!1}else if(n[2]!==t[n[0]])return!1;return!0}function de(e,t,n={},r){const o=t.getModel(e);if(n.include&&n.select)throw new s("include and select cannot both be defined");const a=fe(n.where),i=n.select?"select":n.include?"include":"";if(i){const e=n[i],r=!!n.select,s=[];for(const n in e)if(Object.hasOwn(e,n)&&e[n])switch(o.keyType(n)){case se.Relation:{const r=o.getRelation(n),a="object"==typeof e[n]?de(r.to,t,e[n]):$,i=r.getRelatedKey();if(r.isArray){const e=async(e,t)=>{const n=[],s=t.getStore(r.to);for(const r of e){const e=await a(await s.assertGet(r),t);e&&(delete e[i],n.push(e))}return n};s.push({key:n,getValue:e})}else{const e=async(e,t)=>await a(await t.getStore(r.to).assertGet(e),t);s.push({key:n,getValue:e})}break}case se.Property:case se.PrimaryKey:r&&s.push({key:n})}return r?async(e,t)=>{if(!ye(a,e))return;const n={};for(const{key:r,getValue:o}of s)n[r]=o?await o(e[r],t):e[r];return n}:async(e,t)=>{if(ye(a,e)){for(const{key:n,getValue:r}of s)e[n]=await r(e[n],t);return e}}}return e=>ye(a,e)?e:void 0}function he(e,t,n,r){const s=new Set([e]);if(n){const o=r.getModel(e);for(const e in t){const a=o.getRelation(e),i=S(t[e]);if(a)for(const e of i)if(e&&"object"==typeof e)for(const t in e)if(Object.hasOwn(e,t))switch(t){case"$connect":case"$connectMany":case"$disconnect":case"$disconnectMany":case"$disconnectAll":s.add(a.to);break;case"$delete":case"$deleteMany":case"$deleteAll":k(s,o.getDeletedStores(r));break;case"$create":k(s,he(a.to,e[t],n,r));break;case"$createMany":e[t].forEach(e=>k(s,he(a.to,e,n,r)));break;case"$update":k(s,he(a.to,e[t].data,n,r));break;case"$updateMany":e[t].forEach(e=>k(s,he(a.to,e.data,n,r)))}}}else{const n=r.getModel(e);for(const e in t){const o=n.getRelation(e);if(o)switch(typeof t[e]){case"object":k(s,he(o.to,pe(t[e]),!1,r));break;case"boolean":s.add(o.to)}}}return s}function pe(e){return e.select?e.select:e.include?e.include:{}}class we{constructor(e,t,n){this.client=e,this.name=t,this.accessedStores=Array.from(he(t,pe(n),!1,this.client)),this.selectClause=de(t,this.client,n)}accessedStores;selectClause;async find(){return await this._find(!1)}async findFirst(){return(await this._find(!0))[0]}async _find(e){const t=this.client.createTransaction("readonly",this.accessedStores);return await t.wrap(async t=>{const n=[],r=t.getStore(this.name);return await r.openCursor(async r=>{const s=await this.selectClause(r.value,t);return s&&n.push(s),(!e||!n.length)&&(r.continue(),!0)}),n})}}function me(e,t,r){return async s=>{if(!s)return!1;const o=s[e.primaryKey];for(const[a,c]of e.relations()){const{onDelete:u}=c.getActions(),l=s[a],f=t.getModel(c.to);switch(u){case"Cascade":if(c.isArray){r.assertIsArray(l);const e=new Set(l),n=me(f,t,r),s=r.getStore(c.to);await s.openCursor(async t=>(e.has(t.value[f.primaryKey])&&await n(t.value),t.continue(),!0)).catch(r.onRejection)}else l&&await ge(c.to,t,void 0,void 0,{tx:r,singleton:{id:l}});break;case"SetNull":{if(!l)break;const e=S(l),t=r.getStore(c.to),s=c.getRelatedKey(),a=f.getRelation(s);if(!a)throw new n(`Relation '${c.name}' has an invalid relation key '${c.getRelatedKey()}'`);if(!a.isNullable())throw new n(`Key '${s}' on model '${s}': Non-optional relation cannot have the 'SetNull' action`);for(const n of e){const e=await t.get(n);if(!e)continue;const i=e[s];if(a.isArray){r.assertIsArray(i);const e=i.indexOf(o);if(-1===e)continue;i.splice(e,1)}else e[s]=null;await t.put(e)}break}case"Restrict":if(Array.isArray(l)&&l.length>0||l)throw new i(`Key '${a}' on model '${e.name}' deletion is restricted while there is an active relation`)}}return!0}}async function ge(e,t,n,r=!1,s={}){const{singleton:o,finalStep:a=!0}=s,i=t.getModel(e),c=s.tx?s.tx.storeNames:Array.from(i.getDeletedStores(t)),u=le.create(t.getDb(),c,"readwrite",s.tx);return await u.wrap(async s=>{const c=s.getStore(e);let u=0;const l=me(i,t,s);if(o)await l(await c.assertGet(o.id))&&(await c.delete(o.id),u++);else{const e=fe(n);let t;await c.openCursor(async n=>{const o=n.value;return ye(e,o)&&await l(o)&&(t=g(n.delete()).catch(s.onRejection)),!(r&&u>0)&&(n.continue(),!0)}),t&&a&&await t}return u})}function be(e){return"string"!=typeof e?String(e):e.replaceAll(/~|\//g,e=>"~"===e?"~0":"~1")}async function Se(e,t,n,r){r=le.create(e.getDb(),[t],"readonly",r);const s=fe(n),a=e.getModel(t);return await r.wrap(async e=>{const n={};return await e.getStore(t).openCursor(async e=>{if(ye(s,e.value)){for(const[t,n]of a.entries())if(ee.is(n))if(n.isArray){if(!Array.isArray(e.value[t]))throw new o("Expected array type");const r=[];for(const s of e.value[t])r.push(`/${n.to}/${be(s)}`);e.value[t]=r}else(n.isOptional&&e.value[t]||!n.isNullable())&&(e.value[t]=`/${n.to}/${be(e.value[t])}`);else{if(!ae.is(n)&&!Z.is(n))throw new p(`Unrecognized model field on key '${t}'`);e.value[t]=await U(n.type,e.value[t])}if(n[e.value[a.primaryKey]])throw new p("Duplicate primary key detected "+JSON.stringify(n));n[e.value[a.primaryKey]]=e.value}return e.continue(),!0}),n})}function Ae(e,t){const n=[`## ${e.name}`],r=[];for(const[s,o]of e.entries())Z.is(o)?r.unshift(s):r.push(s);n.push(r.join(","));for(const s of Object.values(t)){const e=[];for(const t of r)switch(typeof s[t]){case"object":e.push(JSON.stringify(s[t]));break;case"undefined":e.push("");break;default:e.push(String(s[t]))}n.push(e.join(","))}return n.join("\n")}class ve{constructor(e,t,n){this.name=e,this.content=t,this.extension=n}toFile(e=`${this.name}_dump.${this.extension}`,t){return new File([this.content],e,t)}download(e=`${this.name}_dump.${this.extension}`,t){const n=URL.createObjectURL(this.toFile(e,t)),r=document.createElement("a");r.href=n,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(n)}static toJson(e,t,n){return new this(e,JSON.stringify(t,void 0,n?.pretty??1?4:void 0),"json")}static toCsvStore(e,t){return new this(e.name,Ae(e,t),"csv")}static toCsvDb(e,t,n){const r=[`# ${e.name}`];for(const s of t)r.push(Ae(e.getModel(s),n[s]));return new this(e.name,r.join("\n"),"csv")}}class $e{constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const n of this.models.keys())this.stores[n]=this.createInterface(n)}name;version;stores;getDb(){return this.db}getStore(e){return this.stores[e]}getStoreNames(){return this.models.keys()}createTransaction(e,t,n){return new le(this.db,t,e,n)}async drop(){await g(window.indexedDB.deleteDatabase(this.name))}async dump(e,t,n){const r=await async function(e,t){const n={};t=t||e.getStoreNames();const r=e.createTransaction("readonly",t);for(const s of t)n[s]=await Se(e,s,void 0,r);return n}(this,t);switch(e){case"json":return ve.toJson(this.name,r,n);case"csv":return ve.toCsvDb(this,t||this.getStoreNames(),r)}}deleteAllStores(){for(const e of this.models.keys())this.db.deleteObjectStore(e)}deleteStore(e){Array.isArray(e)||(e=[e]);for(const t of e)this.db.deleteObjectStore(t)}getModel(e){const t=this.models.getModel(e);if(!t)throw new c(`Model with name '${e}' not found`);return t}getAccessedStores(e,t,n,r){return r?r.storeNames:Array.from(he(e,t,n,this))}createInterface(e){return{add:async(t,n)=>await this.add(e,t,{tx:n}),addMany:async(t,n)=>{if(!n){const r=new Set;for(const n of t)k(r,he(e,n,!0,this));n=this.createTransaction("readwrite",Array.from(r))}const r=[];for(const s of t)r.push(await this.add(e,s,{tx:n}));return r},findFirst:async(t,n)=>(await this.find(e,t,!0,{tx:n}))[0],find:async(t,n)=>await this.find(e,t,!1,{tx:n}),get:async t=>{const n=this.createTransaction("readonly",e);return await n.getStore(e).get(t)},update:async(t,n)=>(await this.update(e,{data:n},!0,{singleton:{id:t}}))[0],updateFirst:async(t,n)=>(await this.update(e,t,!0,{tx:n}))[0],updateMany:async(t,n)=>await this.update(e,t,!1,{tx:n}),compileQuery:t=>new we(this,e,t),delete:async t=>await ge(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await ge(e,this,t,!0)>0,deleteMany:async t=>await ge(e,this,t,!1),dump:async(t,n,r)=>{const s=await Se(this,e,n);switch(t){case"json":return ve.toJson(e,s,r);case"csv":return ve.toCsvStore(this.getModel(e),s)}}}}async add(e,t,n={}){let{tx:r}=n;const{relation:o}=n,i=this.getAccessedStores(e,t,!0,r);return r=le.create(this.db,i,"readwrite",r),await r.wrap(async n=>{const r=n.getStore(e),i=this.getModel(e),c=i.getPrimaryKey(),u=o?{[o.key]:i.getRelation(o.key)?.isArray?[o.id]:o.id}:{},l=c.isAutoIncremented()?{...u}:{...u,[i.primaryKey]:t[i.primaryKey]??c.genKey()},f=await r.add(l),y={},d=new Set;for(const o in t){d.add(o);const r=t[o];switch(i.keyType(o)){case se.Invalid:throw new s(`Key '${o}' does ont exist on model '${e}'`);case se.Property:{const e=i.parseField(o,r);if(!e)throw new a;if(!e.success)throw new s(`Key '${o}' has the following validation error: ${e.error}`);y[o]=e.data;break}case se.Relation:{if(!r)continue;const e=S(r),t=i.getRelation(o);if(t.isArray&&(y[o]=[],"$createMany"in r||"$connectMany"in r)){const t=[];for(const e of r.$createMany??[])t.push({$create:e});for(const e of r.$connectMany??[])t.push({$connect:e});e.push(...t)}const a=this.getModel(t.to).getRelation(t.getRelatedKey()),c=new Set;for(const r of e){const e=b(r)[0];if(!e)throw new s(`Key '${o}' cannot be an empty connection object`);switch(e){case"$connect":{const i=r[e];if(c.has(i))throw new s(`Primary key '${i}' was already used for a connection`);if(c.add(i),!a)throw new s(`Could not find corresponding relation '${t.name}'`);await this.connectDocument(t,f,i,n),t.isArray?y[o].push(i):y[o]=i;break}case"$create":{const s=await this.add(t.to,r[e],{tx:n,relation:{id:f,key:t.getRelatedKey()}});t.isArray?y[o].push(s):y[o]=s;break}case"$connectMany":case"$createMany":break;default:throw new s(`Connection Object on key '${o}' has an unknown key '${e}'`)}if(!t.isArray)break}break}case se.PrimaryKey:}}const h=Array.from(new Set(i.keys()).difference(d));for(const e of h)switch(i.keyType(e)){case se.Property:{const t=i.parseField(e,void 0);if(!t)throw new a("A parsing error occurred");if(!t.success)throw new s(`Key '${e}' is missing`);y[e]=t.data;break}case se.Relation:{const t=i.getRelation(e),n=u[e];if(t.isArray)y[e]=n??[];else if(t.isOptional)y[e]=n??null;else{if(!n)throw new s(`Required relation '${e}' is not defined`);y[e]=n}break}case se.Invalid:case se.PrimaryKey:}return await r.put({[i.primaryKey]:f,...y})})}async clear(e,t){await ge(e,this,void 0,!1,t)}async find(e,t,n,r={}){let{tx:s}=r;const o=this.getAccessedStores(e,pe(t),!1,s);s=le.create(this.db,o,"readonly",s);const a=[];return await s.wrap(async r=>{const s=r.getStore(e),o=de(e,this,t);return await s.openCursor(async e=>{const t=await o(e.value,r);return t&&a.push(t),(!n||!a.length)&&(e.continue(),!0)}),a})}async update(e,t,n,r={}){const{singleton:o}=r,i=r.singleton?t:t.data,c=this.getAccessedStores(e,i,!0,r.tx),f=le.create(this.db,c,"readwrite",r.tx);return await f.wrap(async r=>{const c=r.getStore(e),f=this.getModel(e),y=[];for(const e of b(i))switch(f.keyType(e)){case se.Property:y.push({key:e,isRelation:!1,updateFn:"function"==typeof i[e]?i[e]:()=>i[e]});break;case se.Relation:{const t=S(i[e]);if(!t)continue;const n=[];for(const e of t)for(const t in e){switch(t){case"$createMany":case"$connectMany":case"$updateMany":case"$deleteMany":case"$disconnectMany":{const r=t.substring(0,t.length-4);for(const s of e[t])n.push([r,s]);break}default:n.push([t,e[t]])}break}y.push({actions:n,key:e,isRelation:!0,relation:f.getRelation(e)});break}case se.PrimaryKey:throw new l("Primary key field cannot be updated");case se.Invalid:default:throw new a(`Unknown key '${e}'`)}const d=[],h=async e=>{const t=e[f.primaryKey];for(const{key:n,...o}of y){const a=o.relation;if(o.isRelation)for(const[i,c]of o.actions)switch(i){case"$connect":e[n]&&!a.isArray&&await this.disconnectDocument(a,t,e[n],r).catch(r.onRejection),await this.connectDocument(a,t,c,r).catch(r.onRejection),a.isArray?e[n].push(c):e[n]=c;break;case"$create":{const s=await this.add(a.to,c,{tx:r,relation:{id:t,key:a.getRelatedKey()}});a.isArray?e[n].push(s):e[n]=s;break}case"$delete":if(!a.isNullable())throw new s("Item cannot be deleted, relation is required");e[n]=a.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null,await ge(a.to,this,{},!0,{tx:r,singleton:{id:c}});break;case"$disconnect":{if(!a.isNullable())throw new s("Item cannot be disconnected, relation is required");if(!e[n]||0===e[n]?.lenth)break;const o=this.getModel(a.to).getRelation(a.getRelatedKey());await this.disconnectDocument(a,t,o.isArray?c:e[n],r).catch(r.onRejection),e[n]=a.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null;break}case"$update":a.isArray?await this.update(a.to,c,!1,{tx:r}):null!=e[n]&&await this.update(a.to,c,!1,{tx:r,singleton:{id:t}});break;case"$deleteAll":if(c&&a.isArray&&Array.isArray(e[n])){const t=this.getModel(a.to),s=new Set(e[n]);await ge(a.to,this,{[t.primaryKey]:e=>s.has(e)},!1,{tx:r}),e[n]=[]}break;case"$disconnectAll":if(c&&a.isArray&&Array.isArray(e[n])){for(const s of e[n])await this.disconnectDocument(a,t,s,r);e[n]=[]}}else e[n]=o.updateFn(e[n])}return e};if(o){const e=await c.get(o.id);if(!e)throw new u(`${f.name} with priamry key '${o.id}' not found`);const t=await h(e).catch(r.onRejection);return await c.put(t),[t]}{const e=fe(t.where);return await c.openCursor(async t=>{const s=t.value;if(ye(e,s)){const e=await h(s).catch(r.onRejection);if(await g(t.update(e)).then(()=>d.push(e)).catch(r.onRejection),n)return!1}return t.continue(),!0}),d}})}async connectDocument(e,t,n,r){const s=r.getStore(e.to),o=await s.get(n);if(!o)throw new u(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const a=e.getRelatedKey(),i=this.getModel(e.to).getRelation(a),c=o[a];if(i.isArray&&Array.isArray(c))c.includes(t)||c.push(t);else{if(c)throw new h;o[a]=t}return await s.put(o).catch(r.onRejection),n}async disconnectDocument(e,t,n,r){const s=r.getStore(e.to),o=await s.get(n);if(!o)throw new u(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const a=this.getModel(e.to).getRelation(e.getRelatedKey());if(a.isArray)o[e.getRelatedKey()].filter(e=>e!==t);else{if(!a.isOptional)throw new h;o[e.getRelatedKey()]=null}return await s.put(o).catch(r.onRejection),n}}class ke{constructor(e,t){this.name=e,this.models=t,this.modelKeys=b(this.models),this.schemas={};for(const r of this.modelKeys){const e=this.models[r],t={};for(const[s,o]of e.entries())if(ae.is(o))t[s]=o.type;else if(ee.is(o)){const{onDelete:a}=o.getActions(),i=this.models[o.to],c=i.getPrimaryKey();t[s]=c.type,o.isOptional?t[s]=B(t[s]):o.isArray&&(t[s]=F(t[s]));let u=!!o.getRelatedKey();if(!u)for(const[t,r]of i.relations())if(s!==t&&r.to===e.name&&r.name===o.name){if(u=!0,o.setRelatedKey(t),r.setRelatedKey(s),"SetNull"===a&&!r.isNullable())throw new n(`Key '${t}' on model '${i.name}': Non-optional relation cannot have the 'SetNull' action`);break}if(!u)throw new n(`Relation '${o.name}' of model ${r} does not have an equivalent relation on model '${o.to}'`)}else{if(!Z.is(o))throw new n(`Unknown field value detected: ${JSON.stringify(o)}`);t[s]=o.type}this.schemas[r]=t}}schemas;modelKeys;getModel(e){return this.models[e]}async createClient(e=1){const t=window.indexedDB.open(this.name,e);t.onupgradeneeded=e=>{const t=e.target.result;for(const n of this.modelKeys){const e=this.models[n];t.objectStoreNames.contains(e.name)||t.createObjectStore(e.name,{autoIncrement:e.getPrimaryKey().isAutoIncremented(),keyPath:e.primaryKey})}};const n=await g(t);return new $e(n,this)}keys(){return[...this.modelKeys]}}const Re=Object.freeze(Object.defineProperty({__proto__:null,ArrayRelation:ne,BaseRelation:ee,DbClient:$e,FieldTypes:se,Model:ce,OptionalRelation:re,PrimaryKey:Z,Property:ae,Relation:te,Tag:R,Type:q,deserializeType:G,isExactType:Y,isSubtype:J,isType:W,parseType:H,serializeType:U,typeToString:z},Symbol.toStringTag,{value:"Module"}));exports.Builder=class{constructor(e,t){this.name=e,this.names=t,this.models={}}models;defineModel(e,t){if("object"==typeof e&&ce.is(e))return this.models[e.name]=e,e;{if(!t)throw new Error("Model Fields must be defined");const n=new ce(e,t);return this.models[e]=n,n}}compile(e){return new ke(this.name,e)}},exports.CompiledQuery=we,exports.Model=ce,exports.Property=ae,exports.StoreError=e,exports.Typing=Q,exports.core=Re;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class e extends Error{code;constructor(e,t){super(`(${e}) ${t}`),this.code=e}}function t(t,n){return class extends e{static code;constructor(e=n){super(t,e)}static of(e){new this(e)}}}const n=t("INVALID_CONFIG","Configuration is invalid"),r=t("INVALID_TX","Transaction is invalid"),s=t("INVALID_ITEM","Item is invalid"),a=t("ASSERTION_FAILED","Assertion failed"),i=t("UNKNOWN","An unknown error occurred"),o=t("DELETE_FAILED","Item could not be deleted"),c=t("NOT_FOUND","Object Store Not Found"),l=t("NOT_FOUND","Document Not Found"),u=t("UPDATE_FAILED","Item could not be updated"),y=t("ADD_FAILED","Item could not be added"),d=t("OPEN_CURSOR","Cursor could not be opened"),h=t("GET_FAILED","Item could not be retrieved"),f=t("OVERWRITE_RELATION","Relation cannot be overwritten"),p=t("EXPORT","Export failed"),w=t("SERIALIZATION_FAILED","Seralization failed"),m=t("DESERIALIZATION_FAILED","De-seralization failed");function g(e,t){return new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function b(e){return Object.keys(e)}function S(e){return Array.isArray(e)||(e=[e]),e}function A(){return crypto.randomUUID()}function v(){return new Date}function $(e){return e}function k(e,t){for(const n of t.keys())e.add(n);return e}var R=(e=>(e[e.string=0]="string",e[e.number=1]="number",e[e.date=2]="date",e[e.boolean=3]="boolean",e[e.symbol=4]="symbol",e[e.bigint=5]="bigint",e[e.file=6]="file",e[e.void=7]="void",e[e.float=8]="float",e[e.int=9]="int",e[e.unknown=10]="unknown",e[e.literal=11]="literal",e[e.array=12]="array",e[e.set=13]="set",e[e.union=14]="union",e[e.optional=15]="optional",e[e.default=16]="default",e[e.object=17]="object",e[e.tuple=18]="tuple",e[e.custom=19]="custom",e))(R||{});class j{static cache={};static getType(e){const t=this.cache[e];return t||(this.cache[e]={tag:e})}static string(){return this.getType(R.string)}static number(){return this.getType(R.number)}static boolean(){return this.getType(R.boolean)}static bigint(){return this.getType(R.bigint)}static symbol(){return this.getType(R.symbol)}static int(){return this.getType(R.int)}static float(){return this.getType(R.float)}static void(){return this.getType(R.void)}static file(){return this.getType(R.file)}static date(){return this.getType(R.date)}static unknown(){return this.getType(R.unknown)}static literal(e){return{tag:R.literal,value:e}}static array(e){return{tag:R.array,of:e}}static default(e,t){return{tag:R.default,of:e,value:t}}static set(e){return{tag:R.set,of:e}}static union(e){return{tag:R.union,options:e}}static optional(e){return{tag:R.optional,of:e}}static object(e){return{tag:R.object,props:e}}static tuple(e){return{tag:R.tuple,elements:e}}static custom(e){return{tag:R.custom,...e}}}function O(e){switch(e.tag){case R.void:return"void";case R.literal:return String(e.value);case R.boolean:return"boolean";case R.number:return"number";case R.float:return"float";case R.int:return"integer";case R.bigint:return"bigint";case R.string:return"string";case R.symbol:return"symbol";case R.unknown:return"unknown";case R.date:return"Date";case R.tuple:return`Tuple<${e.elements.map(e=>O(e)).join(", ")}>`;case R.array:return`Array<${O(e.of)}>`;case R.set:return`Set<${O(e.of)}>`;case R.default:case R.optional:return`${O(e.of)} | undefined`;case R.union:return`Union<${e.options.map(e=>O(e)).join(", ")}>`;case R.file:return"File";case R.object:return`{${Object.keys(e.props).map(t=>`${t}: ${O(e.props[t])}`).join(",\n")}}`;case R.custom:return"custom"}}async function T(e,t){if(!M(e,t))throw new w(`Value not of the proper type, expected type '${O(e)}', received '${JSON.stringify(t)}'`);switch(e.tag){case R.literal:case R.boolean:case R.number:case R.float:case R.int:case R.string:return t;case R.void:return;case R.bigint:return Number(t);case R.symbol:return t.description;case R.unknown:return JSON.stringify(t);case R.date:return t.getTime();case R.tuple:{const n=[];for(let r=0;r<t.length;r++)n.push(await T(e.elements[r],t[r]));return n}case R.array:{const n=[];for(const r of t)n.push(T(e.of,r));return await Promise.all(n)}case R.set:{const n=[];for(const r of t.keys())n.push(T(e.of,r));return await Promise.all(n)}case R.optional:if(void 0===t)return;return await T(e.of,t);case R.union:for(const n of e.options)try{return await T(n,t)}catch{}throw new w("Value union could not be serialized");case R.file:if(!(t instanceof File))throw new w("Value is not a valid file");return{data:new Promise((e,n)=>{const r=new FileReader;r.onload=()=>e(r.result),r.onerror=n,r.readAsDataURL(t)}),name:t.name,type:t.type};case R.object:{const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional&&s.tag!==R.default&&s.tag!==R.void)throw new w(`Required property '${r}' not found`);n[r]=await T(s,t[r])}return n}case R.default:return await T(e.of,void 0===t?"function"==typeof e.value?e.value():e.value:t);case R.custom:if(!e.serialize)return JSON.stringify(t);switch(typeof e.serialize){case"object":return await T(e.serialize,t);case"function":return await e.serialize(t);default:throw new w(`Unknown Type Serialize argument '${JSON.stringify(e.serialize)}'`)}}}async function K(e,t){switch(e.tag){case R.void:return;case R.literal:if(t!==e.value)throw new m(`'${t}' is not equal to literal '${t}'`);return t;case R.boolean:if("boolean"!=typeof t)throw new m(`'${t}' is not a boolean`);return t;case R.int:if("number"!=typeof t||!Number.isInteger(t))throw new m(`'${t}' is not an integer`);return t;case R.float:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a float`);return t;case R.number:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a number`);return t;case R.bigint:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a bigint`);return BigInt(t);case R.string:if("string"!=typeof t)throw new m(`'${t}' is not a string`);return t;case R.symbol:if("string"!=typeof t)throw new m(`'${t}' is not a symbol`);return Symbol.for(t);case R.date:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a date timestamp`);return new Date(t);case R.tuple:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(let r=0;r<t.length;r++)n.push(await K(e.elements[r],t[r]));return n}case R.array:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(K(e.of,r));return await Promise.all(n)}case R.set:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(K(e.of,r));return new Set(await Promise.all(n))}case R.optional:if(void 0===t)return;return K(e.of,t);case R.unknown:return"string"!=typeof t?t:JSON.parse(t);case R.union:for(const n of e.options)try{return await K(n,t)}catch{}throw new m("Value did not match the union");case R.file:{if(!(t&&"object"==typeof t&&"data"in t&&"name"in t&&"type"in t&&"string"==typeof t.data&&"string"==typeof t.name&&"string"==typeof t.type))throw new m("Value is not a valid file schema");const e=Buffer.from(t.data.replace(/^data:.+;base64,/,""),"base64");return new File([e],t.name,{type:t.type})}case R.default:return void 0===t?e.value:K(e.of,t);case R.custom:if(!e.isType(t))throw new m("Value is not valid");if(!e.deserialize)return JSON.parse(String(t));switch(typeof e.deserialize){case"object":return await K(e.deserialize,t);case"function":return await e.deserialize(t);default:throw new m(`Unknown Type Deserialize argument '${JSON.stringify(e.deserialize)}'`)}case R.object:{if(!t||"object"!=typeof t)throw new m("Value is not an object");const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional)throw new m(`Required property '${r}' not found`);n[r]=await K(s,t[r])}return n}}}function N(e,t){if(e.tag!==t.tag)return!1;switch(e.tag){case R.literal:return e.value===t.value;case R.optional:case R.default:case R.set:case R.array:return N(e.of,t.of);case R.union:if(e.options.length!==t.options.length)return!1;for(let n=0;n<e.options.length;n++)if(!N(e.options[n],t.options[n]))return!1;return!0;case R.tuple:if(e.elements.length!==t.elements.length)return!1;for(let n=0;n<e.elements.length;n++)if(!N(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(Object.keys(e.props).length!==Object.keys(t.props).length)return!1;for(const n in e.props){if(!(n in t.props))return!1;if(!N(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t;default:return!0}}function D(e,t){switch(e.tag){case R.literal:return t.tag===R.literal&&t.value===e.value;case R.number:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===O(e)||t.tag===R.float||t.tag===R.int;case R.boolean:case R.symbol:case R.string:case R.bigint:case R.int:case R.float:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===O(e);case R.unknown:return!0;case R.date:case R.file:case R.void:return t.tag===e.tag;case R.optional:case R.default:case R.set:case R.array:return t.tag===e.tag&&D(e.of,t.of);case R.union:if(t.tag===R.union){for(const n of t.options)if(!D(e,n))return!1;return!0}return e.options.some(e=>D(e,t));case R.tuple:if(t.tag!==R.tuple)return!1;for(let n=0;n<e.elements.length;n++)if(!D(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(t.tag!==R.object)return!1;for(const n in t.props){if(!e.props[n])return!1;if(!D(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t}}function M(e,t){switch(e.tag){case R.void:return void 0===t;case R.literal:return t===e.value;case R.boolean:return"boolean"==typeof t;case R.number:return"number"==typeof t;case R.bigint:return"bigint"==typeof t;case R.string:return"string"==typeof t;case R.symbol:return"symbol"==typeof t;case R.unknown:return!0;case R.float:return"number"==typeof t&&!isNaN(t);case R.int:return"number"==typeof t&&Number.isInteger(t);case R.date:return t instanceof Date&&!isNaN(t.getTime());case R.tuple:return Array.isArray(t)&&t.length===e.elements.length&&t.every((t,n)=>M(e.elements[n],t));case R.array:return Array.isArray(t)&&t.every(t=>M(e.of,t));case R.set:return t instanceof Set&&Array.from(t).every(t=>M(e.of,t));case R.optional:case R.default:return void 0===t||M(e.of,t);case R.union:return e.options.some(e=>M(e,t));case R.file:return t instanceof File;case R.object:return!(!t||"object"!=typeof t)&&Object.keys(e.props).every(n=>M(e.props[n],t[n]));case R.custom:return e.isType(t)}}function I(e,t){if(M(e,t)){switch(e.tag){case R.custom:if(e.parse)try{return{success:!0,data:e.parse(t)}}catch(n){return{success:!1,error:String(n)}}break;case R.default:return void 0===t?{success:!0,data:e.value}:{success:!0,data:t}}return{success:!0,data:t}}return{success:!1,error:`Value is not a valid '${O(e)}'`}}const x=Object.freeze(Object.defineProperty({__proto__:null,Tag:R,Type:j,deserializeType:K,isExactType:N,isSubtype:D,isType:M,parseType:I,serializeType:T,typeToString:O},Symbol.toStringTag,{value:"Module"})),P=Symbol.for("primaryKey");class E{symbol=P;genFn;autoGenerate;type;constructor(e,t){if(e){if(e.tag>R.date)throw new n("Invalid Primary Key Type");this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1}else this.autoGenerate=!1,this.type=j.number()}getType(){return this.type}generator(e){return this.genFn=e,this.autoGenerate=!0,this}autoIncrement(){if(this.type.tag===R.number)return this.genFn=void 0,this.autoGenerate=!0,this;throw new n("Primary key must be a number to use autoIncrement()")}uuid(){if(!window.isSecureContext)throw new Error("Window is not in a secure context");return new E(j.string(),A)}date(){return new E(j.date(),v)}genKey(...e){if(this.genFn)return this.genFn(...e);throw new Error("Generator function not defined")}isAutoIncremented(){return this.autoGenerate&&!this.genFn}static is(e){return e?.symbol===P}static compareKeyValue(e,t){if(typeof e!=typeof t)return!1;switch(typeof e){case"string":case"number":return e===t;case"object":return e.getTime()===t.getTime();default:return!1}}static validKeyTag=j.union([j.string(),j.number(),j.date()])}class F{constructor(e,t="",n=!1,r=!1,s){this.to=e,this.name=t,this.isOptional=n,this.isArray=r,this.relatedKey="",this.actions={onDelete:s||"Restrict"}}static SYMBOL=Symbol.for("baseRelation");BASE_SYMBOL=F.SYMBOL;actions;relatedKey;getActions(){return{...this.actions}}isNullable(){return this.isArray||this.isOptional}setRelatedKey(e){this.relatedKey=e}getRelatedKey(){return this.relatedKey}tostring(){return`${this.isArray?"Array":this.isOptional?"Optional":"Standard"} relation from this model to model '${this.to}' on key '${this.relatedKey}'`}getBaseSymbol(){return this.BASE_SYMBOL}static is(e){return"getBaseSymbol"in e&&e.getBaseSymbol()===F.SYMBOL}}class _ extends F{static R_SYMBOL=Symbol.for("relation");symbol=_.R_SYMBOL;constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new L(this.to,this.name,e)}optional({onDelete:e}={}){return new C(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}static is(e){return e?.symbol===this.R_SYMBOL}}class L extends F{static A_SYMBOL=Symbol.for("arrayRelation");symbol=L.A_SYMBOL;constructor(e,t,n="None"){super(e,t,!1,!0,n)}static is(e){return e?.symbol===this.A_SYMBOL}}class C extends F{static O_SYMBOL=Symbol.for("optionalRelation");symbol=C.O_SYMBOL;constructor(e,t,n="None"){super(e,t,!0,!1,n)}static is(e){return e?.symbol===this.O_SYMBOL}}var z=(e=>(e[e.Property=0]="Property",e[e.Relation=1]="Relation",e[e.PrimaryKey=2]="PrimaryKey",e[e.Invalid=3]="Invalid",e))(z||{});const B=Symbol.for("property");class V{constructor(e,t){this.type=e,this.options={unique:t?.unique??!1}}symbol=B;hasDefault=!1;options;unique(){switch(this.type.tag){case R.boolean:case R.string:case R.number:case R.symbol:return this.options.unique=!0,this;default:throw new Error("A non-primitive cannot be a unique value")}}hasDefaultValue(){return this.hasDefault}static relation(e,t){return new _(e,t)}static primaryKey(e="number"){return new E(this.nameToType(e))}static nameToType(e){switch(e){case"boolean":return j.boolean();case"bigint":return j.bigint();case"number":return j.number();case"string":return j.string();case"symbol":return j.symbol();default:return j.unknown()}}static is(e){return"object"==typeof e&&e?.symbol===B}array(){return new V(j.array(this.type),this.options)}default(e){return this.hasDefault=!0,new V(j.default(this.type,e),this.options)}optional(){return new V(j.optional(this.type),this.options)}static array(e,t){return new V(j.array(e.type),t)}static boolean(e){return new V(j.boolean(),e)}static custom(e,t){return new V(j.custom({isType:t=>e(t).success,serialize:t?.serialize,deserialize:t?.deserialize}),t)}static date(e){return new V(j.date(),e)}static file(e){return new V(j.file(),e)}static literal(e,t){return new V(j.literal(e),t)}static number(e){return new V(j.number(),e)}static string(e){return new V(j.string(),e)}static set(e,t){return new V(j.set(e.type),t)}static union(e,t){return new V(j.union(e.map(e=>e.type)),t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const n=[];for(const r of t){const t=e(r);if(!t.success)return t;n.push(t.data)}return{success:!0,data:n}}return{success:!1,error:"Value is not an array"}}}}const q=Symbol.for("model");class U{constructor(t,n){this.name=t,this.fields=n,this.fieldKeys=b(n);for(const e of this.fieldKeys){const t=this.fields[e];F.is(t)&&t.to!==this.name&&this.relationLinks.add(t.to)}const r=this.fieldKeys.find(e=>E.is(this.fields[e]));if(!r)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=r}symbol=q;fieldKeys;relationLinks=new Set;cache={};primaryKey;get(e){return this.fields[e]}getPrimaryKey(){return this.fields[this.primaryKey]}getRelation(e){const t=this.fields[e];if(t&&F.is(t))return t}keyType(e){const t=this.fields[e];return t?V.is(t)?z.Property:F.is(t)?z.Relation:E.is(t)?z.PrimaryKey:z.Invalid:z.Invalid}links(){return this.relationLinks.keys()}*relations(){for(const e of this.fieldKeys)F.is(this.fields[e])&&(yield[e,this.fields[e]])}*entries(){for(const e of this.fieldKeys)yield[e,this.fields[e]]}keys(){return this.fieldKeys}parseField(e,t){return V.is(this.fields[e])?I(this.fields[e].type,t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=new Set,n=[this.name];let r;for(;n.length>0;){const s=n.shift();if(t.has(s))continue;r=e.getModel(s);const a=r.cache.delete;if(a)k(t,a);else{t.add(s);for(const e of r.links())t.has(e)||n.push(e)}}return this.cache.delete=t,t}static is(e){return e?.symbol===q}}class G{constructor(e,t){this.tx=e,this.internal=t}add(e){return this.handleRequest(this.internal.add(e),()=>new y)}get(e){return this.handleRequest(this.internal.get(e),()=>new h)}async assertGet(e){const t=await this.handleRequest(this.internal.get(e),()=>new h);if(!t)throw this.tx.abort(new l);return t}put(e){return this.handleRequest(this.internal.put(e),()=>new u)}delete(e){return this.handleRequest(this.internal.delete(e),()=>new o)}async openCursor(t,n={}){const r=n.onError||(()=>new d),s=this.internal.openCursor(n.query,n.direction);await new Promise((n,a)=>{s.onsuccess=async s=>{try{s.target||a(this.tx.abort(r()));const e=s.target.result;e&&await t(e,this.tx)||n()}catch(o){a(this.tx.abort(o instanceof e?o:new i(String(o))))}},s.onerror=()=>{a(this.tx.abort(r()))}})}handleRequest(e,t){return new Promise(n=>{e.onsuccess=()=>{n(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class J{internal;status;error=null;storeNames;inWrap=!1;onRejection=t=>{throw t instanceof e?this.abort(t):this.abort(new i(String(t)))};objectStores;constructor(e,t,n,r={}){e instanceof J?(this.internal=e.getInternal(),this.storeNames=e.storeNames,this.status=e.status,this.error=e.error,this.objectStores=e.getAllStores()):(this.internal=e.transaction(t,n),this.status=0,this.storeNames=Array.from(this.internal.objectStoreNames),this.objectStores=new Map(this.storeNames.map(e=>[e,this.getObjectstore(e)])),this.internal.onabort=this.registerHandler(1,r.onAbort),this.internal.onerror=this.registerHandler(3,r.onError),this.internal.oncomplete=this.registerHandler(2,r.onComplete))}static create(e,t,n,r){return r||new J(e,t,n)}abort(e){return 1!==this.status&&this.internal.abort(),this.status=1,this.error=e,this.error}commit(){this.internal.commit()}getInternal(){return this.internal}getStore(e){const t=this.objectStores.get(e);if(!t)throw this.abort(new r(`Store '${e}' is not a part of this transaction`));return t}getAllStores(){return this.objectStores}get mode(){return this.internal.mode}is(e){return this.status===e}contains(e){Array.isArray(e)||(e=[e]);for(const t of e)if(!this.internal.objectStoreNames.contains(t))return!1;return!0}assertIsArray(e,t="Value is not an array"){if(!Array.isArray(e))throw this.abort(new a(t))}getObjectstore(e){try{return new G(this,this.internal.objectStore(e))}catch{throw this.abort(new c(`No ObjectStore with the name '${e}' found`))}}registerHandler(e,t=()=>{}){return n=>{this.status=e,t(this,n)}}async wrap(t){if(this.inWrap)return await t(this);this.inWrap=!0;try{const e=await t(this);return this.inWrap=!1,e}catch(n){throw this.inWrap=!1,n instanceof e?this.abort(n):this.abort(new i(JSON.stringify(n)))}}}function Y(e){if(!e)return[];const t=[];for(const n in e)if(Object.hasOwn(e,n))switch(typeof e[n]){case"function":t.push([n,!0,e[n]]);break;case"object":if(e[n]instanceof Date){const r=e[n];t.push([n,!0,e=>e instanceof Date&&e.getTime()===r.getTime()])}break;default:t.push([n,!1,e[n]])}return t}function W(e,t){if(!t||"object"!=typeof t)return!1;for(const n of e)if(n[1]){if(!n[2](t[n[0]]))return!1}else if(n[2]!==t[n[0]])return!1;return!0}function H(e,t,n={},r){const a=t.getModel(e);if(n.include&&n.select)throw new s("include and select cannot both be defined");const i=Y(n.where),o=n.select?"select":n.include?"include":"";if(o){const e=n[o],r=!!n.select,s=[];for(const n in e)if(Object.hasOwn(e,n)&&e[n])switch(a.keyType(n)){case z.Relation:{const r=a.getRelation(n),i="object"==typeof e[n]?H(r.to,t,e[n]):$,o=r.getRelatedKey();if(r.isArray){const e=async(e,t)=>{const n=[],s=t.getStore(r.to);for(const r of e){const e=await i(await s.assertGet(r),t);e&&(delete e[o],n.push(e))}return n};s.push({key:n,getValue:e})}else{const e=async(e,t)=>await i(await t.getStore(r.to).assertGet(e),t);s.push({key:n,getValue:e})}break}case z.Property:case z.PrimaryKey:r&&s.push({key:n})}return r?async(e,t)=>{if(!W(i,e))return;const n={};for(const{key:r,getValue:a}of s)n[r]=a?await a(e[r],t):e[r];return n}:async(e,t)=>{if(W(i,e)){for(const{key:n,getValue:r}of s)e[n]=await r(e[n],t);return e}}}return e=>W(i,e)?e:void 0}function Q(e,t,n,r){const s=new Set([e]);if(n){const a=r.getModel(e);for(const e in t){const i=a.getRelation(e),o=S(t[e]);if(i)for(const e of o)if(e&&"object"==typeof e)for(const t in e)if(Object.hasOwn(e,t))switch(t){case"$connect":case"$connectMany":case"$disconnect":case"$disconnectMany":case"$disconnectAll":s.add(i.to);break;case"$delete":case"$deleteMany":case"$deleteAll":k(s,a.getDeletedStores(r));break;case"$create":k(s,Q(i.to,e[t],n,r));break;case"$createMany":e[t].forEach(e=>k(s,Q(i.to,e,n,r)));break;case"$update":k(s,Q(i.to,e[t].data,n,r));break;case"$updateMany":e[t].forEach(e=>k(s,Q(i.to,e.data,n,r)))}}}else{const n=r.getModel(e);for(const e in t){const a=n.getRelation(e);if(a)switch(typeof t[e]){case"object":k(s,Q(a.to,X(t[e]),!1,r));break;case"boolean":s.add(a.to)}}}return s}function X(e){return e.select?e.select:e.include?e.include:{}}class Z{constructor(e,t,n){this.client=e,this.name=t,this.accessedStores=Array.from(Q(t,X(n),!1,this.client)),this.selectClause=H(t,this.client,n)}accessedStores;selectClause;async find(){return await this._find(!1)}async findFirst(){return(await this._find(!0))[0]}async _find(e){const t=this.client.createTransaction("readonly",this.accessedStores);return await t.wrap(async t=>{const n=[],r=t.getStore(this.name);return await r.openCursor(async r=>{const s=await this.selectClause(r.value,t);return s&&n.push(s),(!e||!n.length)&&(r.continue(),!0)}),n})}}function ee(e,t,r){return async s=>{if(!s)return!1;const a=s[e.primaryKey];for(const[i,c]of e.relations()){const{onDelete:l}=c.getActions(),u=s[i],y=t.getModel(c.to);switch(l){case"Cascade":if(c.isArray){r.assertIsArray(u);const e=new Set(u),n=ee(y,t,r),s=r.getStore(c.to);await s.openCursor(async t=>(e.has(t.value[y.primaryKey])&&await n(t.value),t.continue(),!0)).catch(r.onRejection)}else u&&await te(c.to,t,void 0,void 0,{tx:r,singleton:{id:u}});break;case"SetNull":{if(!u)break;const e=S(u),t=r.getStore(c.to),s=c.getRelatedKey(),i=y.getRelation(s);if(!i)throw new n(`Relation '${c.name}' has an invalid relation key '${c.getRelatedKey()}'`);if(!i.isNullable())throw new n(`Key '${s}' on model '${s}': Non-optional relation cannot have the 'SetNull' action`);for(const n of e){const e=await t.get(n);if(!e)continue;const o=e[s];if(i.isArray){r.assertIsArray(o);const e=o.indexOf(a);if(-1===e)continue;o.splice(e,1)}else e[s]=null;await t.put(e)}break}case"Restrict":if(Array.isArray(u)&&u.length>0||u)throw new o(`Key '${i}' on model '${e.name}' deletion is restricted while there is an active relation`)}}return!0}}async function te(e,t,n,r=!1,s={}){const{singleton:a,finalStep:i=!0}=s,o=t.getModel(e),c=s.tx?s.tx.storeNames:Array.from(o.getDeletedStores(t)),l=J.create(t.getDb(),c,"readwrite",s.tx);return await l.wrap(async s=>{const c=s.getStore(e);let l=0;const u=ee(o,t,s);if(a)await u(await c.assertGet(a.id))&&(await c.delete(a.id),l++);else{const e=Y(n);let t;await c.openCursor(async n=>{const a=n.value;return W(e,a)&&await u(a)&&(t=g(n.delete()).catch(s.onRejection)),!(r&&l>0)&&(n.continue(),!0)}),t&&i&&await t}return l})}function ne(e){return"string"!=typeof e?String(e):e.replaceAll(/~|\//g,e=>"~"===e?"~0":"~1")}async function re(e,t,n,r){r=J.create(e.getDb(),[t],"readonly",r);const s=Y(n),i=e.getModel(t);return await r.wrap(async e=>{const n={};return await e.getStore(t).openCursor(async e=>{if(W(s,e.value)){for(const[t,n]of i.entries())if(F.is(n))if(n.isArray){if(!Array.isArray(e.value[t]))throw new a("Expected array type");const r=[];for(const s of e.value[t])r.push(`/${n.to}/${ne(s)}`);e.value[t]=r}else(n.isOptional&&e.value[t]||!n.isNullable())&&(e.value[t]=`/${n.to}/${ne(e.value[t])}`);else{if(!V.is(n)&&!E.is(n))throw new p(`Unrecognized model field on key '${t}'`);e.value[t]=await T(n.type,e.value[t])}if(n[e.value[i.primaryKey]])throw new p("Duplicate primary key detected "+JSON.stringify(n));n[e.value[i.primaryKey]]=e.value}return e.continue(),!0}),n})}function se(e,t){const n=[`## ${e.name}`],r=[];for(const[s,a]of e.entries())E.is(a)?r.unshift(s):r.push(s);n.push(r.join(","));for(const s of Object.values(t)){const e=[];for(const t of r)switch(typeof s[t]){case"object":e.push(JSON.stringify(s[t]));break;case"undefined":e.push("");break;default:e.push(String(s[t]))}n.push(e.join(","))}return n.join("\n")}class ae{constructor(e,t,n){this.name=e,this.content=t,this.extension=n}toFile(e=`${this.name}_dump.${this.extension}`,t){return new File([this.content],e,t)}download(e=`${this.name}_dump.${this.extension}`,t){const n=URL.createObjectURL(this.toFile(e,t)),r=document.createElement("a");r.href=n,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(n)}static toJson(e,t,n){return new this(e,JSON.stringify(t,void 0,n?.pretty??1?4:void 0),"json")}static toCsvStore(e,t){return new this(e.name,se(e,t),"csv")}static toCsvDb(e,t,n){const r=[`# ${e.name}`];for(const s of t)r.push(se(e.getModel(s),n[s]));return new this(e.name,r.join("\n"),"csv")}}class ie{constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const n of this.models.keys())this.stores[n]=this.createInterface(n)}name;version;stores;getDb(){return this.db}getStore(e){return this.stores[e]}getStoreNames(){return this.models.keys()}createTransaction(e,t,n){return new J(this.db,t,e,n)}async drop(){await g(window.indexedDB.deleteDatabase(this.name))}async dump(e,t,n){const r=await async function(e,t){const n={};t=t||e.getStoreNames();const r=e.createTransaction("readonly",t);for(const s of t)n[s]=await re(e,s,void 0,r);return n}(this,t);switch(e){case"json":return ae.toJson(this.name,r,n);case"csv":return ae.toCsvDb(this,t||this.getStoreNames(),r)}}deleteAllStores(){for(const e of this.models.keys())this.db.deleteObjectStore(e)}deleteStore(e){Array.isArray(e)||(e=[e]);for(const t of e)this.db.deleteObjectStore(t)}getModel(e){const t=this.models.getModel(e);if(!t)throw new c(`Model with name '${e}' not found`);return t}getAccessedStores(e,t,n,r){return r?r.storeNames:Array.from(Q(e,t,n,this))}createInterface(e){return{add:async(t,n)=>await this.add(e,t,{tx:n}),addMany:async(t,n)=>{if(!n){const r=new Set;for(const n of t)k(r,Q(e,n,!0,this));n=this.createTransaction("readwrite",Array.from(r))}const r=[];for(const s of t)r.push(await this.add(e,s,{tx:n}));return r},findFirst:async(t,n)=>(await this.find(e,t,!0,{tx:n}))[0],find:async(t,n)=>await this.find(e,t,!1,{tx:n}),get:async t=>{const n=this.createTransaction("readonly",e);return await n.getStore(e).get(t)},update:async(t,n)=>(await this.update(e,{data:n},!0,{singleton:{id:t}}))[0],updateFirst:async(t,n)=>(await this.update(e,t,!0,{tx:n}))[0],updateMany:async(t,n)=>await this.update(e,t,!1,{tx:n}),compileQuery:t=>new Z(this,e,t),delete:async t=>await te(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await te(e,this,t,!0)>0,deleteMany:async t=>await te(e,this,t,!1),dump:async(t,n,r)=>{const s=await re(this,e,n);switch(t){case"json":return ae.toJson(e,s,r);case"csv":return ae.toCsvStore(this.getModel(e),s)}}}}async add(e,t,n={}){let{tx:r}=n;const{relation:a}=n,o=this.getAccessedStores(e,t,!0,r);return r=J.create(this.db,o,"readwrite",r),await r.wrap(async n=>{const r=n.getStore(e),o=this.getModel(e),c=o.getPrimaryKey(),l=a?{[a.key]:o.getRelation(a.key)?.isArray?[a.id]:a.id}:{},u=c.isAutoIncremented()?{...l}:{...l,[o.primaryKey]:t[o.primaryKey]??c.genKey()},y=await r.add(u),d={},h=new Set;for(const a in t){h.add(a);const r=t[a];switch(o.keyType(a)){case z.Invalid:throw new s(`Key '${a}' does ont exist on model '${e}'`);case z.Property:{const e=o.parseField(a,r);if(!e)throw new i;if(!e.success)throw new s(`Key '${a}' has the following validation error: ${e.error}`);d[a]=e.data;break}case z.Relation:{if(!r)continue;const e=S(r),t=o.getRelation(a);if(t.isArray&&(d[a]=[],"$createMany"in r||"$connectMany"in r)){const t=[];for(const e of r.$createMany??[])t.push({$create:e});for(const e of r.$connectMany??[])t.push({$connect:e});e.push(...t)}const i=this.getModel(t.to).getRelation(t.getRelatedKey()),c=new Set;for(const r of e){const e=b(r)[0];if(!e)throw new s(`Key '${a}' cannot be an empty connection object`);switch(e){case"$connect":{const o=r[e];if(c.has(o))throw new s(`Primary key '${o}' was already used for a connection`);if(c.add(o),!i)throw new s(`Could not find corresponding relation '${t.name}'`);await this.connectDocument(t,y,o,n),t.isArray?d[a].push(o):d[a]=o;break}case"$create":{const s=await this.add(t.to,r[e],{tx:n,relation:{id:y,key:t.getRelatedKey()}});t.isArray?d[a].push(s):d[a]=s;break}case"$connectMany":case"$createMany":break;default:throw new s(`Connection Object on key '${a}' has an unknown key '${e}'`)}if(!t.isArray)break}break}case z.PrimaryKey:}}const f=Array.from(new Set(o.keys()).difference(h));for(const e of f)switch(o.keyType(e)){case z.Property:{const t=o.parseField(e,void 0);if(!t)throw new i("A parsing error occurred");if(!t.success)throw new s(`Key '${e}' is missing`);d[e]=t.data;break}case z.Relation:{const t=o.getRelation(e),n=l[e];if(t.isArray)d[e]=n??[];else if(t.isOptional)d[e]=n??null;else{if(!n)throw new s(`Required relation '${e}' is not defined`);d[e]=n}break}case z.Invalid:case z.PrimaryKey:}return await r.put({[o.primaryKey]:y,...d})})}async clear(e,t){await te(e,this,void 0,!1,t)}async find(e,t,n,r={}){let{tx:s}=r;const a=this.getAccessedStores(e,X(t),!1,s);s=J.create(this.db,a,"readonly",s);const i=[];return await s.wrap(async r=>{const s=r.getStore(e),a=H(e,this,t);return await s.openCursor(async e=>{const t=await a(e.value,r);return t&&i.push(t),(!n||!i.length)&&(e.continue(),!0)}),i})}async update(e,t,n,r={}){const{singleton:a}=r,o=r.singleton?t:t.data,c=this.getAccessedStores(e,o,!0,r.tx),y=J.create(this.db,c,"readwrite",r.tx);return await y.wrap(async r=>{const c=r.getStore(e),y=this.getModel(e),d=[];for(const e of b(o))switch(y.keyType(e)){case z.Property:d.push({key:e,isRelation:!1,updateFn:"function"==typeof o[e]?o[e]:()=>o[e]});break;case z.Relation:{const t=S(o[e]);if(!t)continue;const n=[];for(const e of t)for(const t in e){switch(t){case"$createMany":case"$connectMany":case"$updateMany":case"$deleteMany":case"$disconnectMany":{const r=t.substring(0,t.length-4);for(const s of e[t])n.push([r,s]);break}default:n.push([t,e[t]])}break}d.push({actions:n,key:e,isRelation:!0,relation:y.getRelation(e)});break}case z.PrimaryKey:throw new u("Primary key field cannot be updated");case z.Invalid:default:throw new i(`Unknown key '${e}'`)}const h=[],f=async e=>{const t=e[y.primaryKey];for(const{key:n,...a}of d){const i=a.relation;if(a.isRelation)for(const[o,c]of a.actions)switch(o){case"$connect":e[n]&&!i.isArray&&await this.disconnectDocument(i,t,e[n],r).catch(r.onRejection),await this.connectDocument(i,t,c,r).catch(r.onRejection),i.isArray?e[n].push(c):e[n]=c;break;case"$create":{const s=await this.add(i.to,c,{tx:r,relation:{id:t,key:i.getRelatedKey()}});i.isArray?e[n].push(s):e[n]=s;break}case"$delete":if(!i.isNullable())throw new s("Item cannot be deleted, relation is required");e[n]=i.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null,await te(i.to,this,{},!0,{tx:r,singleton:{id:c}});break;case"$disconnect":{if(!i.isNullable())throw new s("Item cannot be disconnected, relation is required");if(!e[n]||0===e[n]?.lenth)break;const a=this.getModel(i.to).getRelation(i.getRelatedKey());await this.disconnectDocument(i,t,a.isArray?c:e[n],r).catch(r.onRejection),e[n]=i.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null;break}case"$update":i.isArray?await this.update(i.to,c,!1,{tx:r}):null!=e[n]&&await this.update(i.to,c,!1,{tx:r,singleton:{id:t}});break;case"$deleteAll":if(c&&i.isArray&&Array.isArray(e[n])){const t=this.getModel(i.to),s=new Set(e[n]);await te(i.to,this,{[t.primaryKey]:e=>s.has(e)},!1,{tx:r}),e[n]=[]}break;case"$disconnectAll":if(c&&i.isArray&&Array.isArray(e[n])){for(const s of e[n])await this.disconnectDocument(i,t,s,r);e[n]=[]}}else e[n]=a.updateFn(e[n])}return e};if(a){const e=await c.get(a.id);if(!e)throw new l(`${y.name} with priamry key '${a.id}' not found`);const t=await f(e).catch(r.onRejection);return await c.put(t),[t]}{const e=Y(t.where);return await c.openCursor(async t=>{const s=t.value;if(W(e,s)){const e=await f(s).catch(r.onRejection);if(await g(t.update(e)).then(()=>h.push(e)).catch(r.onRejection),n)return!1}return t.continue(),!0}),h}})}async connectDocument(e,t,n,r){const s=r.getStore(e.to),a=await s.get(n);if(!a)throw new l(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const i=e.getRelatedKey(),o=this.getModel(e.to).getRelation(i),c=a[i];if(o.isArray&&Array.isArray(c))c.includes(t)||c.push(t);else{if(c)throw new f;a[i]=t}return await s.put(a).catch(r.onRejection),n}async disconnectDocument(e,t,n,r){const s=r.getStore(e.to),a=await s.get(n);if(!a)throw new l(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const i=this.getModel(e.to).getRelation(e.getRelatedKey());if(i.isArray)a[e.getRelatedKey()].filter(e=>e!==t);else{if(!i.isOptional)throw new f;a[e.getRelatedKey()]=null}return await s.put(a).catch(r.onRejection),n}}class oe{constructor(e,t){this.name=e,this.models=t,this.modelKeys=b(this.models),this.schemas={};for(const r of this.modelKeys){const e=this.models[r],t={};for(const[s,a]of e.entries())if(V.is(a))t[s]=a.type;else if(F.is(a)){const{onDelete:i}=a.getActions(),o=this.models[a.to],c=o.getPrimaryKey();t[s]=c.type,a.isOptional?t[s]=j.optional(t[s]):a.isArray&&(t[s]=j.array(t[s]));let l=!!a.getRelatedKey();if(!l)for(const[t,r]of o.relations())if(s!==t&&r.to===e.name&&r.name===a.name){if(l=!0,a.setRelatedKey(t),r.setRelatedKey(s),"SetNull"===i&&!r.isNullable())throw new n(`Key '${t}' on model '${o.name}': Non-optional relation cannot have the 'SetNull' action`);break}if(!l)throw new n(`Relation '${a.name}' of model ${r} does not have an equivalent relation on model '${a.to}'`)}else{if(!E.is(a))throw new n(`Unknown field value detected: ${JSON.stringify(a)}`);t[s]=a.type}this.schemas[r]=t}}schemas;modelKeys;getModel(e){return this.models[e]}async createClient(e=1){const t=window.indexedDB.open(this.name,e);t.onupgradeneeded=e=>{const t=e.target.result;for(const n of this.modelKeys){const e=this.models[n];t.objectStoreNames.contains(e.name)||t.createObjectStore(e.name,{autoIncrement:e.getPrimaryKey().isAutoIncremented(),keyPath:e.primaryKey})}};const n=await g(t);return new ie(n,this)}keys(){return[...this.modelKeys]}}const ce=Object.freeze(Object.defineProperty({__proto__:null,ArrayRelation:L,BaseRelation:F,DbClient:ie,FieldTypes:z,Model:U,OptionalRelation:C,PrimaryKey:E,Property:V,Relation:_,Tag:R,Type:j,deserializeType:K,isExactType:N,isSubtype:D,isType:M,parseType:I,serializeType:T,typeToString:O},Symbol.toStringTag,{value:"Module"}));exports.Builder=class{constructor(e,t){this.name=e,this.names=t,this.models={}}models;defineModel(e,t){if("object"==typeof e&&U.is(e))return this.models[e.name]=e,e;{if(!t)throw new Error("Model Fields must be defined");const n=new U(e,t);return this.models[e]=n,n}}compile(e){return new oe(this.name,e)}},exports.CompiledQuery=Z,exports.Model=U,exports.Property=V,exports.StoreError=e,exports.Typing=x,exports.core=ce;
package/dist/index.es.js CHANGED
@@ -1,2 +1,2 @@
1
- class e extends Error{code;constructor(e,t){super(`(${e}) ${t}`),this.code=e}}function t(t,n){return class extends e{static code;constructor(e=n){super(t,e)}static of(e){new this(e)}}}const n=t("INVALID_CONFIG","Configuration is invalid"),r=t("INVALID_TX","Transaction is invalid"),s=t("INVALID_ITEM","Item is invalid"),a=t("ASSERTION_FAILED","Assertion failed"),o=t("UNKNOWN","An unknown error occurred"),i=t("DELETE_FAILED","Item could not be deleted"),c=t("NOT_FOUND","Object Store Not Found"),u=t("NOT_FOUND","Document Not Found"),l=t("UPDATE_FAILED","Item could not be updated"),f=t("ADD_FAILED","Item could not be added"),y=t("OPEN_CURSOR","Cursor could not be opened"),d=t("GET_FAILED","Item could not be retrieved"),h=t("OVERWRITE_RELATION","Relation cannot be overwritten"),p=t("EXPORT","Export failed"),w=t("SERIALIZATION_FAILED","Seralization failed"),m=t("DESERIALIZATION_FAILED","De-seralization failed");function g(e,t){return new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function b(e){return Object.keys(e)}function S(e){return Array.isArray(e)||(e=[e]),e}function A(){return crypto.randomUUID()}function v(){/* @__PURE__ */
2
- return new Date}function $(e){return e}function k(e,t){for(const n of t.keys())e.add(n);return e}var R=/* @__PURE__ */(e=>(e[e.string=0]="string",e[e.number=1]="number",e[e.date=2]="date",e[e.boolean=3]="boolean",e[e.symbol=4]="symbol",e[e.bigint=5]="bigint",e[e.file=6]="file",e[e.void=7]="void",e[e.float=8]="float",e[e.int=9]="int",e[e.unknown=10]="unknown",e[e.literal=11]="literal",e[e.array=12]="array",e[e.set=13]="set",e[e.union=14]="union",e[e.optional=15]="optional",e[e.default=16]="default",e[e.object=17]="object",e[e.tuple=18]="tuple",e[e.custom=19]="custom",e))(R||{});const O={};function j(e){const t=O[e];return t||(O[e]={tag:e})}function K(){return j(R.string)}function N(){return j(R.number)}function D(){return j(R.boolean)}function T(){return j(R.bigint)}function M(){return j(R.symbol)}function I(){return j(R.file)}function x(){return j(R.date)}function _(){return j(R.unknown)}function P(e){return{tag:R.literal,value:e}}function F(e){return{tag:R.array,of:e}}function E(e,t){return{tag:R.default,of:e,value:t}}function L(e){return{tag:R.set,of:e}}function C(e){return{tag:R.union,options:e}}function B(e){return{tag:R.optional,of:e}}function V(e){return{tag:R.custom,...e}}const q=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,Array:F,BigInt:T,Boolean:D,Custom:V,Date:x,Default:E,File:I,Float:function(){return j(R.float)},Int:function(){return j(R.int)},Literal:P,Number:N,Object:function(e){return{tag:R.object,props:e}},Optional:B,Set:L,String:K,Symbol:M,Tuple:function(e){return{tag:R.tuple,elements:e}},Union:C,Unknown:_,Void:function(){return j(R.void)},getType:j},Symbol.toStringTag,{value:"Module"}));function z(e){switch(e.tag){case R.void:return"void";case R.literal:return String(e.value);case R.boolean:return"boolean";case R.number:return"number";case R.float:return"float";case R.int:return"integer";case R.bigint:return"bigint";case R.string:return"string";case R.symbol:return"symbol";case R.unknown:return"unknown";case R.date:return"Date";case R.tuple:return`Tuple<${e.elements.map(e=>z(e)).join(", ")}>`;case R.array:return`Array<${z(e.of)}>`;case R.set:return`Set<${z(e.of)}>`;case R.default:case R.optional:return`${z(e.of)} | undefined`;case R.union:return`Union<${e.options.map(e=>z(e)).join(", ")}>`;case R.file:return"File";case R.object:return`{${Object.keys(e.props).map(t=>`${t}: ${z(e.props[t])}`).join(",\n")}}`;case R.custom:return"custom"}}async function U(e,t){if(!W(e,t))throw new w(`Value not of the proper type, expected type '${z(e)}', received '${JSON.stringify(t)}'`);switch(e.tag){case R.literal:case R.boolean:case R.number:case R.float:case R.int:case R.string:return t;case R.void:return;case R.bigint:return Number(t);case R.symbol:return t.description;case R.unknown:return JSON.stringify(t);case R.date:return t.getTime();case R.tuple:{const n=[];for(let r=0;r<t.length;r++)n.push(await U(e.elements[r],t[r]));return n}case R.array:{const n=[];for(const r of t)n.push(U(e.of,r));return await Promise.all(n)}case R.set:{const n=[];for(const r of t.keys())n.push(U(e.of,r));return await Promise.all(n)}case R.optional:if(void 0===t)return;return await U(e.of,t);case R.union:for(const n of e.options)try{return await U(n,t)}catch{}throw new w("Value union could not be serialized");case R.file:if(!(t instanceof File))throw new w("Value is not a valid file");return{data:new Promise((e,n)=>{const r=new FileReader;r.onload=()=>e(r.result),r.onerror=n,r.readAsDataURL(t)}),name:t.name,type:t.type};case R.object:{const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional&&s.tag!==R.default&&s.tag!==R.void)throw new w(`Required property '${r}' not found`);n[r]=await U(s,t[r])}return n}case R.default:return await U(e.of,void 0===t?"function"==typeof e.value?e.value():e.value:t);case R.custom:return e.serialize?await e.serialize(t):JSON.stringify(t)}}async function G(e,t){switch(e.tag){case R.void:return;case R.literal:if(t!==e.value)throw new m(`'${t}' is not equal to literal '${t}'`);return t;case R.boolean:if("boolean"!=typeof t)throw new m(`'${t}' is not a boolean`);return t;case R.int:if("number"!=typeof t||!Number.isInteger(t))throw new m(`'${t}' is not an integer`);return t;case R.float:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a float`);return t;case R.number:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a number`);return t;case R.bigint:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a bigint`);return BigInt(t);case R.string:if("string"!=typeof t)throw new m(`'${t}' is not a string`);return t;case R.symbol:if("string"!=typeof t)throw new m(`'${t}' is not a symbol`);return Symbol.for(t);case R.date:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a date timestamp`);return new Date(t);case R.tuple:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(let r=0;r<t.length;r++)n.push(await G(e.elements[r],t[r]));return n}case R.array:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(G(e.of,r));return await Promise.all(n)}case R.set:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(G(e.of,r));return new Set(await Promise.all(n))}case R.optional:if(void 0===t)return;return G(e.of,t);case R.unknown:return"string"!=typeof t?t:JSON.parse(t);case R.union:for(const n of e.options)try{return await G(n,t)}catch{}throw new m("Value did not match the union");case R.file:{if(!(t&&"object"==typeof t&&"data"in t&&"name"in t&&"type"in t&&"string"==typeof t.data&&"string"==typeof t.name&&"string"==typeof t.type))throw new m("Value is not a valid file schema");const e=Buffer.from(t.data.replace(/^data:.+;base64,/,""),"base64");return new File([e],t.name,{type:t.type})}case R.default:return void 0===t?e.value:G(e.of,t);case R.custom:if(e.isType(t))return e.deserialize?await e.deserialize(t):JSON.parse(String(t));throw new m("Value is not valid");case R.object:{if(!t||"object"!=typeof t)throw new m("Value is not an object");const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional)throw new m(`Required property '${r}' not found`);n[r]=await G(s,t[r])}return n}}}function Y(e,t){if(e.tag!==t.tag)return!1;switch(e.tag){case R.literal:return e.value===t.value;case R.optional:case R.default:case R.set:case R.array:return Y(e.of,t.of);case R.union:if(e.options.length!==t.options.length)return!1;for(let n=0;n<e.options.length;n++)if(!Y(e.options[n],t.options[n]))return!1;return!0;case R.tuple:if(e.elements.length!==t.elements.length)return!1;for(let n=0;n<e.elements.length;n++)if(!Y(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(Object.keys(e.props).length!==Object.keys(t.props).length)return!1;for(const n in e.props){if(!(n in t.props))return!1;if(!Y(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t;default:return!0}}function J(e,t){switch(e.tag){case R.literal:return t.tag===R.literal&&t.value===e.value;case R.number:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===z(e)||t.tag===R.float||t.tag===R.int;case R.boolean:case R.symbol:case R.string:case R.bigint:case R.int:case R.float:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===z(e);case R.unknown:return!0;case R.date:case R.file:case R.void:return t.tag===e.tag;case R.optional:case R.default:case R.set:case R.array:return t.tag===e.tag&&J(e.of,t.of);case R.union:if(t.tag===R.union){for(const n of t.options)if(!J(e,n))return!1;return!0}return e.options.some(e=>J(e,t));case R.tuple:if(t.tag!==R.tuple)return!1;for(let n=0;n<e.elements.length;n++)if(!J(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(t.tag!==R.object)return!1;for(const n in t.props){if(!e.props[n])return!1;if(!J(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t}}function W(e,t){switch(e.tag){case R.void:return void 0===t;case R.literal:return t===e.value;case R.boolean:return"boolean"==typeof t;case R.number:return"number"==typeof t;case R.bigint:return"bigint"==typeof t;case R.string:return"string"==typeof t;case R.symbol:return"symbol"==typeof t;case R.unknown:return!0;case R.float:return"number"==typeof t&&!isNaN(t);case R.int:return"number"==typeof t&&Number.isInteger(t);case R.date:return t instanceof Date&&!isNaN(t.getTime());case R.tuple:return Array.isArray(t)&&t.length===e.elements.length&&t.every((t,n)=>W(e.elements[n],t));case R.array:return Array.isArray(t)&&t.every(t=>W(e.of,t));case R.set:return t instanceof Set&&Array.from(t).every(t=>W(e.of,t));case R.optional:case R.default:return void 0===t||W(e.of,t);case R.union:return e.options.some(e=>W(e,t));case R.file:return t instanceof File;case R.object:return!(!t||"object"!=typeof t)&&Object.keys(e.props).every(n=>W(e.props[n],t[n]));case R.custom:return e.isType(t)}}function H(e,t){if(W(e,t)){switch(e.tag){case R.custom:if(e.parse)try{return{success:!0,data:e.parse(t)}}catch(n){return{success:!1,error:String(n)}}break;case R.default:return void 0===t?{success:!0,data:e.value}:{success:!0,data:t}}return{success:!0,data:t}}return{success:!1,error:`Value is not a valid '${z(e)}'`}}const X=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,Tag:R,Type:q,deserializeType:G,isExactType:Y,isSubtype:J,isType:W,parseType:H,serializeType:U,typeToString:z},Symbol.toStringTag,{value:"Module"})),Z=Symbol.for("primaryKey");class Q{symbol=Z;genFn;autoGenerate;type;constructor(e,t){if(e){if(e.tag>R.date)throw new n("Invalid Primary Key Type");this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1}else this.autoGenerate=!1,this.type=N()}getType(){return this.type}generator(e){return this.genFn=e,this.autoGenerate=!0,this}autoIncrement(){if(this.type.tag===R.number)return this.genFn=void 0,this.autoGenerate=!0,this;throw new n("Primary key must be a number to use autoIncrement()")}uuid(){if(!window.isSecureContext)throw new Error("Window is not in a secure context");return new Q(K(),A)}date(){return new Q(x(),v)}genKey(){if(this.genFn)return this.genFn();throw new Error("Generator function not defined")}isAutoIncremented(){return this.autoGenerate&&!this.genFn}static is(e){return e?.symbol===Z}static compareKeyValue(e,t){if(typeof e!=typeof t)return!1;switch(typeof e){case"string":case"number":return e===t;case"object":return e.getTime()===t.getTime();default:return!1}}static validKeyTag=C([K(),N(),x()])}class ee{constructor(e,t="",n=!1,r=!1,s){this.to=e,this.name=t,this.isOptional=n,this.isArray=r,this.relatedKey="",this.actions={onDelete:s||"Restrict"}}static SYMBOL=Symbol.for("baseRelation");BASE_SYMBOL=ee.SYMBOL;actions;relatedKey;getActions(){return{...this.actions}}isNullable(){return this.isArray||this.isOptional}setRelatedKey(e){this.relatedKey=e}getRelatedKey(){return this.relatedKey}toString(){return`${this.isArray?"Array":this.isOptional?"Optional":"Standard"} relation from this model to model '${this.to}' on key '${this.relatedKey}'`}getBaseSymbol(){return this.BASE_SYMBOL}static is(e){return"getBaseSymbol"in e&&e.getBaseSymbol()===ee.SYMBOL}}class te extends ee{static R_SYMBOL=Symbol.for("relation");symbol=te.R_SYMBOL;constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new ne(this.to,this.name,e)}optional({onDelete:e}={}){return new re(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}static is(e){return e?.symbol===this.R_SYMBOL}}class ne extends ee{static A_SYMBOL=Symbol.for("arrayRelation");symbol=ne.A_SYMBOL;constructor(e,t,n="None"){super(e,t,!1,!0,n)}static is(e){return e?.symbol===this.A_SYMBOL}}class re extends ee{static O_SYMBOL=Symbol.for("optionalRelation");symbol=re.O_SYMBOL;constructor(e,t,n="None"){super(e,t,!0,!1,n)}static is(e){return e?.symbol===this.O_SYMBOL}}var se=/* @__PURE__ */(e=>(e[e.Property=0]="Property",e[e.Relation=1]="Relation",e[e.PrimaryKey=2]="PrimaryKey",e[e.Invalid=3]="Invalid",e))(se||{});const ae=Symbol.for("property");class oe{constructor(e,t){this.type=e,this.options={unique:t?.unique??!1}}symbol=ae;hasDefault=!1;options;unique(){switch(this.type.tag){case R.boolean:case R.string:case R.number:case R.symbol:return this.options.unique=!0,this;default:throw new Error("A non-primitive cannot be a unique value")}}hasDefaultValue(){return this.hasDefault}static relation(e,t){return new te(e,t)}static primaryKey(e="number"){return new Q(this.nameToType(e))}static nameToType(e){switch(e){case"boolean":return D();case"bigint":return T();case"number":return N();case"string":return K();case"symbol":return M();default:return _()}}static is(e){return"object"==typeof e&&e?.symbol===ae}array(){return new oe(F(this.type),this.options)}default(e){return this.hasDefault=!0,new oe(E(this.type,e),this.options)}optional(){return new oe(B(this.type),this.options)}static array(e,t){return new oe(F(e.type),t)}static boolean(e){return new oe(D(),e)}static custom(e,t){return new oe(V({isType:t=>e(t).success,serialize:t?.serialize,deserialize:t?.deserialize}),t)}static date(e){return new oe(x(),e)}static file(e){return new oe(I(),e)}static literal(e,t){return new oe(P(e),t)}static number(e){return new oe(N(),e)}static string(e){return new oe(K(),e)}static set(e,t){return new oe(L(e.type),t)}static union(e,t){return new oe(C(e.map(e=>e.type)),t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const n=[];for(const r of t){const t=e(r);if(!t.success)return t;n.push(t.data)}return{success:!0,data:n}}return{success:!1,error:"Value is not an array"}}}}const ie=Symbol.for("model");class ce{constructor(t,n){this.name=t,this.fields=n,this.fieldKeys=b(n);for(const e of this.fieldKeys){const t=this.fields[e];ee.is(t)&&t.to!==this.name&&this.relationLinks.add(t.to)}const r=this.fieldKeys.find(e=>Q.is(this.fields[e]));if(!r)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=r}symbol=ie;fieldKeys;relationLinks=/* @__PURE__ */new Set;cache={};primaryKey;get(e){return this.fields[e]}getPrimaryKey(){return this.fields[this.primaryKey]}defineKeyGen(e){return this.getPrimaryKey().generator(e),this}getRelation(e){const t=this.fields[e];if(t&&ee.is(t))return t}keyType(e){const t=this.fields[e];return t?oe.is(t)?se.Property:ee.is(t)?se.Relation:Q.is(t)?se.PrimaryKey:se.Invalid:se.Invalid}links(){return this.relationLinks.keys()}*relations(){for(const e of this.fieldKeys)ee.is(this.fields[e])&&(yield[e,this.fields[e]])}*entries(){for(const e of this.fieldKeys)yield[e,this.fields[e]]}keys(){return this.fieldKeys}parseField(e,t){return oe.is(this.fields[e])?H(this.fields[e].type,t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=/* @__PURE__ */new Set,n=[this.name];let r;for(;n.length>0;){const s=n.shift();if(t.has(s))continue;r=e.getModel(s);const a=r.cache.delete;if(a)k(t,a);else{t.add(s);for(const e of r.links())t.has(e)||n.push(e)}}return this.cache.delete=t,t}static is(e){return e?.symbol===ie}}class ue{constructor(e,t){this.tx=e,this.internal=t}add(e){return this.handleRequest(this.internal.add(e),()=>new f)}get(e){return this.handleRequest(this.internal.get(e),()=>new d)}async assertGet(e){const t=await this.handleRequest(this.internal.get(e),()=>new d);if(!t)throw this.tx.abort(new u);return t}put(e){return this.handleRequest(this.internal.put(e),()=>new l)}delete(e){return this.handleRequest(this.internal.delete(e),()=>new i)}async openCursor(t,n={}){const r=n.onError||(()=>new y),s=this.internal.openCursor(n.query,n.direction);await new Promise((n,a)=>{s.onsuccess=async s=>{try{s.target||a(this.tx.abort(r()));const e=s.target.result;e&&await t(e,this.tx)||n()}catch(i){a(this.tx.abort(i instanceof e?i:new o(String(i))))}},s.onerror=()=>{a(this.tx.abort(r()))}})}handleRequest(e,t){return new Promise(n=>{e.onsuccess=()=>{n(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class le{internal;status;error=null;storeNames;inWrap=!1;onRejection=t=>{throw t instanceof e?this.abort(t):this.abort(new o(String(t)))};objectStores;constructor(e,t,n,r={}){e instanceof le?(this.internal=e.getInternal(),this.storeNames=e.storeNames,this.status=e.status,this.error=e.error,this.objectStores=e.getAllStores()):(this.internal=e.transaction(t,n),this.status=0,this.storeNames=Array.from(this.internal.objectStoreNames),this.objectStores=new Map(this.storeNames.map(e=>[e,this.getObjectstore(e)])),this.internal.onabort=this.registerHandler(1,r.onAbort),this.internal.onerror=this.registerHandler(3,r.onError),this.internal.oncomplete=this.registerHandler(2,r.onComplete))}static create(e,t,n,r){return r||new le(e,t,n)}abort(e){return 1!==this.status&&this.internal.abort(),this.status=1,this.error=e,this.error}commit(){this.internal.commit()}getInternal(){return this.internal}getStore(e){const t=this.objectStores.get(e);if(!t)throw this.abort(new r(`Store '${e}' is not a part of this transaction`));return t}getAllStores(){return this.objectStores}get mode(){return this.internal.mode}is(e){return this.status===e}contains(e){Array.isArray(e)||(e=[e]);for(const t of e)if(!this.internal.objectStoreNames.contains(t))return!1;return!0}assertIsArray(e,t="Value is not an array"){if(!Array.isArray(e))throw this.abort(new a(t))}getObjectstore(e){try{return new ue(this,this.internal.objectStore(e))}catch{throw this.abort(new c(`No ObjectStore with the name '${e}' found`))}}registerHandler(e,t=()=>{}){return n=>{this.status=e,t(this,n)}}async wrap(t){if(this.inWrap)return await t(this);this.inWrap=!0;try{const e=await t(this);return this.inWrap=!1,e}catch(n){throw this.inWrap=!1,n instanceof e?this.abort(n):this.abort(new o(JSON.stringify(n)))}}}function fe(e){if(!e)return[];const t=[];for(const n in e)if(Object.hasOwn(e,n))switch(typeof e[n]){case"function":t.push([n,!0,e[n]]);break;case"object":if(e[n]instanceof Date){const r=e[n];t.push([n,!0,e=>e instanceof Date&&e.getTime()===r.getTime()])}break;default:t.push([n,!1,e[n]])}return t}function ye(e,t){if(!t||"object"!=typeof t)return!1;for(const n of e)if(n[1]){if(!n[2](t[n[0]]))return!1}else if(n[2]!==t[n[0]])return!1;return!0}function de(e,t,n={},r){const a=t.getModel(e);if(n.include&&n.select)throw new s("include and select cannot both be defined");const o=fe(n.where),i=n.select?"select":n.include?"include":"";if(i){const e=n[i],r=!!n.select,s=[];for(const n in e)if(Object.hasOwn(e,n)&&e[n])switch(a.keyType(n)){case se.Relation:{const r=a.getRelation(n),o="object"==typeof e[n]?de(r.to,t,e[n]):$,i=r.getRelatedKey();if(r.isArray){const e=async(e,t)=>{const n=[],s=t.getStore(r.to);for(const r of e){const e=await o(await s.assertGet(r),t);e&&(delete e[i],n.push(e))}return n};s.push({key:n,getValue:e})}else{const e=async(e,t)=>await o(await t.getStore(r.to).assertGet(e),t);s.push({key:n,getValue:e})}break}case se.Property:case se.PrimaryKey:r&&s.push({key:n})}return r?async(e,t)=>{if(!ye(o,e))return;const n={};for(const{key:r,getValue:a}of s)n[r]=a?await a(e[r],t):e[r];return n}:async(e,t)=>{if(ye(o,e)){for(const{key:n,getValue:r}of s)e[n]=await r(e[n],t);return e}}}return e=>ye(o,e)?e:void 0}function he(e,t,n,r){const s=/* @__PURE__ */new Set([e]);if(n){const a=r.getModel(e);for(const e in t){const o=a.getRelation(e),i=S(t[e]);if(o)for(const e of i)if(e&&"object"==typeof e)for(const t in e)if(Object.hasOwn(e,t))switch(t){case"$connect":case"$connectMany":case"$disconnect":case"$disconnectMany":case"$disconnectAll":s.add(o.to);break;case"$delete":case"$deleteMany":case"$deleteAll":k(s,a.getDeletedStores(r));break;case"$create":k(s,he(o.to,e[t],n,r));break;case"$createMany":e[t].forEach(e=>k(s,he(o.to,e,n,r)));break;case"$update":k(s,he(o.to,e[t].data,n,r));break;case"$updateMany":e[t].forEach(e=>k(s,he(o.to,e.data,n,r)))}}}else{const n=r.getModel(e);for(const e in t){const a=n.getRelation(e);if(a)switch(typeof t[e]){case"object":k(s,he(a.to,pe(t[e]),!1,r));break;case"boolean":s.add(a.to)}}}return s}function pe(e){return e.select?e.select:e.include?e.include:{}}class we{constructor(e,t,n){this.client=e,this.name=t,this.accessedStores=Array.from(he(t,pe(n),!1,this.client)),this.selectClause=de(t,this.client,n)}accessedStores;selectClause;async find(){return await this._find(!1)}async findFirst(){return(await this._find(!0))[0]}async _find(e){const t=this.client.createTransaction("readonly",this.accessedStores);return await t.wrap(async t=>{const n=[],r=t.getStore(this.name);return await r.openCursor(async r=>{const s=await this.selectClause(r.value,t);return s&&n.push(s),(!e||!n.length)&&(r.continue(),!0)}),n})}}function me(e,t,r){return async s=>{if(!s)return!1;const a=s[e.primaryKey];for(const[o,c]of e.relations()){const{onDelete:u}=c.getActions(),l=s[o],f=t.getModel(c.to);switch(u){case"Cascade":if(c.isArray){r.assertIsArray(l);const e=new Set(l),n=me(f,t,r),s=r.getStore(c.to);await s.openCursor(async t=>(e.has(t.value[f.primaryKey])&&await n(t.value),t.continue(),!0)).catch(r.onRejection)}else l&&await ge(c.to,t,void 0,void 0,{tx:r,singleton:{id:l}});break;case"SetNull":{if(!l)break;const e=S(l),t=r.getStore(c.to),s=c.getRelatedKey(),o=f.getRelation(s);if(!o)throw new n(`Relation '${c.name}' has an invalid relation key '${c.getRelatedKey()}'`);if(!o.isNullable())throw new n(`Key '${s}' on model '${s}': Non-optional relation cannot have the 'SetNull' action`);for(const n of e){const e=await t.get(n);if(!e)continue;const i=e[s];if(o.isArray){r.assertIsArray(i);const e=i.indexOf(a);if(-1===e)continue;i.splice(e,1)}else e[s]=null;await t.put(e)}break}case"Restrict":if(Array.isArray(l)&&l.length>0||l)throw new i(`Key '${o}' on model '${e.name}' deletion is restricted while there is an active relation`)}}return!0}}async function ge(e,t,n,r=!1,s={}){const{singleton:a,finalStep:o=!0}=s,i=t.getModel(e),c=s.tx?s.tx.storeNames:Array.from(i.getDeletedStores(t)),u=le.create(t.getDb(),c,"readwrite",s.tx);return await u.wrap(async s=>{const c=s.getStore(e);let u=0;const l=me(i,t,s);if(a)await l(await c.assertGet(a.id))&&(await c.delete(a.id),u++);else{const e=fe(n);let t;await c.openCursor(async n=>{const a=n.value;return ye(e,a)&&await l(a)&&(t=g(n.delete()).catch(s.onRejection)),!(r&&u>0)&&(n.continue(),!0)}),t&&o&&await t}return u})}function be(e){return"string"!=typeof e?String(e):e.replaceAll(/~|\//g,e=>"~"===e?"~0":"~1")}async function Se(e,t,n,r){r=le.create(e.getDb(),[t],"readonly",r);const s=fe(n),o=e.getModel(t);return await r.wrap(async e=>{const n={};return await e.getStore(t).openCursor(async e=>{if(ye(s,e.value)){for(const[t,n]of o.entries())if(ee.is(n))if(n.isArray){if(!Array.isArray(e.value[t]))throw new a("Expected array type");const r=[];for(const s of e.value[t])r.push(`/${n.to}/${be(s)}`);e.value[t]=r}else(n.isOptional&&e.value[t]||!n.isNullable())&&(e.value[t]=`/${n.to}/${be(e.value[t])}`);else{if(!oe.is(n)&&!Q.is(n))throw new p(`Unrecognized model field on key '${t}'`);e.value[t]=await U(n.type,e.value[t])}if(n[e.value[o.primaryKey]])throw new p("Duplicate primary key detected "+JSON.stringify(n));n[e.value[o.primaryKey]]=e.value}return e.continue(),!0}),n})}function Ae(e,t){const n=[`## ${e.name}`],r=[];for(const[s,a]of e.entries())Q.is(a)?r.unshift(s):r.push(s);n.push(r.join(","));for(const s of Object.values(t)){const e=[];for(const t of r)switch(typeof s[t]){case"object":e.push(JSON.stringify(s[t]));break;case"undefined":e.push("");break;default:e.push(String(s[t]))}n.push(e.join(","))}return n.join("\n")}class ve{constructor(e,t,n){this.name=e,this.content=t,this.extension=n}toFile(e=`${this.name}_dump.${this.extension}`,t){return new File([this.content],e,t)}download(e=`${this.name}_dump.${this.extension}`,t){const n=URL.createObjectURL(this.toFile(e,t)),r=document.createElement("a");r.href=n,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(n)}static toJson(e,t,n){return new this(e,JSON.stringify(t,void 0,n?.pretty??1?4:void 0),"json")}static toCsvStore(e,t){return new this(e.name,Ae(e,t),"csv")}static toCsvDb(e,t,n){const r=[`# ${e.name}`];for(const s of t)r.push(Ae(e.getModel(s),n[s]));return new this(e.name,r.join("\n"),"csv")}}class $e{constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const n of this.models.keys())this.stores[n]=this.createInterface(n)}name;version;stores;getDb(){return this.db}getStore(e){return this.stores[e]}getStoreNames(){return this.models.keys()}createTransaction(e,t,n){return new le(this.db,t,e,n)}async drop(){await g(window.indexedDB.deleteDatabase(this.name))}async dump(e,t,n){const r=await async function(e,t){const n={};t=t||e.getStoreNames();const r=e.createTransaction("readonly",t);for(const s of t)n[s]=await Se(e,s,void 0,r);return n}(this,t);switch(e){case"json":return ve.toJson(this.name,r,n);case"csv":return ve.toCsvDb(this,t||this.getStoreNames(),r)}}deleteAllStores(){for(const e of this.models.keys())this.db.deleteObjectStore(e)}deleteStore(e){Array.isArray(e)||(e=[e]);for(const t of e)this.db.deleteObjectStore(t)}getModel(e){const t=this.models.getModel(e);if(!t)throw new c(`Model with name '${e}' not found`);return t}getAccessedStores(e,t,n,r){return r?r.storeNames:Array.from(he(e,t,n,this))}createInterface(e){return{add:async(t,n)=>await this.add(e,t,{tx:n}),addMany:async(t,n)=>{if(!n){const r=/* @__PURE__ */new Set;for(const n of t)k(r,he(e,n,!0,this));n=this.createTransaction("readwrite",Array.from(r))}const r=[];for(const s of t)r.push(await this.add(e,s,{tx:n}));return r},findFirst:async(t,n)=>(await this.find(e,t,!0,{tx:n}))[0],find:async(t,n)=>await this.find(e,t,!1,{tx:n}),get:async t=>{const n=this.createTransaction("readonly",e);return await n.getStore(e).get(t)},update:async(t,n)=>(await this.update(e,{data:n},!0,{singleton:{id:t}}))[0],updateFirst:async(t,n)=>(await this.update(e,t,!0,{tx:n}))[0],updateMany:async(t,n)=>await this.update(e,t,!1,{tx:n}),compileQuery:t=>new we(this,e,t),delete:async t=>await ge(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await ge(e,this,t,!0)>0,deleteMany:async t=>await ge(e,this,t,!1),dump:async(t,n,r)=>{const s=await Se(this,e,n);switch(t){case"json":return ve.toJson(e,s,r);case"csv":return ve.toCsvStore(this.getModel(e),s)}}}}async add(e,t,n={}){let{tx:r}=n;const{relation:a}=n,i=this.getAccessedStores(e,t,!0,r);return r=le.create(this.db,i,"readwrite",r),await r.wrap(async n=>{const r=n.getStore(e),i=this.getModel(e),c=i.getPrimaryKey(),u=a?{[a.key]:i.getRelation(a.key)?.isArray?[a.id]:a.id}:{},l=c.isAutoIncremented()?{...u}:{...u,[i.primaryKey]:t[i.primaryKey]??c.genKey()},f=await r.add(l),y={},d=/* @__PURE__ */new Set;for(const a in t){d.add(a);const r=t[a];switch(i.keyType(a)){case se.Invalid:throw new s(`Key '${a}' does ont exist on model '${e}'`);case se.Property:{const e=i.parseField(a,r);if(!e)throw new o;if(!e.success)throw new s(`Key '${a}' has the following validation error: ${e.error}`);y[a]=e.data;break}case se.Relation:{if(!r)continue;const e=S(r),t=i.getRelation(a);if(t.isArray&&(y[a]=[],"$createMany"in r||"$connectMany"in r)){const t=[];for(const e of r.$createMany??[])t.push({$create:e});for(const e of r.$connectMany??[])t.push({$connect:e});e.push(...t)}const o=this.getModel(t.to).getRelation(t.getRelatedKey()),c=/* @__PURE__ */new Set;for(const r of e){const e=b(r)[0];if(!e)throw new s(`Key '${a}' cannot be an empty connection object`);switch(e){case"$connect":{const i=r[e];if(c.has(i))throw new s(`Primary key '${i}' was already used for a connection`);if(c.add(i),!o)throw new s(`Could not find corresponding relation '${t.name}'`);await this.connectDocument(t,f,i,n),t.isArray?y[a].push(i):y[a]=i;break}case"$create":{const s=await this.add(t.to,r[e],{tx:n,relation:{id:f,key:t.getRelatedKey()}});t.isArray?y[a].push(s):y[a]=s;break}case"$connectMany":case"$createMany":break;default:throw new s(`Connection Object on key '${a}' has an unknown key '${e}'`)}if(!t.isArray)break}break}case se.PrimaryKey:}}const h=Array.from(new Set(i.keys()).difference(d));for(const e of h)switch(i.keyType(e)){case se.Property:{const t=i.parseField(e,void 0);if(!t)throw new o("A parsing error occurred");if(!t.success)throw new s(`Key '${e}' is missing`);y[e]=t.data;break}case se.Relation:{const t=i.getRelation(e),n=u[e];if(t.isArray)y[e]=n??[];else if(t.isOptional)y[e]=n??null;else{if(!n)throw new s(`Required relation '${e}' is not defined`);y[e]=n}break}case se.Invalid:case se.PrimaryKey:}return await r.put({[i.primaryKey]:f,...y})})}async clear(e,t){await ge(e,this,void 0,!1,t)}async find(e,t,n,r={}){let{tx:s}=r;const a=this.getAccessedStores(e,pe(t),!1,s);s=le.create(this.db,a,"readonly",s);const o=[];return await s.wrap(async r=>{const s=r.getStore(e),a=de(e,this,t);return await s.openCursor(async e=>{const t=await a(e.value,r);return t&&o.push(t),(!n||!o.length)&&(e.continue(),!0)}),o})}async update(e,t,n,r={}){const{singleton:a}=r,i=r.singleton?t:t.data,c=this.getAccessedStores(e,i,!0,r.tx),f=le.create(this.db,c,"readwrite",r.tx);return await f.wrap(async r=>{const c=r.getStore(e),f=this.getModel(e),y=[];for(const e of b(i))switch(f.keyType(e)){case se.Property:y.push({key:e,isRelation:!1,updateFn:"function"==typeof i[e]?i[e]:()=>i[e]});break;case se.Relation:{const t=S(i[e]);if(!t)continue;const n=[];for(const e of t)for(const t in e){switch(t){case"$createMany":case"$connectMany":case"$updateMany":case"$deleteMany":case"$disconnectMany":{const r=t.substring(0,t.length-4);for(const s of e[t])n.push([r,s]);break}default:n.push([t,e[t]])}break}y.push({actions:n,key:e,isRelation:!0,relation:f.getRelation(e)});break}case se.PrimaryKey:throw new l("Primary key field cannot be updated");case se.Invalid:default:throw new o(`Unknown key '${e}'`)}const d=[],h=async e=>{const t=e[f.primaryKey];for(const{key:n,...a}of y){const o=a.relation;if(a.isRelation)for(const[i,c]of a.actions)switch(i){case"$connect":e[n]&&!o.isArray&&await this.disconnectDocument(o,t,e[n],r).catch(r.onRejection),await this.connectDocument(o,t,c,r).catch(r.onRejection),o.isArray?e[n].push(c):e[n]=c;break;case"$create":{const s=await this.add(o.to,c,{tx:r,relation:{id:t,key:o.getRelatedKey()}});o.isArray?e[n].push(s):e[n]=s;break}case"$delete":if(!o.isNullable())throw new s("Item cannot be deleted, relation is required");e[n]=o.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null,await ge(o.to,this,{},!0,{tx:r,singleton:{id:c}});break;case"$disconnect":{if(!o.isNullable())throw new s("Item cannot be disconnected, relation is required");if(!e[n]||0===e[n]?.lenth)break;const a=this.getModel(o.to).getRelation(o.getRelatedKey());await this.disconnectDocument(o,t,a.isArray?c:e[n],r).catch(r.onRejection),e[n]=o.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null;break}case"$update":o.isArray?await this.update(o.to,c,!1,{tx:r}):null!=e[n]&&await this.update(o.to,c,!1,{tx:r,singleton:{id:t}});break;case"$deleteAll":if(c&&o.isArray&&Array.isArray(e[n])){const t=this.getModel(o.to),s=new Set(e[n]);await ge(o.to,this,{[t.primaryKey]:e=>s.has(e)},!1,{tx:r}),e[n]=[]}break;case"$disconnectAll":if(c&&o.isArray&&Array.isArray(e[n])){for(const s of e[n])await this.disconnectDocument(o,t,s,r);e[n]=[]}}else e[n]=a.updateFn(e[n])}return e};if(a){const e=await c.get(a.id);if(!e)throw new u(`${f.name} with priamry key '${a.id}' not found`);const t=await h(e).catch(r.onRejection);return await c.put(t),[t]}{const e=fe(t.where);return await c.openCursor(async t=>{const s=t.value;if(ye(e,s)){const e=await h(s).catch(r.onRejection);if(await g(t.update(e)).then(()=>d.push(e)).catch(r.onRejection),n)return!1}return t.continue(),!0}),d}})}async connectDocument(e,t,n,r){const s=r.getStore(e.to),a=await s.get(n);if(!a)throw new u(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const o=e.getRelatedKey(),i=this.getModel(e.to).getRelation(o),c=a[o];if(i.isArray&&Array.isArray(c))c.includes(t)||c.push(t);else{if(c)throw new h;a[o]=t}return await s.put(a).catch(r.onRejection),n}async disconnectDocument(e,t,n,r){const s=r.getStore(e.to),a=await s.get(n);if(!a)throw new u(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const o=this.getModel(e.to).getRelation(e.getRelatedKey());if(o.isArray)a[e.getRelatedKey()].filter(e=>e!==t);else{if(!o.isOptional)throw new h;a[e.getRelatedKey()]=null}return await s.put(a).catch(r.onRejection),n}}class ke{constructor(e,t){this.name=e,this.names=t,this.models={}}models;defineModel(e,t){if("object"==typeof e&&ce.is(e))return this.models[e.name]=e,e;{if(!t)throw new Error("Model Fields must be defined");const n=new ce(e,t);return this.models[e]=n,n}}compile(e){return new Re(this.name,e)}}class Re{constructor(e,t){this.name=e,this.models=t,this.modelKeys=b(this.models),this.schemas={};for(const r of this.modelKeys){const e=this.models[r],t={};for(const[s,a]of e.entries())if(oe.is(a))t[s]=a.type;else if(ee.is(a)){const{onDelete:o}=a.getActions(),i=this.models[a.to],c=i.getPrimaryKey();t[s]=c.type,a.isOptional?t[s]=B(t[s]):a.isArray&&(t[s]=F(t[s]));let u=!!a.getRelatedKey();if(!u)for(const[t,r]of i.relations())if(s!==t&&r.to===e.name&&r.name===a.name){if(u=!0,a.setRelatedKey(t),r.setRelatedKey(s),"SetNull"===o&&!r.isNullable())throw new n(`Key '${t}' on model '${i.name}': Non-optional relation cannot have the 'SetNull' action`);break}if(!u)throw new n(`Relation '${a.name}' of model ${r} does not have an equivalent relation on model '${a.to}'`)}else{if(!Q.is(a))throw new n(`Unknown field value detected: ${JSON.stringify(a)}`);t[s]=a.type}this.schemas[r]=t}}schemas;modelKeys;getModel(e){return this.models[e]}async createClient(e=1){const t=window.indexedDB.open(this.name,e);t.onupgradeneeded=e=>{const t=e.target.result;for(const n of this.modelKeys){const e=this.models[n];t.objectStoreNames.contains(e.name)||t.createObjectStore(e.name,{autoIncrement:e.getPrimaryKey().isAutoIncremented(),keyPath:e.primaryKey})}};const n=await g(t);return new $e(n,this)}keys(){return[...this.modelKeys]}}const Oe=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,ArrayRelation:ne,BaseRelation:ee,DbClient:$e,FieldTypes:se,Model:ce,OptionalRelation:re,PrimaryKey:Q,Property:oe,Relation:te,Tag:R,Type:q,deserializeType:G,isExactType:Y,isSubtype:J,isType:W,parseType:H,serializeType:U,typeToString:z},Symbol.toStringTag,{value:"Module"}));export{ke as Builder,we as CompiledQuery,ce as Model,oe as Property,e as StoreError,X as Typing,Oe as core};
1
+ class e extends Error{code;constructor(e,t){super(`(${e}) ${t}`),this.code=e}}function t(t,n){return class extends e{static code;constructor(e=n){super(t,e)}static of(e){new this(e)}}}const n=t("INVALID_CONFIG","Configuration is invalid"),r=t("INVALID_TX","Transaction is invalid"),s=t("INVALID_ITEM","Item is invalid"),a=t("ASSERTION_FAILED","Assertion failed"),i=t("UNKNOWN","An unknown error occurred"),o=t("DELETE_FAILED","Item could not be deleted"),c=t("NOT_FOUND","Object Store Not Found"),u=t("NOT_FOUND","Document Not Found"),l=t("UPDATE_FAILED","Item could not be updated"),y=t("ADD_FAILED","Item could not be added"),h=t("OPEN_CURSOR","Cursor could not be opened"),d=t("GET_FAILED","Item could not be retrieved"),f=t("OVERWRITE_RELATION","Relation cannot be overwritten"),p=t("EXPORT","Export failed"),w=t("SERIALIZATION_FAILED","Seralization failed"),m=t("DESERIALIZATION_FAILED","De-seralization failed");function g(e,t){return new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function b(e){return Object.keys(e)}function S(e){return Array.isArray(e)||(e=[e]),e}function A(){return crypto.randomUUID()}function v(){/* @__PURE__ */
2
+ return new Date}function $(e){return e}function k(e,t){for(const n of t.keys())e.add(n);return e}var R=/* @__PURE__ */(e=>(e[e.string=0]="string",e[e.number=1]="number",e[e.date=2]="date",e[e.boolean=3]="boolean",e[e.symbol=4]="symbol",e[e.bigint=5]="bigint",e[e.file=6]="file",e[e.void=7]="void",e[e.float=8]="float",e[e.int=9]="int",e[e.unknown=10]="unknown",e[e.literal=11]="literal",e[e.array=12]="array",e[e.set=13]="set",e[e.union=14]="union",e[e.optional=15]="optional",e[e.default=16]="default",e[e.object=17]="object",e[e.tuple=18]="tuple",e[e.custom=19]="custom",e))(R||{});class j{static cache={};static getType(e){const t=this.cache[e];return t||(this.cache[e]={tag:e})}static string(){return this.getType(R.string)}static number(){return this.getType(R.number)}static boolean(){return this.getType(R.boolean)}static bigint(){return this.getType(R.bigint)}static symbol(){return this.getType(R.symbol)}static int(){return this.getType(R.int)}static float(){return this.getType(R.float)}static void(){return this.getType(R.void)}static file(){return this.getType(R.file)}static date(){return this.getType(R.date)}static unknown(){return this.getType(R.unknown)}static literal(e){return{tag:R.literal,value:e}}static array(e){return{tag:R.array,of:e}}static default(e,t){return{tag:R.default,of:e,value:t}}static set(e){return{tag:R.set,of:e}}static union(e){return{tag:R.union,options:e}}static optional(e){return{tag:R.optional,of:e}}static object(e){return{tag:R.object,props:e}}static tuple(e){return{tag:R.tuple,elements:e}}static custom(e){return{tag:R.custom,...e}}}function O(e){switch(e.tag){case R.void:return"void";case R.literal:return String(e.value);case R.boolean:return"boolean";case R.number:return"number";case R.float:return"float";case R.int:return"integer";case R.bigint:return"bigint";case R.string:return"string";case R.symbol:return"symbol";case R.unknown:return"unknown";case R.date:return"Date";case R.tuple:return`Tuple<${e.elements.map(e=>O(e)).join(", ")}>`;case R.array:return`Array<${O(e.of)}>`;case R.set:return`Set<${O(e.of)}>`;case R.default:case R.optional:return`${O(e.of)} | undefined`;case R.union:return`Union<${e.options.map(e=>O(e)).join(", ")}>`;case R.file:return"File";case R.object:return`{${Object.keys(e.props).map(t=>`${t}: ${O(e.props[t])}`).join(",\n")}}`;case R.custom:return"custom"}}async function K(e,t){if(!M(e,t))throw new w(`Value not of the proper type, expected type '${O(e)}', received '${JSON.stringify(t)}'`);switch(e.tag){case R.literal:case R.boolean:case R.number:case R.float:case R.int:case R.string:return t;case R.void:return;case R.bigint:return Number(t);case R.symbol:return t.description;case R.unknown:return JSON.stringify(t);case R.date:return t.getTime();case R.tuple:{const n=[];for(let r=0;r<t.length;r++)n.push(await K(e.elements[r],t[r]));return n}case R.array:{const n=[];for(const r of t)n.push(K(e.of,r));return await Promise.all(n)}case R.set:{const n=[];for(const r of t.keys())n.push(K(e.of,r));return await Promise.all(n)}case R.optional:if(void 0===t)return;return await K(e.of,t);case R.union:for(const n of e.options)try{return await K(n,t)}catch{}throw new w("Value union could not be serialized");case R.file:if(!(t instanceof File))throw new w("Value is not a valid file");return{data:new Promise((e,n)=>{const r=new FileReader;r.onload=()=>e(r.result),r.onerror=n,r.readAsDataURL(t)}),name:t.name,type:t.type};case R.object:{const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional&&s.tag!==R.default&&s.tag!==R.void)throw new w(`Required property '${r}' not found`);n[r]=await K(s,t[r])}return n}case R.default:return await K(e.of,void 0===t?"function"==typeof e.value?e.value():e.value:t);case R.custom:if(!e.serialize)return JSON.stringify(t);switch(typeof e.serialize){case"object":return await K(e.serialize,t);case"function":return await e.serialize(t);default:throw new w(`Unknown Type Serialize argument '${JSON.stringify(e.serialize)}'`)}}}async function N(e,t){switch(e.tag){case R.void:return;case R.literal:if(t!==e.value)throw new m(`'${t}' is not equal to literal '${t}'`);return t;case R.boolean:if("boolean"!=typeof t)throw new m(`'${t}' is not a boolean`);return t;case R.int:if("number"!=typeof t||!Number.isInteger(t))throw new m(`'${t}' is not an integer`);return t;case R.float:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a float`);return t;case R.number:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a number`);return t;case R.bigint:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a bigint`);return BigInt(t);case R.string:if("string"!=typeof t)throw new m(`'${t}' is not a string`);return t;case R.symbol:if("string"!=typeof t)throw new m(`'${t}' is not a symbol`);return Symbol.for(t);case R.date:if("number"!=typeof t||isNaN(t))throw new m(`'${t}' is not a date timestamp`);return new Date(t);case R.tuple:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(let r=0;r<t.length;r++)n.push(await N(e.elements[r],t[r]));return n}case R.array:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(N(e.of,r));return await Promise.all(n)}case R.set:{if(!Array.isArray(t))throw new m(`'${t}' is not an array`);const n=[];for(const r of t)n.push(N(e.of,r));return new Set(await Promise.all(n))}case R.optional:if(void 0===t)return;return N(e.of,t);case R.unknown:return"string"!=typeof t?t:JSON.parse(t);case R.union:for(const n of e.options)try{return await N(n,t)}catch{}throw new m("Value did not match the union");case R.file:{if(!(t&&"object"==typeof t&&"data"in t&&"name"in t&&"type"in t&&"string"==typeof t.data&&"string"==typeof t.name&&"string"==typeof t.type))throw new m("Value is not a valid file schema");const e=Buffer.from(t.data.replace(/^data:.+;base64,/,""),"base64");return new File([e],t.name,{type:t.type})}case R.default:return void 0===t?e.value:N(e.of,t);case R.custom:if(!e.isType(t))throw new m("Value is not valid");if(!e.deserialize)return JSON.parse(String(t));switch(typeof e.deserialize){case"object":return await N(e.deserialize,t);case"function":return await e.deserialize(t);default:throw new m(`Unknown Type Deserialize argument '${JSON.stringify(e.deserialize)}'`)}case R.object:{if(!t||"object"!=typeof t)throw new m("Value is not an object");const n={};for(const r in e.props){const s=e.props[r];if(!(r in t)&&s.tag!==R.optional)throw new m(`Required property '${r}' not found`);n[r]=await N(s,t[r])}return n}}}function T(e,t){if(e.tag!==t.tag)return!1;switch(e.tag){case R.literal:return e.value===t.value;case R.optional:case R.default:case R.set:case R.array:return T(e.of,t.of);case R.union:if(e.options.length!==t.options.length)return!1;for(let n=0;n<e.options.length;n++)if(!T(e.options[n],t.options[n]))return!1;return!0;case R.tuple:if(e.elements.length!==t.elements.length)return!1;for(let n=0;n<e.elements.length;n++)if(!T(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(Object.keys(e.props).length!==Object.keys(t.props).length)return!1;for(const n in e.props){if(!(n in t.props))return!1;if(!T(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t;default:return!0}}function D(e,t){switch(e.tag){case R.literal:return t.tag===R.literal&&t.value===e.value;case R.number:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===O(e)||t.tag===R.float||t.tag===R.int;case R.boolean:case R.symbol:case R.string:case R.bigint:case R.int:case R.float:return t.tag===e.tag||t.tag===R.literal&&typeof t.value===O(e);case R.unknown:return!0;case R.date:case R.file:case R.void:return t.tag===e.tag;case R.optional:case R.default:case R.set:case R.array:return t.tag===e.tag&&D(e.of,t.of);case R.union:if(t.tag===R.union){for(const n of t.options)if(!D(e,n))return!1;return!0}return e.options.some(e=>D(e,t));case R.tuple:if(t.tag!==R.tuple)return!1;for(let n=0;n<e.elements.length;n++)if(!D(e.elements[n],t.elements[n]))return!1;return!0;case R.object:if(t.tag!==R.object)return!1;for(const n in t.props){if(!e.props[n])return!1;if(!D(e.props[n],t.props[n]))return!1}return!0;case R.custom:return e===t}}function M(e,t){switch(e.tag){case R.void:return void 0===t;case R.literal:return t===e.value;case R.boolean:return"boolean"==typeof t;case R.number:return"number"==typeof t;case R.bigint:return"bigint"==typeof t;case R.string:return"string"==typeof t;case R.symbol:return"symbol"==typeof t;case R.unknown:return!0;case R.float:return"number"==typeof t&&!isNaN(t);case R.int:return"number"==typeof t&&Number.isInteger(t);case R.date:return t instanceof Date&&!isNaN(t.getTime());case R.tuple:return Array.isArray(t)&&t.length===e.elements.length&&t.every((t,n)=>M(e.elements[n],t));case R.array:return Array.isArray(t)&&t.every(t=>M(e.of,t));case R.set:return t instanceof Set&&Array.from(t).every(t=>M(e.of,t));case R.optional:case R.default:return void 0===t||M(e.of,t);case R.union:return e.options.some(e=>M(e,t));case R.file:return t instanceof File;case R.object:return!(!t||"object"!=typeof t)&&Object.keys(e.props).every(n=>M(e.props[n],t[n]));case R.custom:return e.isType(t)}}function I(e,t){if(M(e,t)){switch(e.tag){case R.custom:if(e.parse)try{return{success:!0,data:e.parse(t)}}catch(n){return{success:!1,error:String(n)}}break;case R.default:return void 0===t?{success:!0,data:e.value}:{success:!0,data:t}}return{success:!0,data:t}}return{success:!1,error:`Value is not a valid '${O(e)}'`}}const x=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,Tag:R,Type:j,deserializeType:N,isExactType:T,isSubtype:D,isType:M,parseType:I,serializeType:K,typeToString:O},Symbol.toStringTag,{value:"Module"})),P=Symbol.for("primaryKey");class F{symbol=P;genFn;autoGenerate;type;constructor(e,t){if(e){if(e.tag>R.date)throw new n("Invalid Primary Key Type");this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1}else this.autoGenerate=!1,this.type=j.number()}getType(){return this.type}generator(e){return this.genFn=e,this.autoGenerate=!0,this}autoIncrement(){if(this.type.tag===R.number)return this.genFn=void 0,this.autoGenerate=!0,this;throw new n("Primary key must be a number to use autoIncrement()")}uuid(){if(!window.isSecureContext)throw new Error("Window is not in a secure context");return new F(j.string(),A)}date(){return new F(j.date(),v)}genKey(...e){if(this.genFn)return this.genFn(...e);throw new Error("Generator function not defined")}isAutoIncremented(){return this.autoGenerate&&!this.genFn}static is(e){return e?.symbol===P}static compareKeyValue(e,t){if(typeof e!=typeof t)return!1;switch(typeof e){case"string":case"number":return e===t;case"object":return e.getTime()===t.getTime();default:return!1}}static validKeyTag=j.union([j.string(),j.number(),j.date()])}class _{constructor(e,t="",n=!1,r=!1,s){this.to=e,this.name=t,this.isOptional=n,this.isArray=r,this.relatedKey="",this.actions={onDelete:s||"Restrict"}}static SYMBOL=Symbol.for("baseRelation");BASE_SYMBOL=_.SYMBOL;actions;relatedKey;getActions(){return{...this.actions}}isNullable(){return this.isArray||this.isOptional}setRelatedKey(e){this.relatedKey=e}getRelatedKey(){return this.relatedKey}tostring(){return`${this.isArray?"Array":this.isOptional?"Optional":"Standard"} relation from this model to model '${this.to}' on key '${this.relatedKey}'`}getBaseSymbol(){return this.BASE_SYMBOL}static is(e){return"getBaseSymbol"in e&&e.getBaseSymbol()===_.SYMBOL}}class E extends _{static R_SYMBOL=Symbol.for("relation");symbol=E.R_SYMBOL;constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new L(this.to,this.name,e)}optional({onDelete:e}={}){return new C(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}static is(e){return e?.symbol===this.R_SYMBOL}}class L extends _{static A_SYMBOL=Symbol.for("arrayRelation");symbol=L.A_SYMBOL;constructor(e,t,n="None"){super(e,t,!1,!0,n)}static is(e){return e?.symbol===this.A_SYMBOL}}class C extends _{static O_SYMBOL=Symbol.for("optionalRelation");symbol=C.O_SYMBOL;constructor(e,t,n="None"){super(e,t,!0,!1,n)}static is(e){return e?.symbol===this.O_SYMBOL}}var z=/* @__PURE__ */(e=>(e[e.Property=0]="Property",e[e.Relation=1]="Relation",e[e.PrimaryKey=2]="PrimaryKey",e[e.Invalid=3]="Invalid",e))(z||{});const B=Symbol.for("property");class V{constructor(e,t){this.type=e,this.options={unique:t?.unique??!1}}symbol=B;hasDefault=!1;options;unique(){switch(this.type.tag){case R.boolean:case R.string:case R.number:case R.symbol:return this.options.unique=!0,this;default:throw new Error("A non-primitive cannot be a unique value")}}hasDefaultValue(){return this.hasDefault}static relation(e,t){return new E(e,t)}static primaryKey(e="number"){return new F(this.nameToType(e))}static nameToType(e){switch(e){case"boolean":return j.boolean();case"bigint":return j.bigint();case"number":return j.number();case"string":return j.string();case"symbol":return j.symbol();default:return j.unknown()}}static is(e){return"object"==typeof e&&e?.symbol===B}array(){return new V(j.array(this.type),this.options)}default(e){return this.hasDefault=!0,new V(j.default(this.type,e),this.options)}optional(){return new V(j.optional(this.type),this.options)}static array(e,t){return new V(j.array(e.type),t)}static boolean(e){return new V(j.boolean(),e)}static custom(e,t){return new V(j.custom({isType:t=>e(t).success,serialize:t?.serialize,deserialize:t?.deserialize}),t)}static date(e){return new V(j.date(),e)}static file(e){return new V(j.file(),e)}static literal(e,t){return new V(j.literal(e),t)}static number(e){return new V(j.number(),e)}static string(e){return new V(j.string(),e)}static set(e,t){return new V(j.set(e.type),t)}static union(e,t){return new V(j.union(e.map(e=>e.type)),t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const n=[];for(const r of t){const t=e(r);if(!t.success)return t;n.push(t.data)}return{success:!0,data:n}}return{success:!1,error:"Value is not an array"}}}}const q=Symbol.for("model");class U{constructor(t,n){this.name=t,this.fields=n,this.fieldKeys=b(n);for(const e of this.fieldKeys){const t=this.fields[e];_.is(t)&&t.to!==this.name&&this.relationLinks.add(t.to)}const r=this.fieldKeys.find(e=>F.is(this.fields[e]));if(!r)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=r}symbol=q;fieldKeys;relationLinks=/* @__PURE__ */new Set;cache={};primaryKey;get(e){return this.fields[e]}getPrimaryKey(){return this.fields[this.primaryKey]}getRelation(e){const t=this.fields[e];if(t&&_.is(t))return t}keyType(e){const t=this.fields[e];return t?V.is(t)?z.Property:_.is(t)?z.Relation:F.is(t)?z.PrimaryKey:z.Invalid:z.Invalid}links(){return this.relationLinks.keys()}*relations(){for(const e of this.fieldKeys)_.is(this.fields[e])&&(yield[e,this.fields[e]])}*entries(){for(const e of this.fieldKeys)yield[e,this.fields[e]]}keys(){return this.fieldKeys}parseField(e,t){return V.is(this.fields[e])?I(this.fields[e].type,t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=/* @__PURE__ */new Set,n=[this.name];let r;for(;n.length>0;){const s=n.shift();if(t.has(s))continue;r=e.getModel(s);const a=r.cache.delete;if(a)k(t,a);else{t.add(s);for(const e of r.links())t.has(e)||n.push(e)}}return this.cache.delete=t,t}static is(e){return e?.symbol===q}}class G{constructor(e,t){this.tx=e,this.internal=t}add(e){return this.handleRequest(this.internal.add(e),()=>new y)}get(e){return this.handleRequest(this.internal.get(e),()=>new d)}async assertGet(e){const t=await this.handleRequest(this.internal.get(e),()=>new d);if(!t)throw this.tx.abort(new u);return t}put(e){return this.handleRequest(this.internal.put(e),()=>new l)}delete(e){return this.handleRequest(this.internal.delete(e),()=>new o)}async openCursor(t,n={}){const r=n.onError||(()=>new h),s=this.internal.openCursor(n.query,n.direction);await new Promise((n,a)=>{s.onsuccess=async s=>{try{s.target||a(this.tx.abort(r()));const e=s.target.result;e&&await t(e,this.tx)||n()}catch(o){a(this.tx.abort(o instanceof e?o:new i(String(o))))}},s.onerror=()=>{a(this.tx.abort(r()))}})}handleRequest(e,t){return new Promise(n=>{e.onsuccess=()=>{n(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class J{internal;status;error=null;storeNames;inWrap=!1;onRejection=t=>{throw t instanceof e?this.abort(t):this.abort(new i(String(t)))};objectStores;constructor(e,t,n,r={}){e instanceof J?(this.internal=e.getInternal(),this.storeNames=e.storeNames,this.status=e.status,this.error=e.error,this.objectStores=e.getAllStores()):(this.internal=e.transaction(t,n),this.status=0,this.storeNames=Array.from(this.internal.objectStoreNames),this.objectStores=new Map(this.storeNames.map(e=>[e,this.getObjectstore(e)])),this.internal.onabort=this.registerHandler(1,r.onAbort),this.internal.onerror=this.registerHandler(3,r.onError),this.internal.oncomplete=this.registerHandler(2,r.onComplete))}static create(e,t,n,r){return r||new J(e,t,n)}abort(e){return 1!==this.status&&this.internal.abort(),this.status=1,this.error=e,this.error}commit(){this.internal.commit()}getInternal(){return this.internal}getStore(e){const t=this.objectStores.get(e);if(!t)throw this.abort(new r(`Store '${e}' is not a part of this transaction`));return t}getAllStores(){return this.objectStores}get mode(){return this.internal.mode}is(e){return this.status===e}contains(e){Array.isArray(e)||(e=[e]);for(const t of e)if(!this.internal.objectStoreNames.contains(t))return!1;return!0}assertIsArray(e,t="Value is not an array"){if(!Array.isArray(e))throw this.abort(new a(t))}getObjectstore(e){try{return new G(this,this.internal.objectStore(e))}catch{throw this.abort(new c(`No ObjectStore with the name '${e}' found`))}}registerHandler(e,t=()=>{}){return n=>{this.status=e,t(this,n)}}async wrap(t){if(this.inWrap)return await t(this);this.inWrap=!0;try{const e=await t(this);return this.inWrap=!1,e}catch(n){throw this.inWrap=!1,n instanceof e?this.abort(n):this.abort(new i(JSON.stringify(n)))}}}function Y(e){if(!e)return[];const t=[];for(const n in e)if(Object.hasOwn(e,n))switch(typeof e[n]){case"function":t.push([n,!0,e[n]]);break;case"object":if(e[n]instanceof Date){const r=e[n];t.push([n,!0,e=>e instanceof Date&&e.getTime()===r.getTime()])}break;default:t.push([n,!1,e[n]])}return t}function W(e,t){if(!t||"object"!=typeof t)return!1;for(const n of e)if(n[1]){if(!n[2](t[n[0]]))return!1}else if(n[2]!==t[n[0]])return!1;return!0}function H(e,t,n={},r){const a=t.getModel(e);if(n.include&&n.select)throw new s("include and select cannot both be defined");const i=Y(n.where),o=n.select?"select":n.include?"include":"";if(o){const e=n[o],r=!!n.select,s=[];for(const n in e)if(Object.hasOwn(e,n)&&e[n])switch(a.keyType(n)){case z.Relation:{const r=a.getRelation(n),i="object"==typeof e[n]?H(r.to,t,e[n]):$,o=r.getRelatedKey();if(r.isArray){const e=async(e,t)=>{const n=[],s=t.getStore(r.to);for(const r of e){const e=await i(await s.assertGet(r),t);e&&(delete e[o],n.push(e))}return n};s.push({key:n,getValue:e})}else{const e=async(e,t)=>await i(await t.getStore(r.to).assertGet(e),t);s.push({key:n,getValue:e})}break}case z.Property:case z.PrimaryKey:r&&s.push({key:n})}return r?async(e,t)=>{if(!W(i,e))return;const n={};for(const{key:r,getValue:a}of s)n[r]=a?await a(e[r],t):e[r];return n}:async(e,t)=>{if(W(i,e)){for(const{key:n,getValue:r}of s)e[n]=await r(e[n],t);return e}}}return e=>W(i,e)?e:void 0}function X(e,t,n,r){const s=/* @__PURE__ */new Set([e]);if(n){const a=r.getModel(e);for(const e in t){const i=a.getRelation(e),o=S(t[e]);if(i)for(const e of o)if(e&&"object"==typeof e)for(const t in e)if(Object.hasOwn(e,t))switch(t){case"$connect":case"$connectMany":case"$disconnect":case"$disconnectMany":case"$disconnectAll":s.add(i.to);break;case"$delete":case"$deleteMany":case"$deleteAll":k(s,a.getDeletedStores(r));break;case"$create":k(s,X(i.to,e[t],n,r));break;case"$createMany":e[t].forEach(e=>k(s,X(i.to,e,n,r)));break;case"$update":k(s,X(i.to,e[t].data,n,r));break;case"$updateMany":e[t].forEach(e=>k(s,X(i.to,e.data,n,r)))}}}else{const n=r.getModel(e);for(const e in t){const a=n.getRelation(e);if(a)switch(typeof t[e]){case"object":k(s,X(a.to,Z(t[e]),!1,r));break;case"boolean":s.add(a.to)}}}return s}function Z(e){return e.select?e.select:e.include?e.include:{}}class Q{constructor(e,t,n){this.client=e,this.name=t,this.accessedStores=Array.from(X(t,Z(n),!1,this.client)),this.selectClause=H(t,this.client,n)}accessedStores;selectClause;async find(){return await this._find(!1)}async findFirst(){return(await this._find(!0))[0]}async _find(e){const t=this.client.createTransaction("readonly",this.accessedStores);return await t.wrap(async t=>{const n=[],r=t.getStore(this.name);return await r.openCursor(async r=>{const s=await this.selectClause(r.value,t);return s&&n.push(s),(!e||!n.length)&&(r.continue(),!0)}),n})}}function ee(e,t,r){return async s=>{if(!s)return!1;const a=s[e.primaryKey];for(const[i,c]of e.relations()){const{onDelete:u}=c.getActions(),l=s[i],y=t.getModel(c.to);switch(u){case"Cascade":if(c.isArray){r.assertIsArray(l);const e=new Set(l),n=ee(y,t,r),s=r.getStore(c.to);await s.openCursor(async t=>(e.has(t.value[y.primaryKey])&&await n(t.value),t.continue(),!0)).catch(r.onRejection)}else l&&await te(c.to,t,void 0,void 0,{tx:r,singleton:{id:l}});break;case"SetNull":{if(!l)break;const e=S(l),t=r.getStore(c.to),s=c.getRelatedKey(),i=y.getRelation(s);if(!i)throw new n(`Relation '${c.name}' has an invalid relation key '${c.getRelatedKey()}'`);if(!i.isNullable())throw new n(`Key '${s}' on model '${s}': Non-optional relation cannot have the 'SetNull' action`);for(const n of e){const e=await t.get(n);if(!e)continue;const o=e[s];if(i.isArray){r.assertIsArray(o);const e=o.indexOf(a);if(-1===e)continue;o.splice(e,1)}else e[s]=null;await t.put(e)}break}case"Restrict":if(Array.isArray(l)&&l.length>0||l)throw new o(`Key '${i}' on model '${e.name}' deletion is restricted while there is an active relation`)}}return!0}}async function te(e,t,n,r=!1,s={}){const{singleton:a,finalStep:i=!0}=s,o=t.getModel(e),c=s.tx?s.tx.storeNames:Array.from(o.getDeletedStores(t)),u=J.create(t.getDb(),c,"readwrite",s.tx);return await u.wrap(async s=>{const c=s.getStore(e);let u=0;const l=ee(o,t,s);if(a)await l(await c.assertGet(a.id))&&(await c.delete(a.id),u++);else{const e=Y(n);let t;await c.openCursor(async n=>{const a=n.value;return W(e,a)&&await l(a)&&(t=g(n.delete()).catch(s.onRejection)),!(r&&u>0)&&(n.continue(),!0)}),t&&i&&await t}return u})}function ne(e){return"string"!=typeof e?String(e):e.replaceAll(/~|\//g,e=>"~"===e?"~0":"~1")}async function re(e,t,n,r){r=J.create(e.getDb(),[t],"readonly",r);const s=Y(n),i=e.getModel(t);return await r.wrap(async e=>{const n={};return await e.getStore(t).openCursor(async e=>{if(W(s,e.value)){for(const[t,n]of i.entries())if(_.is(n))if(n.isArray){if(!Array.isArray(e.value[t]))throw new a("Expected array type");const r=[];for(const s of e.value[t])r.push(`/${n.to}/${ne(s)}`);e.value[t]=r}else(n.isOptional&&e.value[t]||!n.isNullable())&&(e.value[t]=`/${n.to}/${ne(e.value[t])}`);else{if(!V.is(n)&&!F.is(n))throw new p(`Unrecognized model field on key '${t}'`);e.value[t]=await K(n.type,e.value[t])}if(n[e.value[i.primaryKey]])throw new p("Duplicate primary key detected "+JSON.stringify(n));n[e.value[i.primaryKey]]=e.value}return e.continue(),!0}),n})}function se(e,t){const n=[`## ${e.name}`],r=[];for(const[s,a]of e.entries())F.is(a)?r.unshift(s):r.push(s);n.push(r.join(","));for(const s of Object.values(t)){const e=[];for(const t of r)switch(typeof s[t]){case"object":e.push(JSON.stringify(s[t]));break;case"undefined":e.push("");break;default:e.push(String(s[t]))}n.push(e.join(","))}return n.join("\n")}class ae{constructor(e,t,n){this.name=e,this.content=t,this.extension=n}toFile(e=`${this.name}_dump.${this.extension}`,t){return new File([this.content],e,t)}download(e=`${this.name}_dump.${this.extension}`,t){const n=URL.createObjectURL(this.toFile(e,t)),r=document.createElement("a");r.href=n,r.download=e,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(n)}static toJson(e,t,n){return new this(e,JSON.stringify(t,void 0,n?.pretty??1?4:void 0),"json")}static toCsvStore(e,t){return new this(e.name,se(e,t),"csv")}static toCsvDb(e,t,n){const r=[`# ${e.name}`];for(const s of t)r.push(se(e.getModel(s),n[s]));return new this(e.name,r.join("\n"),"csv")}}class ie{constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const n of this.models.keys())this.stores[n]=this.createInterface(n)}name;version;stores;getDb(){return this.db}getStore(e){return this.stores[e]}getStoreNames(){return this.models.keys()}createTransaction(e,t,n){return new J(this.db,t,e,n)}async drop(){await g(window.indexedDB.deleteDatabase(this.name))}async dump(e,t,n){const r=await async function(e,t){const n={};t=t||e.getStoreNames();const r=e.createTransaction("readonly",t);for(const s of t)n[s]=await re(e,s,void 0,r);return n}(this,t);switch(e){case"json":return ae.toJson(this.name,r,n);case"csv":return ae.toCsvDb(this,t||this.getStoreNames(),r)}}deleteAllStores(){for(const e of this.models.keys())this.db.deleteObjectStore(e)}deleteStore(e){Array.isArray(e)||(e=[e]);for(const t of e)this.db.deleteObjectStore(t)}getModel(e){const t=this.models.getModel(e);if(!t)throw new c(`Model with name '${e}' not found`);return t}getAccessedStores(e,t,n,r){return r?r.storeNames:Array.from(X(e,t,n,this))}createInterface(e){return{add:async(t,n)=>await this.add(e,t,{tx:n}),addMany:async(t,n)=>{if(!n){const r=/* @__PURE__ */new Set;for(const n of t)k(r,X(e,n,!0,this));n=this.createTransaction("readwrite",Array.from(r))}const r=[];for(const s of t)r.push(await this.add(e,s,{tx:n}));return r},findFirst:async(t,n)=>(await this.find(e,t,!0,{tx:n}))[0],find:async(t,n)=>await this.find(e,t,!1,{tx:n}),get:async t=>{const n=this.createTransaction("readonly",e);return await n.getStore(e).get(t)},update:async(t,n)=>(await this.update(e,{data:n},!0,{singleton:{id:t}}))[0],updateFirst:async(t,n)=>(await this.update(e,t,!0,{tx:n}))[0],updateMany:async(t,n)=>await this.update(e,t,!1,{tx:n}),compileQuery:t=>new Q(this,e,t),delete:async t=>await te(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await te(e,this,t,!0)>0,deleteMany:async t=>await te(e,this,t,!1),dump:async(t,n,r)=>{const s=await re(this,e,n);switch(t){case"json":return ae.toJson(e,s,r);case"csv":return ae.toCsvStore(this.getModel(e),s)}}}}async add(e,t,n={}){let{tx:r}=n;const{relation:a}=n,o=this.getAccessedStores(e,t,!0,r);return r=J.create(this.db,o,"readwrite",r),await r.wrap(async n=>{const r=n.getStore(e),o=this.getModel(e),c=o.getPrimaryKey(),u=a?{[a.key]:o.getRelation(a.key)?.isArray?[a.id]:a.id}:{},l=c.isAutoIncremented()?{...u}:{...u,[o.primaryKey]:t[o.primaryKey]??c.genKey()},y=await r.add(l),h={},d=/* @__PURE__ */new Set;for(const a in t){d.add(a);const r=t[a];switch(o.keyType(a)){case z.Invalid:throw new s(`Key '${a}' does ont exist on model '${e}'`);case z.Property:{const e=o.parseField(a,r);if(!e)throw new i;if(!e.success)throw new s(`Key '${a}' has the following validation error: ${e.error}`);h[a]=e.data;break}case z.Relation:{if(!r)continue;const e=S(r),t=o.getRelation(a);if(t.isArray&&(h[a]=[],"$createMany"in r||"$connectMany"in r)){const t=[];for(const e of r.$createMany??[])t.push({$create:e});for(const e of r.$connectMany??[])t.push({$connect:e});e.push(...t)}const i=this.getModel(t.to).getRelation(t.getRelatedKey()),c=/* @__PURE__ */new Set;for(const r of e){const e=b(r)[0];if(!e)throw new s(`Key '${a}' cannot be an empty connection object`);switch(e){case"$connect":{const o=r[e];if(c.has(o))throw new s(`Primary key '${o}' was already used for a connection`);if(c.add(o),!i)throw new s(`Could not find corresponding relation '${t.name}'`);await this.connectDocument(t,y,o,n),t.isArray?h[a].push(o):h[a]=o;break}case"$create":{const s=await this.add(t.to,r[e],{tx:n,relation:{id:y,key:t.getRelatedKey()}});t.isArray?h[a].push(s):h[a]=s;break}case"$connectMany":case"$createMany":break;default:throw new s(`Connection Object on key '${a}' has an unknown key '${e}'`)}if(!t.isArray)break}break}case z.PrimaryKey:}}const f=Array.from(new Set(o.keys()).difference(d));for(const e of f)switch(o.keyType(e)){case z.Property:{const t=o.parseField(e,void 0);if(!t)throw new i("A parsing error occurred");if(!t.success)throw new s(`Key '${e}' is missing`);h[e]=t.data;break}case z.Relation:{const t=o.getRelation(e),n=u[e];if(t.isArray)h[e]=n??[];else if(t.isOptional)h[e]=n??null;else{if(!n)throw new s(`Required relation '${e}' is not defined`);h[e]=n}break}case z.Invalid:case z.PrimaryKey:}return await r.put({[o.primaryKey]:y,...h})})}async clear(e,t){await te(e,this,void 0,!1,t)}async find(e,t,n,r={}){let{tx:s}=r;const a=this.getAccessedStores(e,Z(t),!1,s);s=J.create(this.db,a,"readonly",s);const i=[];return await s.wrap(async r=>{const s=r.getStore(e),a=H(e,this,t);return await s.openCursor(async e=>{const t=await a(e.value,r);return t&&i.push(t),(!n||!i.length)&&(e.continue(),!0)}),i})}async update(e,t,n,r={}){const{singleton:a}=r,o=r.singleton?t:t.data,c=this.getAccessedStores(e,o,!0,r.tx),y=J.create(this.db,c,"readwrite",r.tx);return await y.wrap(async r=>{const c=r.getStore(e),y=this.getModel(e),h=[];for(const e of b(o))switch(y.keyType(e)){case z.Property:h.push({key:e,isRelation:!1,updateFn:"function"==typeof o[e]?o[e]:()=>o[e]});break;case z.Relation:{const t=S(o[e]);if(!t)continue;const n=[];for(const e of t)for(const t in e){switch(t){case"$createMany":case"$connectMany":case"$updateMany":case"$deleteMany":case"$disconnectMany":{const r=t.substring(0,t.length-4);for(const s of e[t])n.push([r,s]);break}default:n.push([t,e[t]])}break}h.push({actions:n,key:e,isRelation:!0,relation:y.getRelation(e)});break}case z.PrimaryKey:throw new l("Primary key field cannot be updated");case z.Invalid:default:throw new i(`Unknown key '${e}'`)}const d=[],f=async e=>{const t=e[y.primaryKey];for(const{key:n,...a}of h){const i=a.relation;if(a.isRelation)for(const[o,c]of a.actions)switch(o){case"$connect":e[n]&&!i.isArray&&await this.disconnectDocument(i,t,e[n],r).catch(r.onRejection),await this.connectDocument(i,t,c,r).catch(r.onRejection),i.isArray?e[n].push(c):e[n]=c;break;case"$create":{const s=await this.add(i.to,c,{tx:r,relation:{id:t,key:i.getRelatedKey()}});i.isArray?e[n].push(s):e[n]=s;break}case"$delete":if(!i.isNullable())throw new s("Item cannot be deleted, relation is required");e[n]=i.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null,await te(i.to,this,{},!0,{tx:r,singleton:{id:c}});break;case"$disconnect":{if(!i.isNullable())throw new s("Item cannot be disconnected, relation is required");if(!e[n]||0===e[n]?.lenth)break;const a=this.getModel(i.to).getRelation(i.getRelatedKey());await this.disconnectDocument(i,t,a.isArray?c:e[n],r).catch(r.onRejection),e[n]=i.isArray&&Array.isArray(e[n])?e[n].filter(e=>e!==c):null;break}case"$update":i.isArray?await this.update(i.to,c,!1,{tx:r}):null!=e[n]&&await this.update(i.to,c,!1,{tx:r,singleton:{id:t}});break;case"$deleteAll":if(c&&i.isArray&&Array.isArray(e[n])){const t=this.getModel(i.to),s=new Set(e[n]);await te(i.to,this,{[t.primaryKey]:e=>s.has(e)},!1,{tx:r}),e[n]=[]}break;case"$disconnectAll":if(c&&i.isArray&&Array.isArray(e[n])){for(const s of e[n])await this.disconnectDocument(i,t,s,r);e[n]=[]}}else e[n]=a.updateFn(e[n])}return e};if(a){const e=await c.get(a.id);if(!e)throw new u(`${y.name} with priamry key '${a.id}' not found`);const t=await f(e).catch(r.onRejection);return await c.put(t),[t]}{const e=Y(t.where);return await c.openCursor(async t=>{const s=t.value;if(W(e,s)){const e=await f(s).catch(r.onRejection);if(await g(t.update(e)).then(()=>d.push(e)).catch(r.onRejection),n)return!1}return t.continue(),!0}),d}})}async connectDocument(e,t,n,r){const s=r.getStore(e.to),a=await s.get(n);if(!a)throw new u(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const i=e.getRelatedKey(),o=this.getModel(e.to).getRelation(i),c=a[i];if(o.isArray&&Array.isArray(c))c.includes(t)||c.push(t);else{if(c)throw new f;a[i]=t}return await s.put(a).catch(r.onRejection),n}async disconnectDocument(e,t,n,r){const s=r.getStore(e.to),a=await s.get(n);if(!a)throw new u(`Document with Primary Key '${n}' could not be found in model '${e.to}'`);const i=this.getModel(e.to).getRelation(e.getRelatedKey());if(i.isArray)a[e.getRelatedKey()].filter(e=>e!==t);else{if(!i.isOptional)throw new f;a[e.getRelatedKey()]=null}return await s.put(a).catch(r.onRejection),n}}class oe{constructor(e,t){this.name=e,this.names=t,this.models={}}models;defineModel(e,t){if("object"==typeof e&&U.is(e))return this.models[e.name]=e,e;{if(!t)throw new Error("Model Fields must be defined");const n=new U(e,t);return this.models[e]=n,n}}compile(e){return new ce(this.name,e)}}class ce{constructor(e,t){this.name=e,this.models=t,this.modelKeys=b(this.models),this.schemas={};for(const r of this.modelKeys){const e=this.models[r],t={};for(const[s,a]of e.entries())if(V.is(a))t[s]=a.type;else if(_.is(a)){const{onDelete:i}=a.getActions(),o=this.models[a.to],c=o.getPrimaryKey();t[s]=c.type,a.isOptional?t[s]=j.optional(t[s]):a.isArray&&(t[s]=j.array(t[s]));let u=!!a.getRelatedKey();if(!u)for(const[t,r]of o.relations())if(s!==t&&r.to===e.name&&r.name===a.name){if(u=!0,a.setRelatedKey(t),r.setRelatedKey(s),"SetNull"===i&&!r.isNullable())throw new n(`Key '${t}' on model '${o.name}': Non-optional relation cannot have the 'SetNull' action`);break}if(!u)throw new n(`Relation '${a.name}' of model ${r} does not have an equivalent relation on model '${a.to}'`)}else{if(!F.is(a))throw new n(`Unknown field value detected: ${JSON.stringify(a)}`);t[s]=a.type}this.schemas[r]=t}}schemas;modelKeys;getModel(e){return this.models[e]}async createClient(e=1){const t=window.indexedDB.open(this.name,e);t.onupgradeneeded=e=>{const t=e.target.result;for(const n of this.modelKeys){const e=this.models[n];t.objectStoreNames.contains(e.name)||t.createObjectStore(e.name,{autoIncrement:e.getPrimaryKey().isAutoIncremented(),keyPath:e.primaryKey})}};const n=await g(t);return new ie(n,this)}keys(){return[...this.modelKeys]}}const ue=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,ArrayRelation:L,BaseRelation:_,DbClient:ie,FieldTypes:z,Model:U,OptionalRelation:C,PrimaryKey:F,Property:V,Relation:E,Tag:R,Type:j,deserializeType:N,isExactType:T,isSubtype:D,isType:M,parseType:I,serializeType:K,typeToString:O},Symbol.toStringTag,{value:"Module"}));export{oe as Builder,Q as CompiledQuery,U as Model,V as Property,e as StoreError,x as Typing,ue as core};
@@ -1,7 +1,7 @@
1
1
  import { DbClient } from '../client';
2
- import { BaseRelation, FieldTypes, PrimaryKey, ValidValue, ParseResult, ValidKey, GetPrimaryKeyType } from '../field';
2
+ import { BaseRelation, FieldTypes, PrimaryKey, ValidValue, ParseResult, ValidKey } from '../field';
3
3
  import { Dict, Keyof } from '../util-types';
4
- import { FindPrimaryKey, CollectionObject, RelationlessModelStructure } from './model-types';
4
+ import { FindPrimaryKey, CollectionObject } from './model-types';
5
5
  export default class Model<Name extends string, F extends Record<string, ValidValue>, Primary extends FindPrimaryKey<F> = FindPrimaryKey<F>> {
6
6
  readonly name: Name;
7
7
  private readonly fields;
@@ -19,7 +19,6 @@ export default class Model<Name extends string, F extends Record<string, ValidVa
19
19
  constructor(name: Name, fields: F);
20
20
  get<K extends Keyof<F>>(key: K): F[K];
21
21
  getPrimaryKey(): PrimaryKey<boolean, ValidKey>;
22
- defineKeyGen(genFn: (model: Omit<RelationlessModelStructure<this>, Primary>) => GetPrimaryKeyType<F[Primary]>): this;
23
22
  getRelation<Models extends string>(key: string): BaseRelation<Models, string> | undefined;
24
23
  keyType(key: Keyof<F>): FieldTypes;
25
24
  links<Names extends string = string>(): SetIterator<Names>;
@@ -1,3 +1,3 @@
1
1
  export * from './tag';
2
- export * as Type from './type';
2
+ export { Type } from './type';
3
3
  export * from './utils';
@@ -91,12 +91,12 @@ export interface CustomTag<V = any, PR = any> {
91
91
  tag: Tag.custom;
92
92
  isType: (test: unknown) => boolean;
93
93
  parse?: (test: unknown) => PR;
94
- serialize?: (value: V) => Promisable<unknown>;
95
- deserialize?: (value: unknown) => Promisable<V>;
94
+ serialize?: ((value: V) => Promisable<unknown>) | TypeTag;
95
+ deserialize?: ((value: unknown) => Promisable<V>) | TypeTag;
96
96
  }
97
97
  type Dec = [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
98
98
  export type TypeTag = VoidTag | LiteralTag | StringTag | IntTag | FloatTag | NumberTag | DateTag | BooleanTag | SymbolTag | UnknownTag | FileTag | BigIntTag | SetTag | OptionalTag | UnionTag | ArrayTag | ObjectTag | TupleTag | CustomTag | DefaultTag;
99
- export type TagToType<T extends TypeTag, Depth extends number = 5> = Depth extends 0 ? any : T extends StringTag ? string : T extends NumberTag ? number : T extends BooleanTag ? boolean : T extends LiteralTag<infer V> ? V : T extends DateTag ? Date : T extends SymbolTag ? symbol : T extends UnknownTag ? unknown : T extends FileTag ? File : T extends BigIntTag ? bigint : T extends TupleTag<infer TEls> ? {
99
+ export type TagToType<T extends TypeTag, Depth extends number = 5> = Depth extends 0 ? any : T extends StringTag ? string : T extends NumberTag | IntTag | FloatTag ? number : T extends BooleanTag ? boolean : T extends LiteralTag<infer V> ? V : T extends DateTag ? Date : T extends SymbolTag ? symbol : T extends UnknownTag ? unknown : T extends FileTag ? File : T extends BigIntTag ? bigint : T extends TupleTag<infer TEls> ? {
100
100
  [K in keyof TEls]: TagToType<TEls[K], Dec[Depth]>;
101
101
  } : T extends SetTag<infer T> ? Set<TagToType<T, Dec[Depth]>> : T extends UnionTag<infer TOpts> ? TagToType<TOpts[number], Dec[Depth]> : T extends ArrayTag<infer T> ? TagToType<T, Dec[Depth]>[] : T extends ObjectTag<infer P> ? {
102
102
  [K in keyof P]: TagToType<P[K], Dec[Depth]>;
@@ -13,30 +13,33 @@ interface TypeCache {
13
13
  [Tag.float]: FloatTag;
14
14
  [Tag.unknown]: UnknownTag;
15
15
  }
16
- /**
17
- * Gets a type from the primitive type cache, creating it if it doesn't exist
18
- * @param tag Primitive tag to acquire a type for
19
- * @returns Proper typetag
20
- */
21
- export declare function getType<K extends keyof TypeCache>(tag: K): TypeCache[K];
22
- export declare function String(): StringTag;
23
- export declare function Number(): NumberTag;
24
- export declare function Boolean(): BooleanTag;
25
- export declare function BigInt(): BigIntTag;
26
- export declare function Symbol(): SymbolTag;
27
- export declare function Int(): IntTag;
28
- export declare function Float(): FloatTag;
29
- export declare function Void(): VoidTag;
30
- export declare function File(): FileTag;
31
- export declare function Date(): DateTag;
32
- export declare function Unknown(): UnknownTag;
33
- export declare function Literal<const V extends Literable>(value: V): LiteralTag<V>;
34
- export declare function Array<V extends TypeTag>(element: V): ArrayTag<V>;
35
- export declare function Default<V extends TypeTag>(of: V, value: TagToType<V>): DefaultTag<V>;
36
- export declare function Set<V extends TypeTag>(element: V): SetTag<V>;
37
- export declare function Union<const V extends TypeTag[]>(types: V): UnionTag<V>;
38
- export declare function Optional<V extends TypeTag>(type: V): OptionalTag<V>;
39
- export declare function Object<R extends Record<string, TypeTag>>(props: R): ObjectTag<R>;
40
- export declare function Tuple<const V extends TypeTag[]>(types: V): TupleTag<V>;
41
- export declare function Custom<V>(opts: Omit<CustomTag<V>, "tag">): CustomTag<V>;
16
+ export declare class Type {
17
+ private static readonly cache;
18
+ /**
19
+ * Gets a type from the primitive type cache, creating it if it doesn't exist
20
+ * @param tag Primitive tag to acquire a type for
21
+ * @returns Proper typetag
22
+ */
23
+ static getType<K extends keyof TypeCache>(tag: K): TypeCache[K];
24
+ static string(): StringTag;
25
+ static number(): NumberTag;
26
+ static boolean(): BooleanTag;
27
+ static bigint(): BigIntTag;
28
+ static symbol(): SymbolTag;
29
+ static int(): IntTag;
30
+ static float(): FloatTag;
31
+ static void(): VoidTag;
32
+ static file(): FileTag;
33
+ static date(): DateTag;
34
+ static unknown(): UnknownTag;
35
+ static literal<const V extends Literable>(value: V): LiteralTag<V>;
36
+ static array<V extends TypeTag>(element: V): ArrayTag<V>;
37
+ static default<V extends TypeTag>(of: V, value: TagToType<V>): DefaultTag<V>;
38
+ static set<V extends TypeTag>(element: V): SetTag<V>;
39
+ static union<const V extends TypeTag[]>(types: V): UnionTag<V>;
40
+ static optional<V extends TypeTag>(type: V): OptionalTag<V>;
41
+ static object<R extends Record<string, TypeTag>>(props: R): ObjectTag<R>;
42
+ static tuple<const V extends TypeTag[]>(types: V): TupleTag<V>;
43
+ static custom<V>(opts: Omit<CustomTag<V>, "tag">): CustomTag<V>;
44
+ }
42
45
  export {};
@@ -37,7 +37,7 @@ export type PartialOnUndefined<T extends Dict> = Required<T> & Optional<T>;
37
37
  /**
38
38
  * Types that can be resolved to specific boolean values
39
39
  */
40
- export type BooleanLike = boolean | undefined | null | 0;
40
+ export type BooleanLike = boolean | undefined | null | 0 | "";
41
41
  export type Literable = string | number | bigint | boolean | null | undefined;
42
42
  export type SinglularKey<T extends Record<string, any>> = {
43
43
  [K in keyof T]: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idb-orm/core",
3
- "version": "1.0.15",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",