@idb-orm/core 1.0.7 → 1.0.9

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,23 +1,40 @@
1
- import { CollectionObject } from "../builder.js";
2
- import { DbClient } from "../client/index.js";
3
- import { BaseRelation, AbstractProperty, FieldTypes, PrimaryKey, ValidValue, ParseResult } from "../field";
4
- import { Keyof, ValidKey } from "../util-types.js";
5
- import { FindPrimaryKey } from "./model-types.js";
1
+ import { DbClient } from '../client/index.js';
2
+ import { BaseRelation, FieldTypes, PrimaryKey, ValidValue, ParseResult, ValidKey } from '../field';
3
+ import { Dict, Keyof } from '../util-types.js';
4
+ import { FindPrimaryKey, CollectionObject } from './model-types.js';
6
5
  export default class Model<Name extends string, F extends Record<string, ValidValue>, Primary extends FindPrimaryKey<F> = FindPrimaryKey<F>> {
7
6
  readonly name: Name;
8
7
  private readonly fields;
8
+ readonly symbol: symbol;
9
+ /**
10
+ * Array of all the model's fields
11
+ */
9
12
  private readonly fieldKeys;
13
+ /**
14
+ * Set of other models this model links to
15
+ */
10
16
  private readonly relationLinks;
11
17
  private cache;
12
18
  readonly primaryKey: Primary;
13
19
  constructor(name: Name, fields: F);
14
20
  get<K extends Keyof<F>>(key: K): F[K];
15
- getModelField(key: string): AbstractProperty<any, any> | undefined;
16
21
  getPrimaryKey(): PrimaryKey<boolean, ValidKey>;
17
22
  getRelation<Models extends string>(key: string): BaseRelation<Models, string> | undefined;
18
23
  keyType(key: Keyof<F>): FieldTypes;
19
24
  links<Names extends string = string>(): SetIterator<Names>;
25
+ /**
26
+ * Generator for all of the relations present on the model
27
+ */
28
+ relations<K extends string = string>(): Generator<[
29
+ key: string,
30
+ relation: BaseRelation<K, string>
31
+ ]>;
32
+ /**
33
+ * Generator for all of the entries present on the model
34
+ */
35
+ entries(): Generator<[key: string, value: ValidValue]>;
20
36
  keys(): Keyof<F>[];
21
37
  parseField<K extends Keyof<F>>(field: K, value: unknown): ParseResult<any>;
22
38
  getDeletedStores<ModelNames extends string, Models extends CollectionObject<ModelNames>>(client: DbClient<string, ModelNames, Models>): Set<ModelNames>;
39
+ static is<Name extends string, Fields extends Dict<ValidValue>, Primary extends FindPrimaryKey<Fields> = FindPrimaryKey<Fields>>(value: object): value is Model<Name, Fields, Primary>;
23
40
  }
@@ -1,21 +1,23 @@
1
- /**
2
- * A paper thin wrapper around IDBObjectStore
3
- */
4
- import { StoreError } from "./error.js";
5
- import { Transaction } from "./transaction.js";
6
- import { Dict, Promisable, ValidKey } from "./util-types.js";
7
- export declare class ObjectStore {
1
+ import { StoreError } from './error.js';
2
+ import { ValidKey } from './field';
3
+ import { Transaction } from './transaction.js';
4
+ import { Dict, Promisable } from './util-types.js';
5
+ export declare class ObjectStore<T = Dict> {
8
6
  private readonly tx;
9
7
  readonly store: IDBObjectStore;
10
8
  constructor(tx: Transaction<IDBTransactionMode, string>, store: IDBObjectStore);
11
- add(item: Dict): Promise<ValidKey>;
9
+ add(item: T): Promise<ValidKey>;
12
10
  /**
13
11
  * Attempts to retrieve the value from the object store.
14
12
  *
15
13
  * Returns `undefined` if no value was found
16
14
  */
17
- get(key: ValidKey): Promise<Dict>;
18
- put(item: Dict): Promise<ValidKey>;
15
+ get(key: ValidKey): Promise<T | undefined>;
16
+ /**
17
+ * Like .get(), but throws an error if the item could not be found
18
+ */
19
+ assertGet(key: ValidKey): Promise<T>;
20
+ put(item: T): Promise<ValidKey>;
19
21
  delete(key: ValidKey): Promise<undefined>;
20
22
  openCursor(callback: (cursor: IDBCursorWithValue, tx: Transaction<IDBTransactionMode, string>) => Promisable<boolean>, options?: {
21
23
  query?: IDBValidKey | IDBKeyRange;
@@ -1,7 +1,12 @@
1
- import { StoreError } from "./error";
2
- import { ObjectStore } from "./object-store.js";
3
- import { Arrayable } from "./util-types.js";
4
- export type TransactionStatus = "running" | "aborted" | "complete" | "error";
1
+ import { StoreError } from './error';
2
+ import { ObjectStore } from './object-store.js';
3
+ import { Arrayable, Promisable } from './util-types.js';
4
+ export declare const enum TransactionStatus {
5
+ Running = 0,
6
+ Aborted = 1,
7
+ Complete = 2,
8
+ Error = 3
9
+ }
5
10
  export type TransactionEventHandler = (tx: Transaction<IDBTransactionMode>, ev: Event) => void;
6
11
  export interface TransactionOptions extends Partial<{
7
12
  onAbort: TransactionEventHandler;
@@ -14,11 +19,22 @@ export declare class Transaction<Mode extends IDBTransactionMode, Stores extends
14
19
  status: TransactionStatus;
15
20
  error: StoreError | null;
16
21
  readonly storeNames: Stores[];
22
+ private inWrap;
23
+ readonly onRejection: (error: any) => never;
17
24
  /**
18
25
  * A record of store names to `IDBObjectStore` objects
19
26
  */
20
27
  private readonly objectStores;
21
- constructor(db: IDBDatabase, stores: Arrayable<Stores>, mode: Mode, options?: TransactionOptions);
28
+ constructor(transaction: Transaction<Mode, Stores>);
29
+ constructor(first: IDBDatabase, stores: Arrayable<Stores>, mode: Mode, options?: TransactionOptions);
30
+ /**
31
+ * Creates a new transaction, or, if an existing one is passed in, just returns the existing one
32
+ * @param db IndexedDB object
33
+ * @param stores List of store names
34
+ * @param mode Transaction mode
35
+ * @param existingTx Existing transaction
36
+ */
37
+ static create<Mode extends IDBTransactionMode, Stores extends string>(db: IDBDatabase, stores: Stores[], mode: Mode, existingTx?: Transaction<Mode, Stores>): Transaction<Mode, Stores>;
22
38
  abort(error: StoreError): StoreError;
23
39
  commit(): void;
24
40
  /**
@@ -29,11 +45,12 @@ export declare class Transaction<Mode extends IDBTransactionMode, Stores extends
29
45
  */
30
46
  getInternal(): IDBTransaction;
31
47
  getStore(store: Stores): ObjectStore;
48
+ getAllStores(): Map<Stores, ObjectStore<import('./util-types.js').Dict>>;
32
49
  get mode(): Mode;
33
50
  is(status: TransactionStatus): boolean;
34
51
  contains(stores: Arrayable<string>): boolean;
35
52
  assertIsArray(value: any, message?: string): asserts value is any[];
36
53
  private getObjectstore;
37
54
  private registerHandler;
38
- wrap<Output>(fn: (tx: this) => Promise<Output>): Promise<Output>;
55
+ wrap<Output>(fn: (tx: this) => Promisable<Output>): Promise<Output>;
39
56
  }
@@ -6,23 +6,24 @@ export type Arrayable<T> = T | T[];
6
6
  export type IsNever<T> = [T] extends [never] ? true : false;
7
7
  export type Promisable<T> = T | Promise<T>;
8
8
  export type NoUndefined<T> = Exclude<T, undefined>;
9
+ export type Extends<T, K> = T extends K ? true : false;
10
+ export type And<T, K> = T extends true ? K extends true ? true : false : false;
11
+ export type Or<T, K> = T extends true ? true : K extends true ? true : false;
9
12
  export type MakeOptional<B extends boolean, T> = B extends true ? T | undefined : T;
13
+ export type MakeRequired<B extends boolean, T> = B extends true ? NonNullable<T> : T;
14
+ export type Simplify<T> = {
15
+ [K in keyof T]: T[K];
16
+ } & {};
10
17
  export type MakeArray<B extends boolean, T> = B extends true ? T[] : T;
11
18
  export type MakeArrayable<B extends boolean, T> = B extends true ? Arrayable<T> : T;
12
- export type ValidKey = string | number | Date;
13
- export type ValidKeyType = "string" | "number" | "date";
14
19
  export type If<Type extends boolean, IfBranch, ElseBranch> = IsNever<Type> extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch;
15
20
  export type RemoveNeverValues<T extends object> = {
16
21
  [K in keyof T as T[K] extends never ? never : K]: T[K];
17
22
  };
23
+ /**
24
+ * A type representing a dictionary from string to some type
25
+ */
18
26
  export type Dict<T = unknown> = Record<string, T>;
19
- export type ConnectionObject<M extends boolean = false, T = object, K = ValidKey> = {
20
- $create: T;
21
- $connect: K;
22
- } & If<M, {
23
- $createMany: T[];
24
- $connectMany: K[];
25
- }, Dict>;
26
27
  type UndefinedKeys<T extends Dict> = {
27
28
  [K in Keyof<T>]: undefined extends T[K] ? K : never;
28
29
  }[Keyof<T>];
@@ -34,4 +35,12 @@ export type PartialOnUndefined<T extends Dict> = Required<T> & Optional<T>;
34
35
  */
35
36
  export type BooleanLike = boolean | undefined | null | 0;
36
37
  export type Literable = string | number | bigint | boolean | null | undefined;
38
+ export type SinglularKey<T extends Record<string, any>> = {
39
+ [K in keyof T]: {
40
+ [P in K]: T[P];
41
+ } & {
42
+ [Q in Exclude<keyof T, K>]?: never;
43
+ };
44
+ }[keyof T];
45
+ export type Ctor<T> = new (...args: any[]) => T;
37
46
  export {};
package/dist/utils.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { Arrayable, Keyof, ValidKeyType } from "./util-types";
2
- import type { Transaction } from "./transaction.js";
1
+ import { Arrayable, Keyof } from './util-types';
2
+ import { Transaction } from './transaction.js';
3
3
  export declare function handleRequest<T>(req: IDBRequest<T>, tx?: Transaction<any, any>): Promise<T>;
4
4
  export declare function getKeys<T extends object>(obj: T): Keyof<T>[];
5
5
  export declare function addToSet<T>(set: Set<T>, items: T[]): Set<T>;
6
6
  export declare function toArray<T>(value: Arrayable<T>): T[];
7
- export declare function stringTypeToEnum(type: ValidKeyType): Type;
8
7
  export declare function uuid(): `${string}-${string}-${string}-${string}-${string}`;
8
+ export declare function getDate(): Date;
9
9
  /**
10
10
  * Identity Function, it returns the first argument it is given, all others are ignored
11
11
  * @param value Value
@@ -16,14 +16,3 @@ export declare function identity<T>(value: T): T;
16
16
  * Performs a union over `set1` and `set2`, modifying `set1` to be union of the two sets
17
17
  */
18
18
  export declare function unionSets<T>(set: Set<T>, other: Set<T>): Set<T>;
19
- export declare enum Type {
20
- String = 0,
21
- Number = 1,
22
- BigInt = 2,
23
- Boolean = 3,
24
- Symbol = 4,
25
- Array = 5,
26
- Date = 6,
27
- Object = 7,
28
- Unknown = 8
29
- }
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@idb-orm/core",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "",
5
- "main": "dist/index.js",
5
+ "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "type": "module",
8
8
  "scripts": {
9
- "build": "rollup --config rollup.config.ts --configPlugin typescript",
10
- "watch": "rollup --watch --config rollup.config.ts --configPlugin typescript",
9
+ "build": "vite build",
10
+ "watch": "vite build --watch",
11
11
  "check": "eslint . && tsc -b --noEmit",
12
- "test": "playwright test"
12
+ "b": "vite build"
13
13
  },
14
14
  "keywords": [
15
15
  "typescript",
@@ -19,18 +19,14 @@
19
19
  "exports": {
20
20
  ".": {
21
21
  "types": "./dist/index.d.ts",
22
- "import": "./dist/index.js",
23
- "require": "./dist/index.js"
24
- },
25
- "./dev": {
26
- "types": "./dist/dev.d.ts",
27
- "default": "./dist/dev.d.ts"
22
+ "import": "./dist/index.es.js",
23
+ "require": "./dist/index.cjs.js"
28
24
  }
29
25
  },
30
26
  "license": "ISC",
31
27
  "devDependencies": {
32
28
  "@eslint/js": "^9.38.0",
33
- "@playwright/test": "^1.56.1",
29
+ "@rolldown/binding-win32-x64-msvc": "^1.0.0-beta.51",
34
30
  "@rollup/plugin-node-resolve": "^16.0.3",
35
31
  "@rollup/plugin-terser": "^0.4.4",
36
32
  "@rollup/plugin-typescript": "^12.1.4",
@@ -38,8 +34,11 @@
38
34
  "eslint": "^9.38.0",
39
35
  "rollup": "^4.52.4",
40
36
  "serve": "^14.2.5",
37
+ "terser": "^5.44.1",
41
38
  "tslib": "^2.8.1",
42
39
  "typescript": "^5.9.3",
43
- "typescript-eslint": "^8.46.2"
40
+ "typescript-eslint": "^8.46.2",
41
+ "vite": "^7.2.4",
42
+ "vite-plugin-dts": "^4.5.4"
44
43
  }
45
44
  }
@@ -1,4 +0,0 @@
1
- import { ParseFn, AbstractProperty, PropertyOptions } from "./field/property.js";
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 DELETED
@@ -1,5 +0,0 @@
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, };
@@ -1,9 +0,0 @@
1
- import z from "zod";
2
- export declare const DEFAULT_SCHEMA_MAP: {
3
- string: z.ZodString;
4
- boolean: z.ZodBoolean;
5
- number: z.ZodNumber;
6
- array: z.ZodArray<z.ZodAny>;
7
- object: z.ZodObject<{}, z.core.$loose>;
8
- date: z.ZodDate;
9
- };
@@ -1,40 +0,0 @@
1
- import z from "zod";
2
- import type { ValidKeyType } from "../types/common.js";
3
- import type { FieldOptions, FunctionMatch, ReferenceActions, RelationOptions } from "./field-types.js";
4
- import PrimaryKey from "./primary-key.js";
5
- import { Relation } from "./relation.js";
6
- export declare class Field<OutputType, HasDefault extends boolean = false> {
7
- schema: z.ZodType<OutputType>;
8
- private hasDefault;
9
- static readonly schemas: {
10
- string: z.ZodString;
11
- boolean: z.ZodBoolean;
12
- number: z.ZodNumber;
13
- array: z.ZodArray<z.ZodAny>;
14
- object: z.ZodObject<{}, z.core.$loose>;
15
- date: z.ZodDate;
16
- };
17
- private options;
18
- constructor(schema: z.ZodType<OutputType>, options?: Partial<FieldOptions>);
19
- array(): Field<OutputType[], false>;
20
- optional(): Field<OutputType | undefined, false>;
21
- default(defaultValue: Exclude<OutputType, undefined>): Field<Exclude<OutputType, undefined>, true>;
22
- refine(refineFn: (val: OutputType) => boolean): void;
23
- parse(value: unknown): z.ZodSafeParseResult<OutputType>;
24
- hasDefaultValue(): HasDefault;
25
- /**
26
- * Indicates that a field must be unique across all documents
27
- *
28
- * **NOTE**: The field type must be a primitive. If this is applied to a non-primitive, it returns `null`
29
- */
30
- unique(): OutputType extends string | number | boolean | symbol ? this : null;
31
- static array<T>(item: z.ZodType<T> | Field<T>, options?: FieldOptions): Field<T[], false>;
32
- static boolean(schema?: z.ZodType<boolean>, options?: FieldOptions): Field<boolean, false>;
33
- static custom<T>(schema: z.ZodType<T>, options?: FieldOptions): Field<T, false>;
34
- static object<T extends Record<string, z.ZodType>>(item: T, options?: FieldOptions): Field<z.core.$InferObjectOutput<{ -readonly [P in keyof T]: T[P]; }, {}>, false>;
35
- static primaryKey<V extends ValidKeyType = "number">(type?: V): PrimaryKey<false, FunctionMatch<V>>;
36
- static literal<V extends string | number | boolean>(value: V): Field<V, false>;
37
- static number(schema?: z.ZodType<number>, options?: FieldOptions): Field<number, false>;
38
- static string(schema?: z.ZodType<string>, options?: FieldOptions): Field<string, false>;
39
- static relation<To extends string, Name extends string = never>(to: To, options?: RelationOptions<Name, ReferenceActions>): Relation<To, Name>;
40
- }
package/dist/index.js DELETED
@@ -1 +0,0 @@
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};
@@ -1 +0,0 @@
1
- {"root":["../src/builder.ts","../src/error.ts","../src/index.ts","../src/object-store.ts","../src/transaction.ts","../src/types.ts","../src/utils.ts","../src/client/compiled-query.ts","../src/client/delete.ts","../src/client/helpers.ts","../src/client/index.ts","../src/client/types/find.ts","../src/client/types/index.ts","../src/client/types/mutation.ts","../src/field/field-types.ts","../src/field/index.ts","../src/field/primary-key.ts","../src/field/property.ts","../src/field/relation.ts","../src/model/index.ts","../src/model/model-types.ts","../src/model/model.ts","../tests/helpers.ts","../tests/test.spec.ts"],"version":"5.9.3"}
@@ -1,48 +0,0 @@
1
- /**
2
- * Extracts the string keys of an object
3
- */
4
- export type Keyof<T extends Record<any, any>> = Extract<keyof T, string>;
5
- export type Arrayable<T> = T | T[];
6
- export type IsNever<T> = [T] extends [never] ? true : false;
7
- export type Promisable<T> = T | Promise<T>;
8
- export type NoUndefined<T> = Exclude<T, undefined>;
9
- export declare enum Type {
10
- String = 0,
11
- Number = 1,
12
- BigInt = 2,
13
- Boolean = 3,
14
- Symbol = 4,
15
- Array = 5,
16
- Date = 6,
17
- Object = 7,
18
- Unknown = 8
19
- }
20
- export type MakeOptional<B extends boolean, T> = B extends true ? T | undefined : T;
21
- export type MakeArray<B extends boolean, T> = B extends true ? T[] : T;
22
- export type MakeArrayable<B extends boolean, T> = B extends true ? Arrayable<T> : T;
23
- export type ValidKey = string | number | Date;
24
- export type ValidKeyType = "string" | "number" | "date";
25
- export type If<Type extends boolean, IfBranch, ElseBranch> = IsNever<Type> extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch;
26
- export type RemoveNeverValues<T extends object> = {
27
- [K in keyof T as T[K] extends never ? never : K]: T[K];
28
- };
29
- export type Dict<T = unknown> = Record<string, T>;
30
- export type ConnectionObject<M extends boolean = false, T = object, K = ValidKey> = {
31
- $create: T;
32
- $connect: K;
33
- } & If<M, {
34
- $createMany: T[];
35
- $connectMany: K[];
36
- }, Dict>;
37
- type UndefinedKeys<T extends Dict> = {
38
- [K in Keyof<T>]: undefined extends T[K] ? K : never;
39
- }[Keyof<T>];
40
- type Optional<T extends Dict> = Partial<Pick<T, UndefinedKeys<T>>>;
41
- type Required<T extends Dict> = Omit<T, UndefinedKeys<T>>;
42
- export type PartialOnUndefined<T extends Dict> = Required<T> & Optional<T>;
43
- /**
44
- * Types that can be resolved to specific boolean values
45
- */
46
- export type BooleanLike = boolean | undefined | null | 0;
47
- export type Literable = string | number | bigint | boolean | null | undefined;
48
- export {};
package/dist/types.d.ts DELETED
@@ -1,48 +0,0 @@
1
- /**
2
- * Extracts the string keys of an object
3
- */
4
- export type Keyof<T extends Record<any, any>> = Extract<keyof T, string>;
5
- export type Arrayable<T> = T | T[];
6
- export type IsNever<T> = [T] extends [never] ? true : false;
7
- export type Promisable<T> = T | Promise<T>;
8
- export type NoUndefined<T> = Exclude<T, undefined>;
9
- export declare enum Type {
10
- String = 0,
11
- Number = 1,
12
- BigInt = 2,
13
- Boolean = 3,
14
- Symbol = 4,
15
- Array = 5,
16
- Date = 6,
17
- Object = 7,
18
- Unknown = 8
19
- }
20
- export type MakeOptional<B extends boolean, T> = B extends true ? T | undefined : T;
21
- export type MakeArray<B extends boolean, T> = B extends true ? T[] : T;
22
- export type MakeArrayable<B extends boolean, T> = B extends true ? Arrayable<T> : T;
23
- export type ValidKey = string | number | Date;
24
- export type ValidKeyType = "string" | "number" | "date";
25
- export type If<Type extends boolean, IfBranch, ElseBranch> = IsNever<Type> extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch;
26
- export type RemoveNeverValues<T extends object> = {
27
- [K in keyof T as T[K] extends never ? never : K]: T[K];
28
- };
29
- export type Dict<T = unknown> = Record<string, T>;
30
- export type ConnectionObject<M extends boolean = false, T = object, K = ValidKey> = {
31
- $create: T;
32
- $connect: K;
33
- } & If<M, {
34
- $createMany: T[];
35
- $connectMany: K[];
36
- }, Dict>;
37
- type UndefinedKeys<T extends Dict> = {
38
- [K in Keyof<T>]: undefined extends T[K] ? K : never;
39
- }[Keyof<T>];
40
- type Optional<T extends Dict> = Partial<Pick<T, UndefinedKeys<T>>>;
41
- type Required<T extends Dict> = Omit<T, UndefinedKeys<T>>;
42
- export type PartialOnUndefined<T extends Dict> = Required<T> & Optional<T>;
43
- /**
44
- * Types that can be resolved to specific boolean values
45
- */
46
- export type BooleanLike = boolean | undefined | null | 0;
47
- export type Literable = string | number | bigint | boolean | null | undefined;
48
- export {};