@idb-orm/core 1.0.6 → 1.0.7

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.
@@ -1,3 +1,4 @@
1
1
  import { ParseFn, AbstractProperty, PropertyOptions } from "./field/property.js";
2
- import type * as util from "./util-types.js";
3
- export { ParseFn, AbstractProperty, util, PropertyOptions };
2
+ import * as util from "./util-types.js";
3
+ import { Type } from "./utils.js";
4
+ export { ParseFn, AbstractProperty, util, PropertyOptions, Type };
package/dist/dev.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { ParseFn, AbstractProperty, PropertyOptions, PropertyInputOptions } from "./field/property.js";
2
+ import { PropertyUnion } from "./field/field-types.js";
3
+ import * as util from "./util-types.js";
4
+ import { Type } from "./utils.js";
5
+ export { ParseFn, AbstractProperty, util, PropertyOptions, Type, PropertyInputOptions, PropertyUnion, };
@@ -6,7 +6,7 @@ import { Relation } from "./relation.js";
6
6
  export interface PropertyOptions {
7
7
  unique: boolean;
8
8
  }
9
- type InputOptions = Partial<PropertyOptions>;
9
+ export type PropertyInputOptions = Partial<PropertyOptions>;
10
10
  export type ParseResult<T> = {
11
11
  success: true;
12
12
  data: T;
@@ -17,25 +17,26 @@ export type ParseResult<T> = {
17
17
  error: string;
18
18
  };
19
19
  /**
20
- * A function to parse and validate an unknown value. It should also handle applying defaults
20
+ * A function to parse and validateFn an unknown value. It should also handle applying defaults
21
21
  */
22
22
  export type ParseFn<T> = (value: unknown) => ParseResult<T>;
23
23
  export declare abstract class AbstractProperty<Value, HasDefault extends boolean> {
24
- readonly validate: (value: unknown) => ParseResult<Value>;
24
+ protected validateFn: (value: unknown) => ParseResult<Value>;
25
25
  protected type: Type;
26
26
  protected hasDefault: HasDefault;
27
27
  protected options: PropertyOptions;
28
- constructor(validate: (value: unknown) => ParseResult<Value>, type: Type, options?: InputOptions);
28
+ constructor(validateFn: (value: unknown) => ParseResult<Value>, type: Type, options?: PropertyInputOptions);
29
+ get validate(): (value: unknown) => ParseResult<Value>;
29
30
  abstract array(...args: unknown[]): AbstractProperty<Value[], false>;
30
31
  abstract optional(...args: unknown[]): AbstractProperty<Value | undefined, false>;
31
- abstract default(defaultValue: Value): AbstractProperty<NoUndefined<Value>, true>;
32
- static array<T>(_prop: AbstractProperty<T, boolean> | ParseFn<T>, _options?: InputOptions): AbstractProperty<T[], false>;
33
- static literal<const V extends Literable>(_value: V, _options?: InputOptions): AbstractProperty<V, false>;
34
- static custom<T>(_fn: ParseFn<T>, _options?: InputOptions): AbstractProperty<T, false>;
35
- static union<const T extends readonly (ParseFn<any> | AbstractProperty<any, boolean>)[]>(_items: T, _options?: InputOptions): AbstractProperty<PropertyUnion<T>, false>;
36
- static string(_options?: InputOptions): AbstractProperty<string, false>;
37
- static number(_options?: InputOptions): AbstractProperty<number, false>;
38
- static boolean(_options?: InputOptions): AbstractProperty<boolean, false>;
32
+ abstract default(defaultValue: NoUndefined<Value>): AbstractProperty<NoUndefined<Value>, true>;
33
+ static array<T>(..._args: unknown[]): AbstractProperty<T[], false>;
34
+ static literal<const V extends Literable>(_item: V, ..._: unknown[]): AbstractProperty<V, false>;
35
+ static custom<T>(..._: unknown[]): AbstractProperty<T, false>;
36
+ static union<const _T extends readonly (ParseFn<any> | AbstractProperty<any, boolean>)[]>(..._: unknown[]): AbstractProperty<unknown, false>;
37
+ static string(..._: unknown[]): AbstractProperty<string, false>;
38
+ static number(..._: unknown[]): AbstractProperty<number, false>;
39
+ static boolean(..._: unknown[]): AbstractProperty<boolean, false>;
39
40
  /**
40
41
  * Indicates that a field must be unique across all documents
41
42
  *
@@ -51,18 +52,18 @@ export declare abstract class AbstractProperty<Value, HasDefault extends boolean
51
52
  date: ParseFn<Date>;
52
53
  };
53
54
  protected static literalToType(value: Literable): Type;
55
+ protected static nameToType(typeName: string): Type;
54
56
  }
55
57
  export declare class Property<Value, HasDefault extends boolean> extends AbstractProperty<Value, HasDefault> {
56
58
  array(): Property<Value[], false>;
57
59
  default(defaultValue: NoUndefined<Value>): Property<NoUndefined<Value>, true>;
58
60
  optional(): Property<Value | undefined, false>;
59
- static literal<const V extends Literable>(value: V, options?: InputOptions): Property<V, false>;
60
- static string(options?: InputOptions): Property<string, false>;
61
- static number(options?: InputOptions): Property<number, false>;
62
- static boolean(options?: InputOptions): Property<boolean, false>;
63
- static union<const T extends readonly (ParseFn<any> | AbstractProperty<any, boolean>)[]>(items: T, options?: InputOptions): Property<PropertyUnion<T>, false>;
64
- static custom<T>(fn: ParseFn<T>, options?: InputOptions): Property<T, false>;
65
- static array<T>(item: ParseFn<T> | Property<T, boolean>, options?: InputOptions): Property<T[], false>;
61
+ static literal<const V extends Literable>(value: V, options?: PropertyInputOptions): Property<V, false>;
62
+ static string(options?: PropertyInputOptions): Property<string, false>;
63
+ static number(options?: PropertyInputOptions): Property<number, false>;
64
+ static boolean(options?: PropertyInputOptions): Property<boolean, false>;
65
+ static union<const T extends readonly (ParseFn<any> | AbstractProperty<any, boolean>)[]>(items: T, options?: PropertyInputOptions): Property<PropertyUnion<T>, false>;
66
+ static custom<T>(fn: ParseFn<T>, options?: PropertyInputOptions): Property<T, false>;
67
+ static array<T>(item: ParseFn<T> | Property<T, boolean>, options?: PropertyInputOptions): Property<T[], false>;
66
68
  private static generateArrayValidator;
67
69
  }
68
- export {};
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Builder } from "./builder.js";
2
2
  import { StoreError, type ErrorType } from "./error.js";
3
- import "./dev-types.js";
3
+ import "./dev.js";
4
4
  export { Builder, StoreError, ErrorType };
5
5
  import { Property } from "./field";
6
6
  export { Property };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- class e extends Error{code;message;constructor(e,t){super(),this.code=e,this.message=t}}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"),s=t("INVALID_TX","Transaction is invalid"),r=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"),l=t("NOT_FOUND","Document Not Found"),u=t("UPDATE_FAILED","Item could not be updated"),d=t("ADD_FAILED","Item could not be added"),h=t("OPEN_CURSOR","Cursor could not be opened"),y=t("GET_FAILED","Item could not be retrieved");async function f(e,t){return await new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function w(e){return Object.keys(e)}function m(e){return Array.isArray(e)||(e=[e]),e}function g(e){switch(e){case"date":return A.Date;case"number":return A.Number;case"string":return A.String}}function b(){return crypto.randomUUID()}function p(e){return e}function k(e,t){for(const n of t.keys())e.add(n);return e}var A;!function(e){e[e.String=0]="String",e[e.Number=1]="Number",e[e.BigInt=2]="BigInt",e[e.Boolean=3]="Boolean",e[e.Symbol=4]="Symbol",e[e.Array=5]="Array",e[e.Date=6]="Date",e[e.Object=7]="Object",e[e.Unknown=8]="Unknown"}(A||(A={}));const S={string:e=>"string"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},number:e=>"number"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},date:e=>e instanceof Date?isNaN(e.getTime())?{success:!1,error:"Value is not a valid date"}:{success:!0,data:e}:{success:!1,error:"Value is not a date"}};class ${genFn;autoGenerate;type;constructor(e,t){e?(this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1):(this.autoGenerate=!1,this.type="number")}autoIncrement(){if("number"===this.type)return this.genFn=void 0,this.autoGenerate=!0,this;const e=new $;return e.genFn=void 0,e.autoGenerate=!0,e}generator(e){return this.genFn=e,this.autoGenerate=!0,this}uuid(){if(!window.isSecureContext)throw new Error("Window is not in a secure context");return new $("string",b)}genKey(){if(this.genFn)return this.genFn();throw new Error("Generator function not defined")}getSchema(){return S[this.type]}isAutoIncremented(){return this.autoGenerate&&!this.genFn}}class N{to;name;isOptional;isArray;actions;relatedKey;constructor(e,t="",n=!1,s=!1,r){this.to=e,this.name=t,this.isOptional=n,this.isArray=s,this.relatedKey="",this.actions={onDelete:r||"Restrict"}}getActions(){return{...this.actions}}setRelatedKey(e){this.relatedKey=e}getRelatedKey(){return this.relatedKey}}class v extends N{constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new I(this.to,this.name,e)}optional({onDelete:e}={}){return new K(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}}class I extends N{constructor(e,t,n="SetNull"){super(e,t,!1,!0,n)}}class K extends N{constructor(e,t,n="SetNull"){super(e,t,!0,!1,n)}}class M{validate;type;hasDefault=!1;options;constructor(e,t,n){this.validate=e,this.type=t,this.options={unique:n?.unique??!1}}static array(e,t){throw new Error("Method Not Implemented")}static literal(e,t){throw new Error("Method Not Implemented")}static custom(e,t){throw new Error("Method Not Implemented")}static union(e,t){throw new Error("Method Not Implemented")}static string(e){throw new Error("Method Not Implemented")}static number(e){throw new Error("Method Not Implemented")}static boolean(e){throw new Error("Method Not Implemented")}unique(){switch(this.type){case A.Boolean:case A.String:case A.Number:case A.Symbol:return this.options.unique=!0,this;default:return console.error("A non-primitive cannot be a unique value"),null}}hasDefaultValue(){return this.hasDefault}static relation(e,t){return new v(e,t)}static primaryKey(e="number"){return new $(e)}static validators=S;static literalToType(e){switch(typeof e){case"boolean":return A.Boolean;case"bigint":return A.BigInt;case"number":case"string":return A.Number;case"object":return A.Object;case"symbol":return A.Symbol;default:return A.Unknown}}}class D extends M{array(){return new D(D.generateArrayValidator(this.validate),A.Array,this.options)}default(e){return new D(t=>null==t?{success:!0,data:e}:this.validate(t),this.type,this.options)}optional(){return new D(e=>null==e?{success:!0,data:void 0}:this.validate(e),this.type,this.options)}static literal(e,t){return new D(t=>t===e?{success:!0,data:e}:{success:!1,error:`${t} !== ${e}`},D.literalToType(e),t)}static string(e){return new D(M.validators.string,A.String,e)}static number(e){return new D(M.validators.number,A.Number,e)}static boolean(e){return new D(e=>"boolean"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},A.Boolean,e)}static union(e,t){const n=e.map(e=>e instanceof M?e.validate:e);return new D(e=>{for(const t of n){const n=t(e);if(n.success)return n}return{success:!1,error:"Value did not match any of the items"}},A.Unknown,t)}static custom(e,t){return new D(e,A.Unknown,t)}static array(e,t){return new D(D.generateArrayValidator(e instanceof D?e.validate:e),A.Array,t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const n=[];for(const s of t){const t=e(s);if(!t.success)return t;n.push(t.data)}return{success:!0,data:n}}return{success:!1,error:"Value is not an array"}}}}class O{name;fields;fieldKeys;relationLinks=new Set;cache={};primaryKey;constructor(t,n){this.name=t,this.fields=n,this.fieldKeys=w(n);for(const e of this.fieldKeys){const t=this.fields[e];t instanceof N&&t.to!==this.name&&this.relationLinks.add(t.to)}const s=this.fieldKeys.find(e=>this.fields[e]instanceof $);if(!s)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=s}get(e){return this.fields[e]}getModelField(e){const t=this.fields[e];if(t&&t instanceof M)return t}getPrimaryKey(){return this.fields[this.primaryKey]}getRelation(e){const t=this.fields[e];if(t&&t instanceof N)return t}keyType(e){const t=this.fields[e];return t?t instanceof M?0:t instanceof N?1:t instanceof $?2:3:3}links(){return this.relationLinks.keys()}keys(){return[...this.fieldKeys]}parseField(e,t){return this.fields[e]instanceof M?this.fields[e].validate(t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=new Set,n=[this.name];let s;for(;n.length>0;){const r=n.shift();if(t.has(r))continue;s=e.getModel(r);const o=s.cache.delete;if(o)k(t,o);else{t.add(r);for(const e of s.links())t.has(e)||n.push(e)}}return this.cache.delete=t,t}}class x{tx;store;constructor(e,t){this.tx=e,this.store=t}async add(e){return await this.handleRequest(this.store.add(e),()=>new d)}async get(e){return await this.handleRequest(this.store.get(e),()=>new y)}async put(e){return await this.handleRequest(this.store.put(e),()=>new u)}async delete(e){return await this.handleRequest(this.store.delete(e),()=>new i)}async openCursor(e,t={}){const n=t.onError||(()=>new h),s=this.store.openCursor(t.query,t.direction);await new Promise(t=>{s.onsuccess=async s=>{if(!s.target)throw this.tx.abort(n());const r=s.target.result;r&&await e(r,this.tx)||t()},s.onerror=()=>{throw this.tx.abort(n())}})}async handleRequest(e,t){return await new Promise(n=>{e.onsuccess=()=>{n(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class R{internal;status;error=null;storeNames;objectStores;constructor(e,t,n,s={}){this.internal=e.transaction(t,n),this.status="running",this.storeNames=Array.from(this.internal.objectStoreNames),this.objectStores={};for(const e of this.storeNames)this.objectStores[e]=this.getObjectstore(e);this.internal.onabort=this.registerHandler("aborted",s.onAbort),this.internal.onerror=this.registerHandler("error",s.onError),this.internal.oncomplete=this.registerHandler("complete",s.onComplete)}abort(e){return this.internal.abort(),this.error=e,this.error}commit(){this.internal.commit()}getInternal(){return this.internal}getStore(e){const t=this.objectStores[e];if(!t)throw this.abort(new s(`Store '${e}' is not a part of this transaction`));return t}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 x(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){try{return await t(this)}catch(t){throw t instanceof e&&"aborted"===this.status?t:this.abort(new a)}}}function j(e){if(!e)return()=>!0;const t=[];for(const n in e)if(Object.hasOwn(e,n))switch(typeof e[n]){case"function":t.push([n,e[n]]);break;case"object":break;default:t.push([n,t=>t===e[n]])}return e=>{if(!e||"object"!=typeof e)return!1;for(const n of t)if(!n[1](e[n[0]]))return!1;return!0}}function F(e,t,n={},s){const o=t.getModel(e);if(n.include&&n.select)throw s?s.abort(new r("include and select cannot both be defined")):new r("include and select cannot both be defined");const a=j(n.where),i=n.select?"select":n.include?"include":"";if(i){const e=n[i],r=!!n.select,c=[];for(const n in e)if(Object.hasOwn(e,n)&&e[n])switch(o.keyType(n)){case 1:{const r=o.getRelation(n),a="object"==typeof e[n]?F(r.to,t,e[n],s):p;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.get(r),t);e&&n.push(e)}return n};c.push({key:n,getValue:e})}else{const e=async(e,t)=>await a(await t.getStore(r.to).get(e),t);c.push({key:n,getValue:e})}break}case 0:case 2:r&&c.push({key:n})}return r?async(e,t)=>{if(!a(e))return;const n={};for(const{key:s,getValue:r}of c)n[s]=r?await r(e[s],t):e[s];return n}:async(e,t)=>{if(a(e)){for(const{key:n,getValue:s}of c)e[n]=await s(e[n],t);return e}}}return e=>a(e)?e:void 0}function E(e,t,n,s){const r=new Set([e]);if("mutation"===n){const o=w(t),a=s.getModel(e);for(const e of o){const o=a.getRelation(e),i=m(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":r.add(o.to);break;case"$delete":case"$deleteMany":k(r,a.getDeletedStores(s));break;case"$create":k(r,E(o.to,e[t],n,s));break;case"$createMany":e[t].forEach(e=>k(r,E(o.to,e,n,s)))}}}else{const n=s.getModel(e);for(const e of w(t)){const o=n.getRelation(e);if(o)switch(typeof t[e]){case"object":k(r,E(o.to,T(t[e]),"query",s));break;case"boolean":r.add(o.to)}}}return r}function T(e){return e.include?e.include:e.select?e.select:{}}function C(t){return n=>{throw n instanceof e?t.abort(n):t.abort(new a(String(n)))}}class V{client;name;accessedStores;selectClause;constructor(e,t,n){this.client=e,this.name=t,this.accessedStores=Array.from(E(t,T(n),"query",this.client)),this.selectClause=F(t,this.client,n)}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),n=[],s=t.getStore(this.name);return await s.openCursor(async s=>{const r=await this.selectClause(s.value,t);return r&&n.push(r),(!e||!n.length)&&(s.continue(),!0)}),n}}async function _(e,t,s,r=!1,o={}){const{singleton:a,finalStep:c=!0}=o,l=t.getModel(e),u=o.tx?o.tx.storeNames:Array.from(l.getDeletedStores(t)),d=o.tx??t.createTransaction("readwrite",u),h=d.getStore(e);let y=0;const w=async s=>{if(!s)return!1;const r=s[l.primaryKey];for(const o of l.links()){const a=l.getRelation(o),{onDelete:c}=a.getActions(),u=s[o],h=t.getModel(a.to);switch(c){case"Cascade":if(a.isArray){d.assertIsArray(u);for(const e of u)await _(a.to,t,void 0,void 0,{tx:d,singleton:{id:e}})}else u&&await _(a.to,t,void 0,void 0,{tx:d,singleton:{id:u}});break;case"SetNull":{if(!u)break;const e=m(u),t=d.getStore(a.to),s=a.getRelatedKey(),o=h.getRelation(s);if(!o)throw d.abort(new n(`Relation '${a.name}' has an invalid relation key '${a.getRelatedKey()}'`));if(!o.isArray&&!o.isOptional)throw d.abort(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 a=e[s];if(o.isArray){d.assertIsArray(a);const e=a.indexOf(r);if(-1===e)continue;a.splice(e,1)}else e[s]=null;await t.put(e)}break}case"Restrict":if(Array.isArray(u)&&u.length>0||u)throw d.abort(new i(`Key '${o}' on model '${e}' deletion is restricted while there is an active relation`))}}return!0};if(a)await w(await h.get(a.id))&&(await h.delete(a.id),y++);else{const e=j(s);let t;await h.openCursor(async n=>{const s=n.value;return e(s)&&await w(s)&&(t=n.delete()),r&&y>0?(t&&c&&await f(t),!1):(n.continue(),!0)})}return y}class q{db;models;name;version;stores;constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const e of this.models.keys())this.stores[e]=this.createInterface(e)}getStore(e){return this.stores[e]}createTransaction(e,t,n){return new R(this.db,t,e,n)}async deleteDb(){await f(window.indexedDB.deleteDatabase(this.name))}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){return this.models.getModel(e)}getAccessedStores(e,t,n="mutation"){return Array.from(E(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 s=new Set;for(const n of t)k(s,E(e,n,"mutation",this));n=this.createTransaction("readwrite",Array.from(s))}const s=[];let r;for(const o of t)r=this.add(e,o,{tx:n}),r.then(e=>s.push(e)).catch(C(n));return r&&await r,s},clear:async t=>await this.clear(e,{tx:t}),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}),put:async()=>{},get:async t=>{const n=this.createTransaction("readonly",e);return await n.getStore(e).get(t)},insert:async(e,t)=>(await new Promise(e=>e()),5),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 V(this,e,t),delete:async t=>await _(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await _(e,this,t,!0)>0,deleteMany:async t=>await _(e,this,t,!1)}}async add(e,t,n={}){let{tx:s}=n;const{relation:o}=n,i=s?s.storeNames:this.getAccessedStores(e,t,"mutation");s=s??new R(this.db,i,"readwrite");const c=s.getStore(e),u=this.getModel(e),d=u.getPrimaryKey(),h=o?{[o.key]:u.getRelation(o.key)?.isArray?[o.id]:o.id}:{},y=d.isAutoIncremented()?{...h}:{...h,[u.primaryKey]:t[u.primaryKey]??d.genKey()},f=await c.add(y),g={},b=new Set;for(const n of w(t)){b.add(n);const o=t[n];switch(u.keyType(n)){case 3:throw s.abort(new r(`Key '${n}' does ont exist on model '${e}'`));case 0:{const e=u.parseField(n,o);if(!e)throw s.abort(new a);if(!e.success)throw s.abort(new r(`Key '${n}' has the following validation error: ${e.error}`));g[n]=e.data;break}case 1:{if(!o)continue;const e=m(o),t=u.getRelation(n);if(t.isArray&&(g[n]=[],"$createMany"in o||"$connectMany"in o)){const t=[];for(const e of o.$createMany??[])t.push({$create:e});for(const e of o.$connectMany??[])t.push({$connect:e});e.push(...t)}const a=this.getModel(t.to).getRelation(t.getRelatedKey()),i=s.getStore(t.to),c=new Set;for(const o of e){const e=w(o)[0];if(!e)throw s.abort(new r(`Key '${n}' cannot be an empty connection object`));switch(e){case"$connect":{const u=o[e];if(c.has(u))throw s.abort(new r(`Primary key '${u}' was already used for a connection`));c.add(u);const d=await i.get(u);if(!d)throw s.abort(new l(`Document with Primary Key '${u}' could not be found in model '${t.to}'`));if(!a)throw s.abort(new r(`Could not find corresponding relation '${t.name}'`));if(a.isArray)d[t.getRelatedKey()].push(f);else{const e=t.getRelatedKey();d[e],d[e]=f}i.put(d).catch(C(s)),t.isArray?g[n].push(u):g[n]=u;break}case"$create":{const r=await this.add(t.to,o[e],{tx:s,relation:{id:f,key:t.getRelatedKey()}});t.isArray?g[n].push(r):g[n]=r;break}case"$connectMany":case"$createMany":break;default:throw s.abort(new r(`Connection Object on key '${n}' has an unknown key '${e}'`))}if(!t.isArray)break}break}}}const p=Array.from(new Set(u.keys()).difference(b));for(const e of p)switch(u.keyType(e)){case 0:{const t=u.parseField(e,void 0);if(!t)throw s.abort(new a);if(!t.success)throw s.abort(new r(`Key '${e}' is missing`));g[e]=t.data;break}case 1:{const t=u.getRelation(e),n=h[e];if(t.isArray)g[e]=n??[];else if(t.isOptional)g[e]=n??null;else{if(!n)throw s.abort(new r(`Required relation '${e}' is not defined`));g[e]=n}break}}return await c.put({[u.primaryKey]:f,...g})}async clear(e,t){await _(e,this,void 0,!1,t)}async find(e,t,n,s={}){let{tx:r}=s;const o=r?r.storeNames:this.getAccessedStores(e,T(t),"query");r=r??new R(this.db,o,"readonly");const a=[],i=r.getStore(e),c=F(e,this,t,r);return await i.openCursor(async e=>{const t=await c(e.value,r);return t&&a.push(t),(!n||!a.length)&&(e.continue(),!0)}),a}async update(e,t,n,s={}){let{tx:o}=s;const{singleton:i=!1}=s,c=o?o.storeNames:this.getAccessedStores(e,t.data,"mutation");o=o??new R(this.db,c,"readwrite");const l=[],d=o.getStore(e),h=this.getModel(e),{where:y,data:f}=t,g=[];for(const e of w(f))switch(h.keyType(e)){case 0:g.push({key:e,isFun:"function"==typeof f[e],isRelation:!1});break;case 1:g.push({key:e,isFun:!1,isRelation:!0,relation:h.getRelation(e)});break;case 2:throw o.abort(new u("Primary key field cannot be updated"));default:throw o.abort(new a(`Unknown key '${e}'`))}const b=j(y),p=async e=>{if(y&&!b(e))return!1;for(const{key:t,isRelation:n,isFun:s,relation:a}of g){if(!n){e[t]=s?f[t](e[t]):f[t];continue}const i=m(f[t]);for(const n of i)for(const s in n){if(!Object.hasOwn(n,t))continue;const i=n[t];switch(s){case"$connect":case"$create":case"$updateMany":case"$delete":case"$disconnect":break;case"$update":a.isArray?await this.update(a.to,i,!0,{tx:o}):e[t]&&await this.updateSingleton(a.to,e[t],i,{tx:o});break;case"$connectMany":case"$createMany":case"$deleteMany":case"$disconnectMany":case"$disconnectAll":case"$deleteAll":throw o.abort(new r(`Connection Object on key '${t}' has an unknown key '${s}'`))}break}}};return i?await p(await d.get(i.id)):await d.openCursor(async e=>(await p(e.value),(!n||!l.length)&&(e.continue(),!0))),l}async updateSingleton(e,t,n,s){let{tx:r}=s;const o=r?r.storeNames:this.getAccessedStores(e,n,"mutation");r=r??new R(this.db,o,"readwrite");const a=r.getStore(e),i=this.getModel(e),c=await a.get(t);if(!c)throw r.abort(new l(`No document with key '${t}' could be found in store '${i.name}'`));return c}}class L{name;names;models;constructor(e,t){this.name=e,this.names=t,this.models={}}defineModel(e,t){const n=new O(e,t);return this.models[e]=n,n}compile(e){return new G(this.name,e)}}class G{name;models;schemas;modelKeys;constructor(t,n){this.name=t,this.models=n,this.modelKeys=w(this.models),this.schemas={};for(const t of this.modelKeys){const n=this.models[t],s={};for(const r of n.keys()){const o=n.get(r);if(o instanceof M)s[r]=o.validate;else if(o instanceof N){const a=this.models[o.to],i=a.getPrimaryKey();s[r]=M.validators[i.type],o.isOptional?s[r]=new D(s[r],g(i.type)).optional().validate:o.isArray&&(s[r]=s[r]=new D(s[r],g(i.type)).array().validate);let c=!!o.getRelatedKey();if(!c)for(const e of a.keys()){const t=a.get(e);if(r!==e&&t instanceof N&&t.to===n.name&&t.name===o.name){c=t.to!==o.to||r!==e,c&&(o.setRelatedKey(e),t.setRelatedKey(r));break}}if(!c)throw new e("INVALID_CONFIG",`Relation '${o.name}' of model ${t} does not have an equivalent relation on model '${o.to}'`)}else{if(!(o instanceof $))throw new e("INVALID_CONFIG",`Unknown field value detected: ${JSON.stringify(o)}`);s[r]=M.validators[o.type]}}this.schemas[t]=s}}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 e of this.modelKeys){const n=this.models[e];t.objectStoreNames.contains(n.name)||t.createObjectStore(n.name,{autoIncrement:n.getPrimaryKey().isAutoIncremented(),keyPath:n.primaryKey})}};const n=await f(t);return new q(n,this)}keys(){return[...this.modelKeys]}}export{L as Builder,V as CompiledQuery,D as Property,e as StoreError};
1
+ class e extends Error{code;message;constructor(e,t){super(),this.code=e,this.message=t}}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"),s=t("INVALID_TX","Transaction is invalid"),r=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"),l=t("NOT_FOUND","Document Not Found"),u=t("UPDATE_FAILED","Item could not be updated"),d=t("ADD_FAILED","Item could not be added"),h=t("OPEN_CURSOR","Cursor could not be opened"),y=t("GET_FAILED","Item could not be retrieved");async function f(e,t){return await new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function w(e){return Object.keys(e)}function m(e){return Array.isArray(e)||(e=[e]),e}function g(e){switch(e){case"date":return A.Date;case"number":return A.Number;case"string":return A.String}}function b(){return crypto.randomUUID()}function p(e){return e}function k(e,t){for(const n of t.keys())e.add(n);return e}var A;!function(e){e[e.String=0]="String",e[e.Number=1]="Number",e[e.BigInt=2]="BigInt",e[e.Boolean=3]="Boolean",e[e.Symbol=4]="Symbol",e[e.Array=5]="Array",e[e.Date=6]="Date",e[e.Object=7]="Object",e[e.Unknown=8]="Unknown"}(A||(A={}));const S={string:e=>"string"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},number:e=>"number"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},date:e=>e instanceof Date?isNaN(e.getTime())?{success:!1,error:"Value is not a valid date"}:{success:!0,data:e}:{success:!1,error:"Value is not a date"}};class ${genFn;autoGenerate;type;constructor(e,t){e?(this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1):(this.autoGenerate=!1,this.type="number")}autoIncrement(){if("number"===this.type)return this.genFn=void 0,this.autoGenerate=!0,this;const e=new $;return e.genFn=void 0,e.autoGenerate=!0,e}generator(e){return this.genFn=e,this.autoGenerate=!0,this}uuid(){if(!window.isSecureContext)throw new Error("Window is not in a secure context");return new $("string",b)}genKey(){if(this.genFn)return this.genFn();throw new Error("Generator function not defined")}getSchema(){return S[this.type]}isAutoIncremented(){return this.autoGenerate&&!this.genFn}}class N{to;name;isOptional;isArray;actions;relatedKey;constructor(e,t="",n=!1,s=!1,r){this.to=e,this.name=t,this.isOptional=n,this.isArray=s,this.relatedKey="",this.actions={onDelete:r||"Restrict"}}getActions(){return{...this.actions}}setRelatedKey(e){this.relatedKey=e}getRelatedKey(){return this.relatedKey}}class v extends N{constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new I(this.to,this.name,e)}optional({onDelete:e}={}){return new K(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}}class I extends N{constructor(e,t,n="SetNull"){super(e,t,!1,!0,n)}}class K extends N{constructor(e,t,n="SetNull"){super(e,t,!0,!1,n)}}class D{validateFn;type;hasDefault=!1;options;constructor(e,t,n){this.validateFn=e,this.type=t,this.options={unique:n?.unique??!1}}get validate(){return this.validateFn}static array(...e){throw new Error("Method Not Implemented")}static literal(e,...t){throw new Error("Method Not Implemented")}static custom(...e){throw new Error("Method Not Implemented")}static union(...e){throw new Error("Method Not Implemented")}static string(...e){throw new Error("Method Not Implemented")}static number(...e){throw new Error("Method Not Implemented")}static boolean(...e){throw new Error("Method Not Implemented")}unique(){switch(this.type){case A.Boolean:case A.String:case A.Number:case A.Symbol:return this.options.unique=!0,this;default:return console.error("A non-primitive cannot be a unique value"),null}}hasDefaultValue(){return this.hasDefault}static relation(e,t){return new v(e,t)}static primaryKey(e="number"){return new $(e)}static validators=S;static literalToType(e){return D.nameToType(typeof e)}static nameToType(e){switch(e){case"boolean":return A.Boolean;case"bigint":return A.BigInt;case"number":case"string":return A.Number;case"object":return A.Object;case"symbol":return A.Symbol;default:return A.Unknown}}}class M extends D{array(){return new M(M.generateArrayValidator(this.validateFn),A.Array,this.options)}default(e){return this.hasDefault=!0,new M(t=>null==t?{success:!0,data:e}:this.validateFn(t),this.type,this.options)}optional(){return new M(e=>null==e?{success:!0,data:void 0}:this.validateFn(e),this.type,this.options)}static literal(e,t){return new M(t=>t===e?{success:!0,data:e}:{success:!1,error:`${t} !== ${e}`},M.literalToType(e),t)}static string(e){return new M(D.validators.string,A.String,e)}static number(e){return new M(D.validators.number,A.Number,e)}static boolean(e){return new M(e=>"boolean"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},A.Boolean,e)}static union(e,t){const n=e.map(e=>e instanceof D?e.validate:e);return new M(e=>{for(const t of n){const n=t(e);if(n.success)return n}return{success:!1,error:"Value did not match any of the items"}},A.Unknown,t)}static custom(e,t){return new M(e,A.Unknown,t)}static array(e,t){return new M(M.generateArrayValidator(e instanceof M?e.validateFn:e),A.Array,t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const n=[];for(const s of t){const t=e(s);if(!t.success)return t;n.push(t.data)}return{success:!0,data:n}}return{success:!1,error:"Value is not an array"}}}}class O{name;fields;fieldKeys;relationLinks=new Set;cache={};primaryKey;constructor(t,n){this.name=t,this.fields=n,this.fieldKeys=w(n);for(const e of this.fieldKeys){const t=this.fields[e];t instanceof N&&t.to!==this.name&&this.relationLinks.add(t.to)}const s=this.fieldKeys.find(e=>this.fields[e]instanceof $);if(!s)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=s}get(e){return this.fields[e]}getModelField(e){const t=this.fields[e];if(t&&t instanceof D)return t}getPrimaryKey(){return this.fields[this.primaryKey]}getRelation(e){const t=this.fields[e];if(t&&t instanceof N)return t}keyType(e){const t=this.fields[e];return t?t instanceof D?0:t instanceof N?1:t instanceof $?2:3:3}links(){return this.relationLinks.keys()}keys(){return[...this.fieldKeys]}parseField(e,t){return this.fields[e]instanceof D?this.fields[e].validate(t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=new Set,n=[this.name];let s;for(;n.length>0;){const r=n.shift();if(t.has(r))continue;s=e.getModel(r);const o=s.cache.delete;if(o)k(t,o);else{t.add(r);for(const e of s.links())t.has(e)||n.push(e)}}return this.cache.delete=t,t}}class F{tx;store;constructor(e,t){this.tx=e,this.store=t}async add(e){return await this.handleRequest(this.store.add(e),()=>new d)}async get(e){return await this.handleRequest(this.store.get(e),()=>new y)}async put(e){return await this.handleRequest(this.store.put(e),()=>new u)}async delete(e){return await this.handleRequest(this.store.delete(e),()=>new i)}async openCursor(e,t={}){const n=t.onError||(()=>new h),s=this.store.openCursor(t.query,t.direction);await new Promise(t=>{s.onsuccess=async s=>{if(!s.target)throw this.tx.abort(n());const r=s.target.result;r&&await e(r,this.tx)||t()},s.onerror=()=>{throw this.tx.abort(n())}})}async handleRequest(e,t){return await new Promise(n=>{e.onsuccess=()=>{n(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class x{internal;status;error=null;storeNames;objectStores;constructor(e,t,n,s={}){this.internal=e.transaction(t,n),this.status="running",this.storeNames=Array.from(this.internal.objectStoreNames),this.objectStores={};for(const e of this.storeNames)this.objectStores[e]=this.getObjectstore(e);this.internal.onabort=this.registerHandler("aborted",s.onAbort),this.internal.onerror=this.registerHandler("error",s.onError),this.internal.oncomplete=this.registerHandler("complete",s.onComplete)}abort(e){return this.internal.abort(),this.error=e,this.error}commit(){this.internal.commit()}getInternal(){return this.internal}getStore(e){const t=this.objectStores[e];if(!t)throw this.abort(new s(`Store '${e}' is not a part of this transaction`));return t}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 F(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){try{return await t(this)}catch(t){throw t instanceof e&&"aborted"===this.status?t:this.abort(new a)}}}function R(e){if(!e)return()=>!0;const t=[];for(const n in e)if(Object.hasOwn(e,n))switch(typeof e[n]){case"function":t.push([n,e[n]]);break;case"object":break;default:t.push([n,t=>t===e[n]])}return e=>{if(!e||"object"!=typeof e)return!1;for(const n of t)if(!n[1](e[n[0]]))return!1;return!0}}function j(e,t,n={},s){const o=t.getModel(e);if(n.include&&n.select)throw s?s.abort(new r("include and select cannot both be defined")):new r("include and select cannot both be defined");const a=R(n.where),i=n.select?"select":n.include?"include":"";if(i){const e=n[i],r=!!n.select,c=[];for(const n in e)if(Object.hasOwn(e,n)&&e[n])switch(o.keyType(n)){case 1:{const r=o.getRelation(n),a="object"==typeof e[n]?j(r.to,t,e[n],s):p;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.get(r),t);e&&n.push(e)}return n};c.push({key:n,getValue:e})}else{const e=async(e,t)=>await a(await t.getStore(r.to).get(e),t);c.push({key:n,getValue:e})}break}case 0:case 2:r&&c.push({key:n})}return r?async(e,t)=>{if(!a(e))return;const n={};for(const{key:s,getValue:r}of c)n[s]=r?await r(e[s],t):e[s];return n}:async(e,t)=>{if(a(e)){for(const{key:n,getValue:s}of c)e[n]=await s(e[n],t);return e}}}return e=>a(e)?e:void 0}function T(e,t,n,s){const r=new Set([e]);if("mutation"===n){const o=w(t),a=s.getModel(e);for(const e of o){const o=a.getRelation(e),i=m(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":r.add(o.to);break;case"$delete":case"$deleteMany":k(r,a.getDeletedStores(s));break;case"$create":k(r,T(o.to,e[t],n,s));break;case"$createMany":e[t].forEach(e=>k(r,T(o.to,e,n,s)))}}}else{const n=s.getModel(e);for(const e of w(t)){const o=n.getRelation(e);if(o)switch(typeof t[e]){case"object":k(r,T(o.to,E(t[e]),"query",s));break;case"boolean":r.add(o.to)}}}return r}function E(e){return e.include?e.include:e.select?e.select:{}}function C(t){return n=>{throw n instanceof e?t.abort(n):t.abort(new a(String(n)))}}class V{client;name;accessedStores;selectClause;constructor(e,t,n){this.client=e,this.name=t,this.accessedStores=Array.from(T(t,E(n),"query",this.client)),this.selectClause=j(t,this.client,n)}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),n=[],s=t.getStore(this.name);return await s.openCursor(async s=>{const r=await this.selectClause(s.value,t);return r&&n.push(r),(!e||!n.length)&&(s.continue(),!0)}),n}}async function _(e,t,s,r=!1,o={}){const{singleton:a,finalStep:c=!0}=o,l=t.getModel(e),u=o.tx?o.tx.storeNames:Array.from(l.getDeletedStores(t)),d=o.tx??t.createTransaction("readwrite",u),h=d.getStore(e);let y=0;const w=async s=>{if(!s)return!1;const r=s[l.primaryKey];for(const o of l.links()){const a=l.getRelation(o),{onDelete:c}=a.getActions(),u=s[o],h=t.getModel(a.to);switch(c){case"Cascade":if(a.isArray){d.assertIsArray(u);for(const e of u)await _(a.to,t,void 0,void 0,{tx:d,singleton:{id:e}})}else u&&await _(a.to,t,void 0,void 0,{tx:d,singleton:{id:u}});break;case"SetNull":{if(!u)break;const e=m(u),t=d.getStore(a.to),s=a.getRelatedKey(),o=h.getRelation(s);if(!o)throw d.abort(new n(`Relation '${a.name}' has an invalid relation key '${a.getRelatedKey()}'`));if(!o.isArray&&!o.isOptional)throw d.abort(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 a=e[s];if(o.isArray){d.assertIsArray(a);const e=a.indexOf(r);if(-1===e)continue;a.splice(e,1)}else e[s]=null;await t.put(e)}break}case"Restrict":if(Array.isArray(u)&&u.length>0||u)throw d.abort(new i(`Key '${o}' on model '${e}' deletion is restricted while there is an active relation`))}}return!0};if(a)await w(await h.get(a.id))&&(await h.delete(a.id),y++);else{const e=R(s);let t;await h.openCursor(async n=>{const s=n.value;return e(s)&&await w(s)&&(t=n.delete()),r&&y>0?(t&&c&&await f(t),!1):(n.continue(),!0)})}return y}class q{db;models;name;version;stores;constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const e of this.models.keys())this.stores[e]=this.createInterface(e)}getStore(e){return this.stores[e]}createTransaction(e,t,n){return new x(this.db,t,e,n)}async deleteDb(){await f(window.indexedDB.deleteDatabase(this.name))}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){return this.models.getModel(e)}getAccessedStores(e,t,n="mutation"){return Array.from(T(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 s=new Set;for(const n of t)k(s,T(e,n,"mutation",this));n=this.createTransaction("readwrite",Array.from(s))}const s=[];let r;for(const o of t)r=this.add(e,o,{tx:n}),r.then(e=>s.push(e)).catch(C(n));return r&&await r,s},clear:async t=>await this.clear(e,{tx:t}),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}),put:async()=>{},get:async t=>{const n=this.createTransaction("readonly",e);return await n.getStore(e).get(t)},insert:async(e,t)=>(await new Promise(e=>e()),5),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 V(this,e,t),delete:async t=>await _(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await _(e,this,t,!0)>0,deleteMany:async t=>await _(e,this,t,!1)}}async add(e,t,n={}){let{tx:s}=n;const{relation:o}=n,i=s?s.storeNames:this.getAccessedStores(e,t,"mutation");s=s??new x(this.db,i,"readwrite");const c=s.getStore(e),u=this.getModel(e),d=u.getPrimaryKey(),h=o?{[o.key]:u.getRelation(o.key)?.isArray?[o.id]:o.id}:{},y=d.isAutoIncremented()?{...h}:{...h,[u.primaryKey]:t[u.primaryKey]??d.genKey()},f=await c.add(y),g={},b=new Set;for(const n of w(t)){b.add(n);const o=t[n];switch(u.keyType(n)){case 3:throw s.abort(new r(`Key '${n}' does ont exist on model '${e}'`));case 0:{const e=u.parseField(n,o);if(!e)throw s.abort(new a);if(!e.success)throw s.abort(new r(`Key '${n}' has the following validation error: ${e.error}`));g[n]=e.data;break}case 1:{if(!o)continue;const e=m(o),t=u.getRelation(n);if(t.isArray&&(g[n]=[],"$createMany"in o||"$connectMany"in o)){const t=[];for(const e of o.$createMany??[])t.push({$create:e});for(const e of o.$connectMany??[])t.push({$connect:e});e.push(...t)}const a=this.getModel(t.to).getRelation(t.getRelatedKey()),i=s.getStore(t.to),c=new Set;for(const o of e){const e=w(o)[0];if(!e)throw s.abort(new r(`Key '${n}' cannot be an empty connection object`));switch(e){case"$connect":{const u=o[e];if(c.has(u))throw s.abort(new r(`Primary key '${u}' was already used for a connection`));c.add(u);const d=await i.get(u);if(!d)throw s.abort(new l(`Document with Primary Key '${u}' could not be found in model '${t.to}'`));if(!a)throw s.abort(new r(`Could not find corresponding relation '${t.name}'`));if(a.isArray)d[t.getRelatedKey()].push(f);else{const e=t.getRelatedKey();d[e],d[e]=f}i.put(d).catch(C(s)),t.isArray?g[n].push(u):g[n]=u;break}case"$create":{const r=await this.add(t.to,o[e],{tx:s,relation:{id:f,key:t.getRelatedKey()}});t.isArray?g[n].push(r):g[n]=r;break}case"$connectMany":case"$createMany":break;default:throw s.abort(new r(`Connection Object on key '${n}' has an unknown key '${e}'`))}if(!t.isArray)break}break}}}const p=Array.from(new Set(u.keys()).difference(b));for(const e of p)switch(u.keyType(e)){case 0:{const t=u.parseField(e,void 0);if(!t)throw s.abort(new a);if(!t.success)throw s.abort(new r(`Key '${e}' is missing`));g[e]=t.data;break}case 1:{const t=u.getRelation(e),n=h[e];if(t.isArray)g[e]=n??[];else if(t.isOptional)g[e]=n??null;else{if(!n)throw s.abort(new r(`Required relation '${e}' is not defined`));g[e]=n}break}}return await c.put({[u.primaryKey]:f,...g})}async clear(e,t){await _(e,this,void 0,!1,t)}async find(e,t,n,s={}){let{tx:r}=s;const o=r?r.storeNames:this.getAccessedStores(e,E(t),"query");r=r??new x(this.db,o,"readonly");const a=[],i=r.getStore(e),c=j(e,this,t,r);return await i.openCursor(async e=>{const t=await c(e.value,r);return t&&a.push(t),(!n||!a.length)&&(e.continue(),!0)}),a}async update(e,t,n,s={}){let{tx:o}=s;const{singleton:i=!1}=s,c=o?o.storeNames:this.getAccessedStores(e,t.data,"mutation");o=o??new x(this.db,c,"readwrite");const l=[],d=o.getStore(e),h=this.getModel(e),{where:y,data:f}=t,g=[];for(const e of w(f))switch(h.keyType(e)){case 0:g.push({key:e,isFun:"function"==typeof f[e],isRelation:!1});break;case 1:g.push({key:e,isFun:!1,isRelation:!0,relation:h.getRelation(e)});break;case 2:throw o.abort(new u("Primary key field cannot be updated"));default:throw o.abort(new a(`Unknown key '${e}'`))}const b=R(y),p=async e=>{if(y&&!b(e))return!1;for(const{key:t,isRelation:n,isFun:s,relation:a}of g){if(!n){e[t]=s?f[t](e[t]):f[t];continue}const i=m(f[t]);for(const n of i)for(const s in n){if(!Object.hasOwn(n,t))continue;const i=n[t];switch(s){case"$connect":case"$create":case"$updateMany":case"$delete":case"$disconnect":break;case"$update":a.isArray?await this.update(a.to,i,!0,{tx:o}):e[t]&&await this.updateSingleton(a.to,e[t],i,{tx:o});break;case"$connectMany":case"$createMany":case"$deleteMany":case"$disconnectMany":case"$disconnectAll":case"$deleteAll":throw o.abort(new r(`Connection Object on key '${t}' has an unknown key '${s}'`))}break}}};return i?await p(await d.get(i.id)):await d.openCursor(async e=>(await p(e.value),(!n||!l.length)&&(e.continue(),!0))),l}async updateSingleton(e,t,n,s){let{tx:r}=s;const o=r?r.storeNames:this.getAccessedStores(e,n,"mutation");r=r??new x(this.db,o,"readwrite");const a=r.getStore(e),i=this.getModel(e),c=await a.get(t);if(!c)throw r.abort(new l(`No document with key '${t}' could be found in store '${i.name}'`));return c}}class L{name;names;models;constructor(e,t){this.name=e,this.names=t,this.models={}}defineModel(e,t){const n=new O(e,t);return this.models[e]=n,n}compile(e){return new G(this.name,e)}}class G{name;models;schemas;modelKeys;constructor(t,n){this.name=t,this.models=n,this.modelKeys=w(this.models),this.schemas={};for(const t of this.modelKeys){const n=this.models[t],s={};for(const r of n.keys()){const o=n.get(r);if(o instanceof D)s[r]=o.validate;else if(o instanceof N){const a=this.models[o.to],i=a.getPrimaryKey();s[r]=D.validators[i.type],o.isOptional?s[r]=new M(s[r],g(i.type)).optional().validate:o.isArray&&(s[r]=s[r]=new M(s[r],g(i.type)).array().validate);let c=!!o.getRelatedKey();if(!c)for(const e of a.keys()){const t=a.get(e);if(r!==e&&t instanceof N&&t.to===n.name&&t.name===o.name){c=t.to!==o.to||r!==e,c&&(o.setRelatedKey(e),t.setRelatedKey(r));break}}if(!c)throw new e("INVALID_CONFIG",`Relation '${o.name}' of model ${t} does not have an equivalent relation on model '${o.to}'`)}else{if(!(o instanceof $))throw new e("INVALID_CONFIG",`Unknown field value detected: ${JSON.stringify(o)}`);s[r]=D.validators[o.type]}}this.schemas[t]=s}}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 e of this.modelKeys){const n=this.models[e];t.objectStoreNames.contains(n.name)||t.createObjectStore(n.name,{autoIncrement:n.getPrimaryKey().isAutoIncremented(),keyPath:n.primaryKey})}};const n=await f(t);return new q(n,this)}keys(){return[...this.modelKeys]}}export{L as Builder,V as CompiledQuery,M as Property,e as StoreError};
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@idb-orm/core",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
+ "types": "./dist/index.d.ts",
6
7
  "type": "module",
7
8
  "scripts": {
8
9
  "build": "rollup --config rollup.config.ts --configPlugin typescript",
@@ -21,8 +22,9 @@
21
22
  "import": "./dist/index.js",
22
23
  "require": "./dist/index.js"
23
24
  },
24
- "./types": {
25
- "types": "./dist/dev-types.d.ts"
25
+ "./dev": {
26
+ "types": "./dist/dev.d.ts",
27
+ "default": "./dist/dev.d.ts"
26
28
  }
27
29
  },
28
30
  "license": "ISC",
@@ -1,4 +0,0 @@
1
- {
2
- "status": "passed",
3
- "failedTests": []
4
- }