@idb-orm/core 1.0.8 → 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.
- package/dist/builder.d.ts +23 -0
- package/dist/client/compiled-query.d.ts +13 -0
- package/dist/client/delete.d.ts +13 -0
- package/dist/client/helpers.d.ts +18 -0
- package/dist/client/index.d.ts +59 -0
- package/dist/client/types/find.d.ts +29 -0
- package/dist/client/types/index.d.ts +63 -0
- package/dist/client/types/mutation.d.ts +49 -0
- package/dist/core.d.ts +11 -0
- package/dist/dump/class.d.ts +22 -0
- package/dist/dump/json.d.ts +9 -0
- package/dist/error.d.ts +223 -0
- package/dist/field/field-types.d.ts +37 -0
- package/dist/field/index.d.ts +6 -0
- package/dist/field/primary-key.d.ts +23 -0
- package/dist/field/property.d.ts +75 -0
- package/dist/field/relation.d.ts +96 -0
- package/dist/field/type-wrapper.d.ts +108 -0
- package/dist/field/validators.d.ts +13 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.es.js +2 -0
- package/dist/model/index.d.ts +3 -0
- package/dist/model/model-types.d.ts +41 -0
- package/dist/model/model.d.ts +40 -0
- package/dist/object-store.d.ts +28 -0
- package/dist/transaction.d.ts +56 -0
- package/dist/util-types.d.ts +46 -0
- package/dist/utils.d.ts +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Literable, NoUndefined, Promisable } from '../util-types.js';
|
|
2
|
+
import { FunctionMatch, PropertyUnion, ReferenceActions, RelationOptions, StringValidKeyType } from './field-types.js';
|
|
3
|
+
import { default as PrimaryKey } from './primary-key.js';
|
|
4
|
+
import { Relation } from './relation.js';
|
|
5
|
+
import { TypeTag } from './type-wrapper.js';
|
|
6
|
+
export interface PropertyOptions {
|
|
7
|
+
unique: boolean;
|
|
8
|
+
}
|
|
9
|
+
export type PropertyInputOptions = Partial<PropertyOptions>;
|
|
10
|
+
export interface CustomPropertyOptions<T> extends PropertyInputOptions {
|
|
11
|
+
isType: (test: unknown) => boolean;
|
|
12
|
+
serialize?: (value: T) => Promisable<unknown>;
|
|
13
|
+
deserialize?: (value: unknown) => Promisable<T>;
|
|
14
|
+
}
|
|
15
|
+
export type ParseResult<T> = {
|
|
16
|
+
success: true;
|
|
17
|
+
data: T;
|
|
18
|
+
error?: undefined;
|
|
19
|
+
} | {
|
|
20
|
+
success: false;
|
|
21
|
+
data?: undefined;
|
|
22
|
+
error: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A function to parse and validate an unknown value. It should also handle applying defaults
|
|
26
|
+
*/
|
|
27
|
+
export type ParseFn<T> = (value: unknown) => ParseResult<T>;
|
|
28
|
+
export declare abstract class AbstractProperty<Value, HasDefault extends boolean> {
|
|
29
|
+
protected parseFn: (value: unknown) => ParseResult<Value>;
|
|
30
|
+
protected type: TypeTag;
|
|
31
|
+
readonly symbol: symbol;
|
|
32
|
+
protected hasDefault: HasDefault;
|
|
33
|
+
protected options: PropertyOptions;
|
|
34
|
+
constructor(parseFn: (value: unknown) => ParseResult<Value>, type: TypeTag, options?: PropertyInputOptions);
|
|
35
|
+
get parse(): (value: unknown) => ParseResult<Value>;
|
|
36
|
+
getType(): TypeTag;
|
|
37
|
+
abstract array(...args: unknown[]): AbstractProperty<Value[], false>;
|
|
38
|
+
abstract default(defaultValue: NoUndefined<Value> | (() => NoUndefined<Value>)): AbstractProperty<NoUndefined<Value>, true>;
|
|
39
|
+
abstract optional(...args: unknown[]): AbstractProperty<Value | undefined, false>;
|
|
40
|
+
static array<T>(..._args: unknown[]): AbstractProperty<T[], false>;
|
|
41
|
+
static boolean(..._: unknown[]): AbstractProperty<boolean, false>;
|
|
42
|
+
static custom<T>(..._: unknown[]): AbstractProperty<T, false>;
|
|
43
|
+
static date(..._: unknown[]): AbstractProperty<Date, false>;
|
|
44
|
+
static literal<const V extends Literable>(_item: V, ..._: unknown[]): AbstractProperty<V, false>;
|
|
45
|
+
static number(..._: unknown[]): AbstractProperty<number, false>;
|
|
46
|
+
static union<const _T extends readonly AbstractProperty<any, boolean>[]>(..._: unknown[]): AbstractProperty<unknown, false>;
|
|
47
|
+
static set<T>(..._: unknown[]): AbstractProperty<Set<T>, false>;
|
|
48
|
+
static string(..._: unknown[]): AbstractProperty<string, false>;
|
|
49
|
+
/**
|
|
50
|
+
* Indicates that a field must be unique across all documents
|
|
51
|
+
*
|
|
52
|
+
* **NOTE**: The field type must be a primitive. If this is applied to a non-primitive, it returns `null`
|
|
53
|
+
*/
|
|
54
|
+
unique(): this;
|
|
55
|
+
hasDefaultValue(): HasDefault;
|
|
56
|
+
static relation<To extends string, const Name extends string = never>(to: To, options?: RelationOptions<Name, ReferenceActions>): Relation<To, Name>;
|
|
57
|
+
static primaryKey<V extends StringValidKeyType = "number">(type?: V): PrimaryKey<false, FunctionMatch<V>>;
|
|
58
|
+
static nameToType(typeName: string): TypeTag;
|
|
59
|
+
static is(value: any): value is AbstractProperty<any, any>;
|
|
60
|
+
}
|
|
61
|
+
export declare class Property<Value, HasDefault extends boolean> extends AbstractProperty<Value, HasDefault> {
|
|
62
|
+
array(): Property<Value[], false>;
|
|
63
|
+
default(defaultValue: NoUndefined<Value> | (() => NoUndefined<Value>)): Property<NoUndefined<Value>, true>;
|
|
64
|
+
optional(): Property<Value | undefined, false>;
|
|
65
|
+
static array<T>(item: Property<T, boolean>, options?: PropertyInputOptions): Property<T[], false>;
|
|
66
|
+
static boolean(options?: PropertyInputOptions): Property<boolean, false>;
|
|
67
|
+
static custom<T>(fn: ParseFn<T>, options?: PropertyInputOptions): Property<T, false>;
|
|
68
|
+
static date(options?: PropertyInputOptions): Property<Date, false>;
|
|
69
|
+
static literal<const V extends Literable>(value: V, options?: PropertyInputOptions): Property<V, false>;
|
|
70
|
+
static number(options?: PropertyInputOptions): Property<number, false>;
|
|
71
|
+
static string(options?: PropertyInputOptions): Property<string, false>;
|
|
72
|
+
static set<T>(item: Property<T, boolean>, options?: PropertyInputOptions): Property<Set<T>, false>;
|
|
73
|
+
static union<const T extends readonly AbstractProperty<any, boolean>[]>(items: T, options?: PropertyInputOptions): Property<PropertyUnion<T>, false>;
|
|
74
|
+
private static generateArrayValidator;
|
|
75
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { OptionalActions, ReferenceActions, RelationActions, RelationOptions } from './field-types.js';
|
|
2
|
+
export declare class BaseRelation<To extends string, Name extends string = never> {
|
|
3
|
+
/**
|
|
4
|
+
* The name of the model this relation is pointing to
|
|
5
|
+
*/
|
|
6
|
+
readonly to: To;
|
|
7
|
+
/**
|
|
8
|
+
* An optional label to give to the relation. This helps distinguish it from others
|
|
9
|
+
*/
|
|
10
|
+
readonly name: Name;
|
|
11
|
+
/**
|
|
12
|
+
* If the relation is optional or not
|
|
13
|
+
*/
|
|
14
|
+
readonly isOptional: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* If the relation is an array or not
|
|
17
|
+
*/
|
|
18
|
+
readonly isArray: boolean;
|
|
19
|
+
private static readonly SYMBOL;
|
|
20
|
+
protected readonly BASE_SYMBOL: symbol;
|
|
21
|
+
/**
|
|
22
|
+
* Actions to be performed under certain conditions
|
|
23
|
+
*/
|
|
24
|
+
protected actions: RelationActions;
|
|
25
|
+
/**
|
|
26
|
+
* The corresponding relation key on the model this relation points to
|
|
27
|
+
*/
|
|
28
|
+
private relatedKey;
|
|
29
|
+
constructor(
|
|
30
|
+
/**
|
|
31
|
+
* The name of the model this relation is pointing to
|
|
32
|
+
*/
|
|
33
|
+
to: To,
|
|
34
|
+
/**
|
|
35
|
+
* An optional label to give to the relation. This helps distinguish it from others
|
|
36
|
+
*/
|
|
37
|
+
name?: Name,
|
|
38
|
+
/**
|
|
39
|
+
* If the relation is optional or not
|
|
40
|
+
*/
|
|
41
|
+
isOptional?: boolean,
|
|
42
|
+
/**
|
|
43
|
+
* If the relation is an array or not
|
|
44
|
+
*/
|
|
45
|
+
isArray?: boolean, onDelete?: OptionalActions);
|
|
46
|
+
getActions(): {
|
|
47
|
+
onDelete: OptionalActions;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Whether or not this relation can have the "SetNull" onDelete action used against it
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
isNullable(): boolean;
|
|
54
|
+
setRelatedKey(key: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Gets the key on the corresponding model this relation points to
|
|
57
|
+
*/
|
|
58
|
+
getRelatedKey(): string;
|
|
59
|
+
toString(): string;
|
|
60
|
+
getBaseSymbol(): symbol;
|
|
61
|
+
static is(value: object): value is BaseRelation<any, any>;
|
|
62
|
+
}
|
|
63
|
+
export declare class Relation<To extends string, const Name extends string> extends BaseRelation<To, Name> {
|
|
64
|
+
private static readonly R_SYMBOL;
|
|
65
|
+
readonly symbol: symbol;
|
|
66
|
+
private readonly _brand;
|
|
67
|
+
constructor(to: To, options?: RelationOptions<Name, ReferenceActions>);
|
|
68
|
+
/**
|
|
69
|
+
* Creates an array relation to the specified model
|
|
70
|
+
*
|
|
71
|
+
* **Note: Calling this function will reset any relation actions to the default**
|
|
72
|
+
*/
|
|
73
|
+
array({ onDelete, }?: Omit<RelationOptions<Name, OptionalActions>, "name">): ArrayRelation<To, Name>;
|
|
74
|
+
/**
|
|
75
|
+
* Creates an optional relation to the specified model
|
|
76
|
+
*
|
|
77
|
+
* **Note: Calling this function will reset any relation actions to the default**
|
|
78
|
+
*/
|
|
79
|
+
optional({ onDelete, }?: Omit<RelationOptions<Name, OptionalActions>, "name">): OptionalRelation<To, Name>;
|
|
80
|
+
onDelete(action: ReferenceActions): this;
|
|
81
|
+
static is(value: object): value is Relation<any, any>;
|
|
82
|
+
}
|
|
83
|
+
export declare class ArrayRelation<To extends string, Name extends string> extends BaseRelation<To, Name> {
|
|
84
|
+
private static readonly A_SYMBOL;
|
|
85
|
+
readonly symbol: symbol;
|
|
86
|
+
private readonly _brand;
|
|
87
|
+
constructor(to: To, name?: Name, action?: OptionalActions);
|
|
88
|
+
static is(value: object): value is ArrayRelation<any, any>;
|
|
89
|
+
}
|
|
90
|
+
export declare class OptionalRelation<To extends string, Name extends string> extends BaseRelation<To, Name> {
|
|
91
|
+
private static readonly O_SYMBOL;
|
|
92
|
+
readonly symbol: symbol;
|
|
93
|
+
private readonly _brand;
|
|
94
|
+
constructor(to: To, name?: Name, action?: OptionalActions);
|
|
95
|
+
static is(value: object): value is OptionalRelation<any, any>;
|
|
96
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Literable, Promisable } from '../util-types.js';
|
|
2
|
+
declare const enum TypeLabel {
|
|
3
|
+
string = 0,
|
|
4
|
+
number = 1,
|
|
5
|
+
boolean = 2,
|
|
6
|
+
literal = 3,
|
|
7
|
+
date = 4,
|
|
8
|
+
symbol = 5,
|
|
9
|
+
bigint = 6,
|
|
10
|
+
array = 7,
|
|
11
|
+
set = 8,
|
|
12
|
+
union = 9,
|
|
13
|
+
optional = 10,
|
|
14
|
+
file = 11,
|
|
15
|
+
unknown = 12,
|
|
16
|
+
default = 13,
|
|
17
|
+
object = 14,
|
|
18
|
+
custom = 15
|
|
19
|
+
}
|
|
20
|
+
export interface StringTag {
|
|
21
|
+
tag: TypeLabel.string;
|
|
22
|
+
}
|
|
23
|
+
export interface NumberTag {
|
|
24
|
+
tag: TypeLabel.number;
|
|
25
|
+
}
|
|
26
|
+
export interface DateTag {
|
|
27
|
+
tag: TypeLabel.date;
|
|
28
|
+
}
|
|
29
|
+
interface BooleanTag {
|
|
30
|
+
tag: TypeLabel.boolean;
|
|
31
|
+
}
|
|
32
|
+
interface SymbolTag {
|
|
33
|
+
tag: TypeLabel.symbol;
|
|
34
|
+
}
|
|
35
|
+
interface BigIntTag {
|
|
36
|
+
tag: TypeLabel.bigint;
|
|
37
|
+
}
|
|
38
|
+
interface UnknownTag {
|
|
39
|
+
tag: TypeLabel.unknown;
|
|
40
|
+
}
|
|
41
|
+
interface FileTag {
|
|
42
|
+
tag: TypeLabel.file;
|
|
43
|
+
}
|
|
44
|
+
interface LiteralTag<V = unknown> {
|
|
45
|
+
tag: TypeLabel.literal;
|
|
46
|
+
value: V;
|
|
47
|
+
}
|
|
48
|
+
interface ArrayTag<V extends TypeTag = TypeTag> {
|
|
49
|
+
tag: TypeLabel.array;
|
|
50
|
+
of: V;
|
|
51
|
+
}
|
|
52
|
+
interface SetTag<V extends TypeTag = TypeTag> {
|
|
53
|
+
tag: TypeLabel.set;
|
|
54
|
+
of: V;
|
|
55
|
+
}
|
|
56
|
+
interface OptionalTag<V extends TypeTag = TypeTag> {
|
|
57
|
+
tag: TypeLabel.optional;
|
|
58
|
+
of: V;
|
|
59
|
+
}
|
|
60
|
+
interface UnionTag<V extends TypeTag[] = TypeTag[]> {
|
|
61
|
+
tag: TypeLabel.union;
|
|
62
|
+
options: V;
|
|
63
|
+
}
|
|
64
|
+
interface ObjectTag<P extends Record<string, TypeTag> = Record<string, TypeTag>> {
|
|
65
|
+
tag: TypeLabel.object;
|
|
66
|
+
props: P;
|
|
67
|
+
}
|
|
68
|
+
interface DefaultTag<V extends TypeTag = TypeTag> {
|
|
69
|
+
tag: TypeLabel.default;
|
|
70
|
+
of: V;
|
|
71
|
+
}
|
|
72
|
+
interface CustomTag<V = any> {
|
|
73
|
+
tag: TypeLabel.custom;
|
|
74
|
+
isType: (test: unknown) => boolean;
|
|
75
|
+
serialize?: (value: V) => Promisable<unknown>;
|
|
76
|
+
deserialize?: (value: unknown) => Promisable<V>;
|
|
77
|
+
}
|
|
78
|
+
export type TypeTag = LiteralTag | StringTag | NumberTag | DateTag | BooleanTag | SymbolTag | UnknownTag | FileTag | BigIntTag | SetTag | OptionalTag | UnionTag | ArrayTag | ObjectTag | DefaultTag | CustomTag;
|
|
79
|
+
export declare class Type {
|
|
80
|
+
static readonly String: StringTag;
|
|
81
|
+
static readonly Number: NumberTag;
|
|
82
|
+
static readonly Boolean: BooleanTag;
|
|
83
|
+
static readonly BigInt: BigIntTag;
|
|
84
|
+
static readonly Symbol: SymbolTag;
|
|
85
|
+
static readonly File: FileTag;
|
|
86
|
+
static readonly Date: DateTag;
|
|
87
|
+
static readonly Unknown: UnknownTag;
|
|
88
|
+
static Literal<const V extends Literable>(value: V): LiteralTag<V>;
|
|
89
|
+
static Array<V extends TypeTag>(element: V): ArrayTag<V>;
|
|
90
|
+
static Set<V extends TypeTag>(element: V): SetTag<V>;
|
|
91
|
+
static Union<const V extends TypeTag[]>(types: V): UnionTag<V>;
|
|
92
|
+
static Optional<V extends TypeTag>(type: V): OptionalTag<V>;
|
|
93
|
+
static Object<R extends Record<string, TypeTag>>(props: R): ObjectTag<R>;
|
|
94
|
+
static Custom<V>({ isType, serialize, deserialize, }: {
|
|
95
|
+
isType: (test: unknown) => boolean;
|
|
96
|
+
serialize?: (value: V) => unknown;
|
|
97
|
+
deserialize?: (value: unknown) => V;
|
|
98
|
+
}): CustomTag<V>;
|
|
99
|
+
/**
|
|
100
|
+
* Serialize's a type into JSON
|
|
101
|
+
* @param type Type
|
|
102
|
+
* @param value Value to serialize
|
|
103
|
+
*/
|
|
104
|
+
static serialize(type: TypeTag, value: unknown): Promise<unknown>;
|
|
105
|
+
static deserialize<T extends TypeTag>(type: T, value: unknown): Promise<unknown>;
|
|
106
|
+
static is<T extends TypeTag>(type: T, value: unknown): boolean;
|
|
107
|
+
}
|
|
108
|
+
export {};
|
|
@@ -0,0 +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,r){return class extends e{static code;constructor(e=r){super(t,e)}static of(e){new this(e)}}}const r=t("INVALID_CONFIG","Configuration is invalid"),n=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"),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"),f=t("OVERWRITE_RELATION","Relation cannot be overwritten"),w=t("EXPORT","Export failed");function p(e,t){return new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function m(e){return Object.keys(e)}function g(e){return Array.isArray(e)||(e=[e]),e}function b(){return crypto.randomUUID()}function S(){return new Date}function A(e){return e}function $(e,t){for(const r of t.keys())e.add(r);return e}class k{static String={tag:0};static Number={tag:1};static Boolean={tag:2};static BigInt={tag:6};static Symbol={tag:5};static File={tag:11};static Date={tag:4};static Unknown={tag:12};static Literal(e){return{tag:3,value:e}}static Array(e){return{tag:7,of:e}}static Set(e){return{tag:8,of:e}}static Union(e){return{tag:9,options:e}}static Optional(e){return{tag:10,of:e}}static Object(e){return{tag:14,props:e}}static Custom({isType:e,serialize:t,deserialize:r}){return{tag:15,isType:e,serialize:t,deserialize:r}}static async serialize(e,t){switch(e.tag){case 3:case 2:case 1:case 6:case 0:return t;case 5:return t.description;case 12:return JSON.stringify(t);case 4:return t.getTime();case 7:{const r=[];for(const n of t)r.push(await k.serialize(e.of,n));return r}case 8:{const r=new Set;for(const n of t)r.add(await k.serialize(e.of,n));return r}case 10:return void 0===t?null:await k.serialize(e.of,t);case 9:for(const r of e.options)if(k.is(r,t))return await k.serialize(r,t);throw new Error("Value union could not be serialized");case 11:if(!(t instanceof File))throw new Error("Value is not a valid file");return{data:new Promise((e,r)=>{const n=new FileReader;n.onload=()=>e(n.result),n.onerror=r,n.readAsDataURL(t)}),name:t.name};case 14:{if(!t||"object"!=typeof t)throw new Error("Value is not an object");const r={};for(const n in e.props){const s=e.props[n];if(!(n in t)&&10!==s.tag)throw new Error(`Required property '${n}' not found`);r[n]=await this.serialize(s,t[n])}return r}case 13:return this.serialize(e.of,t);case 15:return e.serialize?await e.serialize(t):JSON.stringify(t)}}static async deserialize(e,t){switch(e.tag){case 3:if(typeof t!=typeof e.value)throw new Error(`'${t}' is not equal to literal '${t}'`);return t;case 2:if("boolean"!=typeof t)throw new Error(`'${t}' is not a boolean`);return t;case 1:if("number"!=typeof t)throw new Error(`'${t}' is not a number`);return t;case 6:if("number"!=typeof t)throw new Error(`'${t}' is not a bigint`);return BigInt(t);case 0:if("string"!=typeof t)throw new Error(`'${t}' is not a string`);return t;case 5:if("string"!=typeof t)throw new Error(`'${t}' is not a symbol`);return Symbol.for(t);case 4:if(!(t instanceof Date))throw new Error(`'${t}' is not a date`);return t;case 7:if(!Array.isArray(t))throw new Error(`'${t}' is not an array`);return t;case 8:if(!Array.isArray(t))throw new Error(`'${t}' is not an array`);return new Set(t);case 10:return k.deserialize(e.of,t);case 12:return JSON.parse(t);case 9:{let r,n=!1;for(const s of e.options){try{r=k.deserialize(s,t),n=!0}catch{n=!1}if(n)break}if(!n)throw new Error("Value did not match the union");return r}case 11:{if(!t||"object"!=typeof t||!("data"in t)||!("name"in t)||"string"!=typeof t.data||"string"!=typeof t.name)throw new Error("Value is not a valid file schema");const e=await fetch(t.data);return new File([await e.blob()],t.name)}case 13:return this.deserialize(e.of,t);case 15:if(e.isType(t))return e.deserialize?await e.deserialize(t):JSON.parse(String(t));throw new Error("Value is not valid");case 14:{if(!t||"object"!=typeof t)throw new Error("Value is not an object");const r={};for(const n in e.props){const s=e.props[n];if(!(n in t)&&10!==s.tag)throw new Error(`Required property '${n}' not found`);r[n]=await this.deserialize(s,t[n])}return r}}}static is(e,t){switch(e.tag){case 3:return t===e.value;case 2:return"boolean"==typeof t;case 1:return"number"==typeof t;case 6:return"bigint"==typeof t;case 0:return"string"==typeof t;case 5:return"symbol"==typeof t;case 12:return!0;case 4:return t instanceof Date;case 7:return Array.isArray(t)&&t.every(t=>k.is(e.of,t));case 8:return t instanceof Set&&Array.from(t).every(t=>k.is(e.of,t));case 10:return void 0===t||this.is(e.of,t);case 9:return e.options.some(e=>k.is(e,t));case 11:return t instanceof File;case 14:return!(!t||"object"!=typeof t)&&Object.keys(e.props).every(r=>k.is(e.props[r],t[r]));case 13:return this.is(e.of,t);case 15:return e.isType(t)}}}function R(e){return t=>typeof t===e?{success:!0,data:t}:{success:!1,error:"Value is not a string"}}const v={[k.String.tag]:R("string"),[k.Number.tag]:R("number"),[k.BigInt.tag]:R("bigint"),[k.Boolean.tag]:R("boolean"),[k.Symbol.tag]:R("symbol"),[k.Unknown.tag]:e=>({success:!0,data:e}),[k.Date.tag]: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"}},K=Symbol.for("primaryKey");class N{symbol=K;genFn;autoGenerate;type;constructor(e,t){if(e){if(e>k.Date)throw new r("Invalid Primary Key Type");this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1}else this.autoGenerate=!1,this.type=k.Number}getType(){return this.type}generator(e){return this.genFn=e,this.autoGenerate=!0,this}autoIncrement(){if(this.type===k.Number)return this.genFn=void 0,this.autoGenerate=!0,this;throw new r("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 N(k.String,b)}date(){return new N(k.Date,S)}genKey(){if(this.genFn)return this.genFn();throw new Error("Generator function not defined")}getSchema(){return v[this.type.tag]}isAutoIncremented(){return this.autoGenerate&&!this.genFn}static is(e){return e?.symbol===K}}class O{constructor(e,t="",r=!1,n=!1,s){this.to=e,this.name=t,this.isOptional=r,this.isArray=n,this.relatedKey="",this.actions={onDelete:s||"Restrict"}}static SYMBOL=Symbol.for("baseRelation");BASE_SYMBOL=O.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()===O.SYMBOL}}class M extends O{static R_SYMBOL=Symbol.for("relation");symbol=M.R_SYMBOL;constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new D(this.to,this.name,e)}optional({onDelete:e}={}){return new I(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}static is(e){return e?.symbol===this.R_SYMBOL}}class D extends O{static A_SYMBOL=Symbol.for("arrayRelation");symbol=D.A_SYMBOL;constructor(e,t,r="None"){super(e,t,!1,!0,r)}static is(e){return e?.symbol===this.A_SYMBOL}}class I extends O{static O_SYMBOL=Symbol.for("optionalRelation");symbol=I.O_SYMBOL;constructor(e,t,r="None"){super(e,t,!0,!1,r)}static is(e){return e?.symbol===this.O_SYMBOL}}var E=(e=>(e[e.Property=0]="Property",e[e.Relation=1]="Relation",e[e.PrimaryKey=2]="PrimaryKey",e[e.Invalid=3]="Invalid",e))(E||{});const j=Symbol.for("property");class x{constructor(e,t,r){this.parseFn=e,this.type=t,this.options={unique:r?.unique??!1}}symbol=j;hasDefault=!1;options;get parse(){return this.parseFn}getType(){return this.type}static array(...e){throw new Error("Method Not Implemented")}static boolean(...e){throw new Error("Method Not Implemented")}static custom(...e){throw new Error("Method Not Implemented")}static date(...e){throw new Error("Method Not Implemented")}static literal(e,...t){throw new Error("Method Not Implemented")}static number(...e){throw new Error("Method Not Implemented")}static union(...e){throw new Error("Method Not Implemented")}static set(...e){throw new Error("Method Not Implemented")}static string(...e){throw new Error("Method Not Implemented")}unique(){switch(this.type){case k.Boolean:case k.String:case k.Number:case k.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 M(e,t)}static primaryKey(e="number"){return new N(this.nameToType(e))}static nameToType(e){switch(e){case"boolean":return k.Boolean;case"bigint":return k.BigInt;case"number":case"string":return k.Number;case"symbol":return k.Symbol;default:return k.Unknown}}static is(e){return"object"==typeof e&&e?.symbol===j}}class F extends x{array(){return new F(F.generateArrayValidator(this.parseFn),k.Array(this.type),this.options)}default(e){return this.hasDefault=!0,new F(t=>null==t?{success:!0,data:"function"==typeof e?e():e}:this.parseFn(t),this.type,this.options)}optional(){return new F(e=>null==e?{success:!0,data:void 0}:this.parseFn(e),this.type,this.options)}static array(e,t){return new F(F.generateArrayValidator(e.parseFn),k.Array(e.type),t)}static boolean(e){return new F(e=>"boolean"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},k.Boolean,e)}static custom(e,t){return new F(e,k.Unknown,t)}static date(e){return new F(v[k.Date.tag],k.Date,e)}static literal(e,t){return new F(t=>t===e?{success:!0,data:e}:{success:!1,error:`${t} !== ${e}`},k.Literal(e),t)}static number(e){return new F(v[k.Number.tag],k.Number,e)}static string(e){return new F(v[k.String.tag],k.String,e)}static set(e,t){return new F(t=>{if(t instanceof Set){const r=new Set;for(const n of t){const t=e.parseFn(n);if(!t.success)return t;r.add(t.data)}return{success:!0,data:r}}return{success:!1,error:"Value is not an array"}},k.Set(e.type),t)}static union(e,t){const r=e.map(e=>e.parse);return new F(e=>{for(const t of r){const r=t(e);if(r.success)return r}return{success:!1,error:"Value did not match any of the items"}},k.Union(e.map(e=>e.getType())),t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const r=[];for(const n of t){const t=e(n);if(!t.success)return t;r.push(t.data)}return{success:!0,data:r}}return{success:!1,error:"Value is not an array"}}}}const T=Symbol.for("model");class P{constructor(t,r){this.name=t,this.fields=r,this.fieldKeys=m(r);for(const e of this.fieldKeys){const t=this.fields[e];O.is(t)&&t.to!==this.name&&this.relationLinks.add(t.to)}const n=this.fieldKeys.find(e=>N.is(this.fields[e]));if(!n)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=n}symbol=T;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&&O.is(t))return t}keyType(e){const t=this.fields[e];return t?x.is(t)?E.Property:O.is(t)?E.Relation:N.is(t)?E.PrimaryKey:E.Invalid:E.Invalid}links(){return this.relationLinks.keys()}*relations(){for(const e of this.fieldKeys)O.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 x.is(this.fields[e])?this.fields[e].parse(t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=new Set,r=[this.name];let n;for(;r.length>0;){const s=r.shift();if(t.has(s))continue;n=e.getModel(s);const a=n.cache.delete;if(a)$(t,a);else{t.add(s);for(const e of n.links())t.has(e)||r.push(e)}}return this.cache.delete=t,t}static is(e){return e?.symbol===T}}class L{constructor(e,t){this.tx=e,this.store=t}add(e){return this.handleRequest(this.store.add(e),()=>new d)}get(e){return this.handleRequest(this.store.get(e),()=>new y)}async assertGet(e){const t=await this.handleRequest(this.store.get(e),()=>new y);if(!t)throw this.tx.abort(new l);return t}put(e){return this.handleRequest(this.store.put(e),()=>new u)}delete(e){return this.handleRequest(this.store.delete(e),()=>new i)}async openCursor(t,r={}){const n=r.onError||(()=>new h),s=this.store.openCursor(r.query,r.direction);await new Promise((r,a)=>{s.onsuccess=async s=>{try{s.target||a(this.tx.abort(n()));const e=s.target.result;e&&await t(e,this.tx)||r()}catch(i){a(this.tx.abort(i instanceof e?i:new o(String(i))))}},s.onerror=()=>{a(this.tx.abort(n()))}})}handleRequest(e,t){return new Promise(r=>{e.onsuccess=()=>{r(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class _{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,r,n={}){e instanceof _?(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,r),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,n.onAbort),this.internal.onerror=this.registerHandler(3,n.onError),this.internal.oncomplete=this.registerHandler(2,n.onComplete))}static create(e,t,r,n){return n||new _(e,t,r)}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 n(`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 L(this,this.internal.objectStore(e))}catch{throw this.abort(new c(`No ObjectStore with the name '${e}' found`))}}registerHandler(e,t=()=>{}){return r=>{this.status=e,t(this,r)}}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(r){throw this.inWrap=!1,r instanceof e?this.abort(r):this.abort(new o(JSON.stringify(r)))}}}function B(e){if(!e)return[];const t=[];for(const r in e)if(Object.hasOwn(e,r))switch(typeof e[r]){case"function":t.push([r,!0,e[r]]);break;case"object":if(e[r]instanceof Date){const n=e[r];t.push([r,!0,e=>e instanceof Date&&e.getTime()===n.getTime()])}break;default:t.push([r,!1,e[r]])}return t}function V(e,t){if(!t||"object"!=typeof t)return!1;for(const r of e)if(r[1]){if(!r[2](t[r[0]]))return!1}else if(r[2]!==t[r[0]])return!1;return!0}function C(e,t,r={},n){const a=t.getModel(e);if(r.include&&r.select)throw new s("include and select cannot both be defined");const o=B(r.where),i=r.select?"select":r.include?"include":"";if(i){const e=r[i],n=!!r.select,s=[];for(const r in e)if(Object.hasOwn(e,r)&&e[r])switch(a.keyType(r)){case E.Relation:{const n=a.getRelation(r),o="object"==typeof e[r]?C(n.to,t,e[r]):A,i=n.getRelatedKey();if(n.isArray){const e=async(e,t)=>{const r=[],s=t.getStore(n.to);for(const n of e){const e=await o(await s.assertGet(n),t);e&&(delete e[i],r.push(e))}return r};s.push({key:r,getValue:e})}else{const e=async(e,t)=>await o(await t.getStore(n.to).assertGet(e),t);s.push({key:r,getValue:e})}break}case E.Property:case E.PrimaryKey:n&&s.push({key:r})}return n?async(e,t)=>{if(!V(o,e))return;const r={};for(const{key:n,getValue:a}of s)r[n]=a?await a(e[n],t):e[n];return r}:async(e,t)=>{if(V(o,e)){for(const{key:r,getValue:n}of s)e[r]=await n(e[r],t);return e}}}return e=>V(o,e)?e:void 0}function z(e,t,r,n){const s=new Set([e]);if(r){const a=m(t),o=n.getModel(e);for(const e of a){const a=o.getRelation(e),i=g(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":$(s,o.getDeletedStores(n));break;case"$create":$(s,z(a.to,e[t],r,n));break;case"$createMany":e[t].forEach(e=>$(s,z(a.to,e,r,n)));break;case"$update":$(s,z(a.to,e[t].data,r,n));break;case"$updateMany":e[t].forEach(e=>$(s,z(a.to,e.data,r,n)))}}}else{const r=n.getModel(e);for(const e of m(t)){const a=r.getRelation(e);if(a)switch(typeof t[e]){case"object":$(s,z(a.to,U(t[e]),!1,n));break;case"boolean":s.add(a.to)}}}return s}function U(e){return e.select?e.select:e.include?e.include:{}}class q{constructor(e,t,r){this.client=e,this.name=t,this.accessedStores=Array.from(z(t,U(r),!1,this.client)),this.selectClause=C(t,this.client,r)}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 r=[],n=t.getStore(this.name);return await n.openCursor(async n=>{const s=await this.selectClause(n.value,t);return s&&r.push(s),(!e||!r.length)&&(n.continue(),!0)}),r})}}function G(e,t,n){return async s=>{if(!s)return!1;const a=s[e.primaryKey];for(const[o,c]of e.relations()){const{onDelete:l}=c.getActions(),u=s[o],d=t.getModel(c.to);switch(l){case"Cascade":if(c.isArray){n.assertIsArray(u);const e=new Set(u),r=G(d,t,n),s=n.getStore(c.to);await s.openCursor(async t=>(e.has(t.value[d.primaryKey])&&await r(t.value),t.continue(),!0)).catch(n.onRejection)}else u&&await Y(c.to,t,void 0,void 0,{tx:n,singleton:{id:u}});break;case"SetNull":{if(!u)break;const e=g(u),t=n.getStore(c.to),s=c.getRelatedKey(),o=d.getRelation(s);if(!o)throw new r(`Relation '${c.name}' has an invalid relation key '${c.getRelatedKey()}'`);if(!o.isNullable())throw new r(`Key '${s}' on model '${s}': Non-optional relation cannot have the 'SetNull' action`);for(const r of e){const e=await t.get(r);if(!e)continue;const i=e[s];if(o.isArray){n.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(u)&&u.length>0||u)throw new i(`Key '${o}' on model '${e.name}' deletion is restricted while there is an active relation`)}}return!0}}async function Y(e,t,r,n=!1,s={}){const{singleton:a,finalStep:o=!0}=s,i=t.getModel(e),c=s.tx?s.tx.storeNames:Array.from(i.getDeletedStores(t)),l=_.create(t.getDb(),c,"readwrite",s.tx);return await l.wrap(async s=>{const c=s.getStore(e);let l=0;const u=G(i,t,s);if(a)await u(await c.assertGet(a.id))&&(await c.delete(a.id),l++);else{const e=B(r);let t;await c.openCursor(async r=>{const a=r.value;return V(e,a)&&await u(a)&&(t=p(r.delete()).catch(s.onRejection)),!(n&&l>0)&&(r.continue(),!0)}),t&&o&&await t}return l})}class J{constructor(e,t,r){this.name=e,this.content=t,this.extension=r}download(e=`${this.name}_dump.${this.extension}`,t){const r=URL.createObjectURL(this.toFile(e,t)),n=document.createElement("a");n.href=r,n.download=e,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(r)}}class W extends J{constructor(e,t){super(e,t,"json")}getValue(){return this.content}toFile(e=`${this.name}_dump.json`,t={}){return new File([JSON.stringify(this.content,void 0,4)],e,t)}}class H extends J{constructor(e,t){super(e,t,"csv")}getValue(){return this.content}toFile(e=`${this.name}_dump.csv`,t){return new File([this.content],e,t)}}function Q(e){return"string"!=typeof e?`${e}`:e.replaceAll(/~/g,"~0").replaceAll(/\//g,"~1")}async function X(e,t,r,n){n=_.create(e.getDb(),[t],"readonly",n);const s=B(r),o=e.getModel(t);return new W(t,await n.wrap(async e=>{const r={};return await e.getStore(t).openCursor(async e=>{if(V(s,e.value)){for(const[t,r]of o.entries())if(O.is(r))if(r.isArray){if(!Array.isArray(e.value[t]))throw new a("Expected array type");const n=[];for(const s of e.value[t])n.push(`/${r.to}/${Q(s)}`);e.value[t]=n}else(r.isOptional&&e.value[t]||!r.isNullable())&&(e.value[t]=`/${r.to}/${Q(e.value[t])}`);else{if(!F.is(r)&&!N.is(r))throw new w(`Unrecognized model field on key '${t}'`);e.value[t]=await k.serialize(r.getType(),e.value[t])}if(r[e.value[o.primaryKey]])throw new w("Duplicate primary key detected "+JSON.stringify(r));r[e.value[o.primaryKey]]=e.value}return e.continue(),!0}),r}))}class Z{constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const r of this.models.keys())this.stores[r]=this.createInterface(r)}name;version;stores;getDb(){return this.db}getStore(e){return this.stores[e]}getStoreNames(){return this.models.keys()}createTransaction(e,t,r){return new _(this.db,t,e,r)}async deleteDb(){await p(window.indexedDB.deleteDatabase(this.name))}async dump(e,t){return"json"===e?await async function(e,t){const r={};t=t||e.getStoreNames();const n=e.createTransaction("readonly",t);for(const s of t)r[s]=(await X(e,s,void 0,n)).getValue();return new W(e.name,r)}(this,t):new H("d","")}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,r,n){return n?n.storeNames:Array.from(z(e,t,r,this))}createInterface(e){return{add:async(t,r)=>await this.add(e,t,{tx:r}),addMany:async(t,r)=>{if(!r){const n=new Set;for(const r of t)$(n,z(e,r,!0,this));r=this.createTransaction("readwrite",Array.from(n))}const n=[];for(const s of t)n.push(await this.add(e,s,{tx:r}));return n},findFirst:async(t,r)=>(await this.find(e,t,!0,{tx:r}))[0],find:async(t,r)=>await this.find(e,t,!1,{tx:r}),get:async t=>{const r=this.createTransaction("readonly",e);return await r.getStore(e).get(t)},update:async(t,r)=>(await this.update(e,{data:r},!0,{singleton:{id:t}}))[0],updateFirst:async(t,r)=>(await this.update(e,t,!0,{tx:r}))[0],updateMany:async(t,r)=>await this.update(e,t,!1,{tx:r}),compileQuery:t=>new q(this,e,t),delete:async t=>await Y(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await Y(e,this,t,!0)>0,deleteMany:async t=>await Y(e,this,t,!1),dump:async(t,r)=>"json"===t?await X(this,e,r):new H("","")}}async add(e,t,r={}){let{tx:n}=r;const{relation:a}=r,i=this.getAccessedStores(e,t,!0,n);return n=_.create(this.db,i,"readwrite",n),await n.wrap(async r=>{const n=r.getStore(e),i=this.getModel(e),c=i.getPrimaryKey(),l=a?{[a.key]:i.getRelation(a.key)?.isArray?[a.id]:a.id}:{},u=c.isAutoIncremented()?{...l}:{...l,[i.primaryKey]:t[i.primaryKey]??c.genKey()},d=await n.add(u),h={},y=new Set;for(const a of m(t)){y.add(a);const n=t[a];switch(i.keyType(a)){case E.Invalid:throw new s(`Key '${a}' does ont exist on model '${e}'`);case E.Property:{const e=i.parseField(a,n);if(!e)throw new o;if(!e.success)throw new s(`Key '${a}' has the following validation error: ${e.error}`);h[a]=e.data;break}case E.Relation:{if(!n)continue;const e=g(n),t=i.getRelation(a);if(t.isArray&&(h[a]=[],"$createMany"in n||"$connectMany"in n)){const t=[];for(const e of n.$createMany??[])t.push({$create:e});for(const e of n.$connectMany??[])t.push({$connect:e});e.push(...t)}const o=this.getModel(t.to).getRelation(t.getRelatedKey()),c=new Set;for(const n of e){const e=m(n)[0];if(!e)throw new s(`Key '${a}' cannot be an empty connection object`);switch(e){case"$connect":{const i=n[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,d,i,r),t.isArray?h[a].push(i):h[a]=i;break}case"$create":{const s=await this.add(t.to,n[e],{tx:r,relation:{id:d,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 E.PrimaryKey:}}const f=Array.from(new Set(i.keys()).difference(y));for(const e of f)switch(i.keyType(e)){case E.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`);h[e]=t.data;break}case E.Relation:{const t=i.getRelation(e),r=l[e];if(t.isArray)h[e]=r??[];else if(t.isOptional)h[e]=r??null;else{if(!r)throw new s(`Required relation '${e}' is not defined`);h[e]=r}break}case E.Invalid:case E.PrimaryKey:}return await n.put({[i.primaryKey]:d,...h})})}async clear(e,t){await Y(e,this,void 0,!1,t)}async find(e,t,r,n={}){let{tx:s}=n;const a=this.getAccessedStores(e,U(t),!1,s);s=_.create(this.db,a,"readonly",s);const o=[];return await s.wrap(async n=>{const s=n.getStore(e),a=C(e,this,t);return await s.openCursor(async e=>{const t=await a(e.value,n);return t&&o.push(t),(!r||!o.length)&&(e.continue(),!0)}),o})}async update(e,t,r,n={}){const{singleton:a}=n,i=n.singleton?t:t.data,c=this.getAccessedStores(e,i,!0,n.tx),d=_.create(this.db,c,"readwrite",n.tx);return await d.wrap(async n=>{const c=n.getStore(e),d=this.getModel(e),h=[];for(const e of m(i))switch(d.keyType(e)){case E.Property:h.push({key:e,isRelation:!1,updateFn:"function"==typeof i[e]?i[e]:()=>i[e]});break;case E.Relation:{const t=g(i[e]);if(!t)continue;const r=[];for(const e of t)for(const t in e){switch(t){case"$createMany":case"$connectMany":case"$updateMany":case"$deleteMany":case"$disconnectMany":{const n=t.substring(0,t.length-4);for(const s of e[t])r.push([n,s]);break}default:r.push([t,e[t]])}break}h.push({actions:r,key:e,isRelation:!0,relation:d.getRelation(e)});break}case E.PrimaryKey:throw new u("Primary key field cannot be updated");case E.Invalid:default:throw new o(`Unknown key '${e}'`)}const y=[],f=async e=>{const t=e[d.primaryKey];for(const{key:r,...a}of h){const o=a.relation;if(a.isRelation)for(const[i,c]of a.actions)switch(i){case"$connect":e[r]&&!o.isArray&&await this.disconnectDocument(o,t,e[r],n).catch(n.onRejection),await this.connectDocument(o,t,c,n).catch(n.onRejection),o.isArray?e[r].push(c):e[r]=c;break;case"$create":{const s=await this.add(o.to,c,{tx:n,relation:{id:t,key:o.getRelatedKey()}});o.isArray?e[r].push(s):e[r]=s;break}case"$delete":if(!o.isNullable())throw new s("Item cannot be deleted, relation is required");e[r]=o.isArray&&Array.isArray(e[r])?e[r].filter(e=>e!==c):null,await Y(o.to,this,{},!0,{tx:n,singleton:{id:c}});break;case"$disconnect":{if(!o.isNullable())throw new s("Item cannot be disconnected, relation is required");if(!e[r]||0===e[r]?.lenth)break;const a=this.getModel(o.to).getRelation(o.getRelatedKey());await this.disconnectDocument(o,t,a.isArray?c:e[r],n).catch(n.onRejection),e[r]=o.isArray&&Array.isArray(e[r])?e[r].filter(e=>e!==c):null;break}case"$update":o.isArray?await this.update(o.to,c,!1,{tx:n}):null!=e[r]&&await this.update(o.to,c,!1,{tx:n,singleton:{id:t}});break;case"$deleteAll":if(c&&o.isArray&&Array.isArray(e[r])){const t=this.getModel(o.to),s=new Set(e[r]);await Y(o.to,this,{[t.primaryKey]:e=>s.has(e)},!1,{tx:n}),e[r]=[]}break;case"$disconnectAll":if(c&&o.isArray&&Array.isArray(e[r])){for(const s of e[r])await this.disconnectDocument(o,t,s,n);e[r]=[]}}else e[r]=a.updateFn(e[r])}return e};if(a){const e=await c.get(a.id);if(!e)throw new l(`${d.name} with priamry key '${a.id}' not found`);const t=await f(e).catch(n.onRejection);return await c.put(t),[t]}{const e=B(t.where);return await c.openCursor(async t=>{const s=t.value;if(V(e,s)){const e=await f(s).catch(n.onRejection);if(await p(t.update(e)).then(()=>y.push(e)).catch(n.onRejection),r)return!1}return t.continue(),!0}),y}})}async connectDocument(e,t,r,n){const s=n.getStore(e.to),a=await s.get(r);if(!a)throw new l(`Document with Primary Key '${r}' 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 f;a[o]=t}return await s.put(a).catch(n.onRejection),r}async disconnectDocument(e,t,r,n){const s=n.getStore(e.to),a=await s.get(r);if(!a)throw new l(`Document with Primary Key '${r}' 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 f;a[e.getRelatedKey()]=null}return await s.put(a).catch(n.onRejection),r}}class ee{constructor(e,t){this.name=e,this.models=t,this.modelKeys=m(this.models),this.schemas={};for(const n of this.modelKeys){const e=this.models[n],t={};for(const s of e.keys()){const a=e.get(s);if(x.is(a))t[s]=a.parse;else if(O.is(a)){const{onDelete:o}=a.getActions(),i=this.models[a.to],c=i.getPrimaryKey();t[s]=v[c.type.tag],a.isOptional?t[s]=new F(t[s],c.type).optional().parse:a.isArray&&(t[s]=t[s]=new F(t[s],c.type).array().parse);let l=!!a.getRelatedKey();if(!l)for(const[t,n]of i.relations())if(s!==t&&n.to===e.name&&n.name===a.name){if(l=!0,a.setRelatedKey(t),n.setRelatedKey(s),"SetNull"===o&&!n.isNullable())throw new r(`Key '${t}' on model '${i.name}': Non-optional relation cannot have the 'SetNull' action`);break}if(!l)throw new r(`Relation '${a.name}' of model ${n} does not have an equivalent relation on model '${a.to}'`)}else{if(!N.is(a))throw new r(`Unknown field value detected: ${JSON.stringify(a)}`);t[s]=v[a.type.tag]}}this.schemas[n]=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 r of this.modelKeys){const e=this.models[r];t.objectStoreNames.contains(e.name)||t.createObjectStore(e.name,{autoIncrement:e.getPrimaryKey().isAutoIncremented(),keyPath:e.primaryKey})}};const r=await p(t);return new Z(r,this)}keys(){return[...this.modelKeys]}}const te=Object.freeze(Object.defineProperty({__proto__:null,AbstractProperty:x,ArrayRelation:D,BaseRelation:O,DbClient:Z,FieldTypes:E,Model:P,OptionalRelation:I,PrimaryKey:N,Property:F,Relation:M,Type:k,VALIDATORS:v},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&&P.is(e))return this.models[e.name]=e,e;{if(!t)throw new Error("Model Fields must be defined");const r=new P(e,t);return this.models[e]=r,r}}compile(e){return new ee(this.name,e)}},exports.CompiledQuery=q,exports.Model=P,exports.Property=F,exports.StoreError=e,exports.core=te;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Builder } from './builder.js';
|
|
2
|
+
import { StoreError, ErrorType } from './error.js';
|
|
3
|
+
export { Builder, StoreError, ErrorType };
|
|
4
|
+
export { Property } from './field';
|
|
5
|
+
export { CompiledQuery } from './client/compiled-query.js';
|
|
6
|
+
export { Model } from './model';
|
|
7
|
+
export type { ModelType } from './model';
|
|
8
|
+
import * as core from "./core.js";
|
|
9
|
+
export { core };
|
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
class e extends Error{code;constructor(e,t){super(`(${e}) ${t}`),this.code=e}}function t(t,r){return class extends e{static code;constructor(e=r){super(t,e)}static of(e){new this(e)}}}const r=t("INVALID_CONFIG","Configuration is invalid"),n=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"),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"),f=t("OVERWRITE_RELATION","Relation cannot be overwritten"),w=t("EXPORT","Export failed");function p(e,t){return new Promise(t=>{e.onsuccess=()=>{t(e.result)},e.onerror=()=>{}})}function m(e){return Object.keys(e)}function g(e){return Array.isArray(e)||(e=[e]),e}function b(){return crypto.randomUUID()}function S(){/* @__PURE__ */
|
|
2
|
+
return new Date}function A(e){return e}function $(e,t){for(const r of t.keys())e.add(r);return e}class k{static String={tag:0};static Number={tag:1};static Boolean={tag:2};static BigInt={tag:6};static Symbol={tag:5};static File={tag:11};static Date={tag:4};static Unknown={tag:12};static Literal(e){return{tag:3,value:e}}static Array(e){return{tag:7,of:e}}static Set(e){return{tag:8,of:e}}static Union(e){return{tag:9,options:e}}static Optional(e){return{tag:10,of:e}}static Object(e){return{tag:14,props:e}}static Custom({isType:e,serialize:t,deserialize:r}){return{tag:15,isType:e,serialize:t,deserialize:r}}static async serialize(e,t){switch(e.tag){case 3:case 2:case 1:case 6:case 0:return t;case 5:return t.description;case 12:return JSON.stringify(t);case 4:return t.getTime();case 7:{const r=[];for(const n of t)r.push(await k.serialize(e.of,n));return r}case 8:{const r=/* @__PURE__ */new Set;for(const n of t)r.add(await k.serialize(e.of,n));return r}case 10:return void 0===t?null:await k.serialize(e.of,t);case 9:for(const r of e.options)if(k.is(r,t))return await k.serialize(r,t);throw new Error("Value union could not be serialized");case 11:if(!(t instanceof File))throw new Error("Value is not a valid file");return{data:new Promise((e,r)=>{const n=new FileReader;n.onload=()=>e(n.result),n.onerror=r,n.readAsDataURL(t)}),name:t.name};case 14:{if(!t||"object"!=typeof t)throw new Error("Value is not an object");const r={};for(const n in e.props){const s=e.props[n];if(!(n in t)&&10!==s.tag)throw new Error(`Required property '${n}' not found`);r[n]=await this.serialize(s,t[n])}return r}case 13:return this.serialize(e.of,t);case 15:return e.serialize?await e.serialize(t):JSON.stringify(t)}}static async deserialize(e,t){switch(e.tag){case 3:if(typeof t!=typeof e.value)throw new Error(`'${t}' is not equal to literal '${t}'`);return t;case 2:if("boolean"!=typeof t)throw new Error(`'${t}' is not a boolean`);return t;case 1:if("number"!=typeof t)throw new Error(`'${t}' is not a number`);return t;case 6:if("number"!=typeof t)throw new Error(`'${t}' is not a bigint`);return BigInt(t);case 0:if("string"!=typeof t)throw new Error(`'${t}' is not a string`);return t;case 5:if("string"!=typeof t)throw new Error(`'${t}' is not a symbol`);return Symbol.for(t);case 4:if(!(t instanceof Date))throw new Error(`'${t}' is not a date`);return t;case 7:if(!Array.isArray(t))throw new Error(`'${t}' is not an array`);return t;case 8:if(!Array.isArray(t))throw new Error(`'${t}' is not an array`);return new Set(t);case 10:return k.deserialize(e.of,t);case 12:return JSON.parse(t);case 9:{let r,n=!1;for(const s of e.options){try{r=k.deserialize(s,t),n=!0}catch{n=!1}if(n)break}if(!n)throw new Error("Value did not match the union");return r}case 11:{if(!t||"object"!=typeof t||!("data"in t)||!("name"in t)||"string"!=typeof t.data||"string"!=typeof t.name)throw new Error("Value is not a valid file schema");const e=await fetch(t.data);return new File([await e.blob()],t.name)}case 13:return this.deserialize(e.of,t);case 15:if(e.isType(t))return e.deserialize?await e.deserialize(t):JSON.parse(String(t));throw new Error("Value is not valid");case 14:{if(!t||"object"!=typeof t)throw new Error("Value is not an object");const r={};for(const n in e.props){const s=e.props[n];if(!(n in t)&&10!==s.tag)throw new Error(`Required property '${n}' not found`);r[n]=await this.deserialize(s,t[n])}return r}}}static is(e,t){switch(e.tag){case 3:return t===e.value;case 2:return"boolean"==typeof t;case 1:return"number"==typeof t;case 6:return"bigint"==typeof t;case 0:return"string"==typeof t;case 5:return"symbol"==typeof t;case 12:return!0;case 4:return t instanceof Date;case 7:return Array.isArray(t)&&t.every(t=>k.is(e.of,t));case 8:return t instanceof Set&&Array.from(t).every(t=>k.is(e.of,t));case 10:return void 0===t||this.is(e.of,t);case 9:return e.options.some(e=>k.is(e,t));case 11:return t instanceof File;case 14:return!(!t||"object"!=typeof t)&&Object.keys(e.props).every(r=>k.is(e.props[r],t[r]));case 13:return this.is(e.of,t);case 15:return e.isType(t)}}}function R(e){return t=>typeof t===e?{success:!0,data:t}:{success:!1,error:"Value is not a string"}}const v={[k.String.tag]:R("string"),[k.Number.tag]:R("number"),[k.BigInt.tag]:R("bigint"),[k.Boolean.tag]:R("boolean"),[k.Symbol.tag]:R("symbol"),[k.Unknown.tag]:e=>({success:!0,data:e}),[k.Date.tag]: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"}},K=Symbol.for("primaryKey");class N{symbol=K;genFn;autoGenerate;type;constructor(e,t){if(e){if(e>k.Date)throw new r("Invalid Primary Key Type");this.type=e,t?(this.autoGenerate=!0,this.genFn=t):this.autoGenerate=!1}else this.autoGenerate=!1,this.type=k.Number}getType(){return this.type}generator(e){return this.genFn=e,this.autoGenerate=!0,this}autoIncrement(){if(this.type===k.Number)return this.genFn=void 0,this.autoGenerate=!0,this;throw new r("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 N(k.String,b)}date(){return new N(k.Date,S)}genKey(){if(this.genFn)return this.genFn();throw new Error("Generator function not defined")}getSchema(){return v[this.type.tag]}isAutoIncremented(){return this.autoGenerate&&!this.genFn}static is(e){return e?.symbol===K}}class O{constructor(e,t="",r=!1,n=!1,s){this.to=e,this.name=t,this.isOptional=r,this.isArray=n,this.relatedKey="",this.actions={onDelete:s||"Restrict"}}static SYMBOL=Symbol.for("baseRelation");BASE_SYMBOL=O.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()===O.SYMBOL}}class M extends O{static R_SYMBOL=Symbol.for("relation");symbol=M.R_SYMBOL;constructor(e,t={}){super(e,t.name,!1,!1,t.onDelete)}array({onDelete:e}={}){return new D(this.to,this.name,e)}optional({onDelete:e}={}){return new I(this.to,this.name,e)}onDelete(e){return this.actions.onDelete=e,this}static is(e){return e?.symbol===this.R_SYMBOL}}class D extends O{static A_SYMBOL=Symbol.for("arrayRelation");symbol=D.A_SYMBOL;constructor(e,t,r="None"){super(e,t,!1,!0,r)}static is(e){return e?.symbol===this.A_SYMBOL}}class I extends O{static O_SYMBOL=Symbol.for("optionalRelation");symbol=I.O_SYMBOL;constructor(e,t,r="None"){super(e,t,!0,!1,r)}static is(e){return e?.symbol===this.O_SYMBOL}}var E=/* @__PURE__ */(e=>(e[e.Property=0]="Property",e[e.Relation=1]="Relation",e[e.PrimaryKey=2]="PrimaryKey",e[e.Invalid=3]="Invalid",e))(E||{});const j=Symbol.for("property");class x{constructor(e,t,r){this.parseFn=e,this.type=t,this.options={unique:r?.unique??!1}}symbol=j;hasDefault=!1;options;get parse(){return this.parseFn}getType(){return this.type}static array(...e){throw new Error("Method Not Implemented")}static boolean(...e){throw new Error("Method Not Implemented")}static custom(...e){throw new Error("Method Not Implemented")}static date(...e){throw new Error("Method Not Implemented")}static literal(e,...t){throw new Error("Method Not Implemented")}static number(...e){throw new Error("Method Not Implemented")}static union(...e){throw new Error("Method Not Implemented")}static set(...e){throw new Error("Method Not Implemented")}static string(...e){throw new Error("Method Not Implemented")}unique(){switch(this.type){case k.Boolean:case k.String:case k.Number:case k.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 M(e,t)}static primaryKey(e="number"){return new N(this.nameToType(e))}static nameToType(e){switch(e){case"boolean":return k.Boolean;case"bigint":return k.BigInt;case"number":case"string":return k.Number;case"symbol":return k.Symbol;default:return k.Unknown}}static is(e){return"object"==typeof e&&e?.symbol===j}}class F extends x{array(){return new F(F.generateArrayValidator(this.parseFn),k.Array(this.type),this.options)}default(e){return this.hasDefault=!0,new F(t=>null==t?{success:!0,data:"function"==typeof e?e():e}:this.parseFn(t),this.type,this.options)}optional(){return new F(e=>null==e?{success:!0,data:void 0}:this.parseFn(e),this.type,this.options)}static array(e,t){return new F(F.generateArrayValidator(e.parseFn),k.Array(e.type),t)}static boolean(e){return new F(e=>"boolean"==typeof e?{success:!0,data:e}:{success:!1,error:"Value is not a string"},k.Boolean,e)}static custom(e,t){return new F(e,k.Unknown,t)}static date(e){return new F(v[k.Date.tag],k.Date,e)}static literal(e,t){return new F(t=>t===e?{success:!0,data:e}:{success:!1,error:`${t} !== ${e}`},k.Literal(e),t)}static number(e){return new F(v[k.Number.tag],k.Number,e)}static string(e){return new F(v[k.String.tag],k.String,e)}static set(e,t){return new F(t=>{if(t instanceof Set){const r=/* @__PURE__ */new Set;for(const n of t){const t=e.parseFn(n);if(!t.success)return t;r.add(t.data)}return{success:!0,data:r}}return{success:!1,error:"Value is not an array"}},k.Set(e.type),t)}static union(e,t){const r=e.map(e=>e.parse);return new F(e=>{for(const t of r){const r=t(e);if(r.success)return r}return{success:!1,error:"Value did not match any of the items"}},k.Union(e.map(e=>e.getType())),t)}static generateArrayValidator(e){return t=>{if(Array.isArray(t)){const r=[];for(const n of t){const t=e(n);if(!t.success)return t;r.push(t.data)}return{success:!0,data:r}}return{success:!1,error:"Value is not an array"}}}}const T=Symbol.for("model");class L{constructor(t,r){this.name=t,this.fields=r,this.fieldKeys=m(r);for(const e of this.fieldKeys){const t=this.fields[e];O.is(t)&&t.to!==this.name&&this.relationLinks.add(t.to)}const n=this.fieldKeys.find(e=>N.is(this.fields[e]));if(!n)throw new e("INVALID_CONFIG",`Model ${this.name} has no primary key`);this.primaryKey=n}symbol=T;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&&O.is(t))return t}keyType(e){const t=this.fields[e];return t?x.is(t)?E.Property:O.is(t)?E.Relation:N.is(t)?E.PrimaryKey:E.Invalid:E.Invalid}links(){return this.relationLinks.keys()}*relations(){for(const e of this.fieldKeys)O.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 x.is(this.fields[e])?this.fields[e].parse(t):null}getDeletedStores(e){if(this.cache.delete)return this.cache.delete;const t=/* @__PURE__ */new Set,r=[this.name];let n;for(;r.length>0;){const s=r.shift();if(t.has(s))continue;n=e.getModel(s);const a=n.cache.delete;if(a)$(t,a);else{t.add(s);for(const e of n.links())t.has(e)||r.push(e)}}return this.cache.delete=t,t}static is(e){return e?.symbol===T}}class P{constructor(e,t){this.tx=e,this.store=t}add(e){return this.handleRequest(this.store.add(e),()=>new d)}get(e){return this.handleRequest(this.store.get(e),()=>new y)}async assertGet(e){const t=await this.handleRequest(this.store.get(e),()=>new y);if(!t)throw this.tx.abort(new l);return t}put(e){return this.handleRequest(this.store.put(e),()=>new u)}delete(e){return this.handleRequest(this.store.delete(e),()=>new i)}async openCursor(t,r={}){const n=r.onError||(()=>new h),s=this.store.openCursor(r.query,r.direction);await new Promise((r,a)=>{s.onsuccess=async s=>{try{s.target||a(this.tx.abort(n()));const e=s.target.result;e&&await t(e,this.tx)||r()}catch(i){a(this.tx.abort(i instanceof e?i:new o(String(i))))}},s.onerror=()=>{a(this.tx.abort(n()))}})}handleRequest(e,t){return new Promise(r=>{e.onsuccess=()=>{r(e.result)},e.onerror=()=>{throw this.tx.abort(t())}})}}class _{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,r,n={}){e instanceof _?(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,r),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,n.onAbort),this.internal.onerror=this.registerHandler(3,n.onError),this.internal.oncomplete=this.registerHandler(2,n.onComplete))}static create(e,t,r,n){return n||new _(e,t,r)}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 n(`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 P(this,this.internal.objectStore(e))}catch{throw this.abort(new c(`No ObjectStore with the name '${e}' found`))}}registerHandler(e,t=()=>{}){return r=>{this.status=e,t(this,r)}}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(r){throw this.inWrap=!1,r instanceof e?this.abort(r):this.abort(new o(JSON.stringify(r)))}}}function V(e){if(!e)return[];const t=[];for(const r in e)if(Object.hasOwn(e,r))switch(typeof e[r]){case"function":t.push([r,!0,e[r]]);break;case"object":if(e[r]instanceof Date){const n=e[r];t.push([r,!0,e=>e instanceof Date&&e.getTime()===n.getTime()])}break;default:t.push([r,!1,e[r]])}return t}function B(e,t){if(!t||"object"!=typeof t)return!1;for(const r of e)if(r[1]){if(!r[2](t[r[0]]))return!1}else if(r[2]!==t[r[0]])return!1;return!0}function C(e,t,r={},n){const a=t.getModel(e);if(r.include&&r.select)throw new s("include and select cannot both be defined");const o=V(r.where),i=r.select?"select":r.include?"include":"";if(i){const e=r[i],n=!!r.select,s=[];for(const r in e)if(Object.hasOwn(e,r)&&e[r])switch(a.keyType(r)){case E.Relation:{const n=a.getRelation(r),o="object"==typeof e[r]?C(n.to,t,e[r]):A,i=n.getRelatedKey();if(n.isArray){const e=async(e,t)=>{const r=[],s=t.getStore(n.to);for(const n of e){const e=await o(await s.assertGet(n),t);e&&(delete e[i],r.push(e))}return r};s.push({key:r,getValue:e})}else{const e=async(e,t)=>await o(await t.getStore(n.to).assertGet(e),t);s.push({key:r,getValue:e})}break}case E.Property:case E.PrimaryKey:n&&s.push({key:r})}return n?async(e,t)=>{if(!B(o,e))return;const r={};for(const{key:n,getValue:a}of s)r[n]=a?await a(e[n],t):e[n];return r}:async(e,t)=>{if(B(o,e)){for(const{key:r,getValue:n}of s)e[r]=await n(e[r],t);return e}}}return e=>B(o,e)?e:void 0}function z(e,t,r,n){const s=/* @__PURE__ */new Set([e]);if(r){const a=m(t),o=n.getModel(e);for(const e of a){const a=o.getRelation(e),i=g(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":$(s,o.getDeletedStores(n));break;case"$create":$(s,z(a.to,e[t],r,n));break;case"$createMany":e[t].forEach(e=>$(s,z(a.to,e,r,n)));break;case"$update":$(s,z(a.to,e[t].data,r,n));break;case"$updateMany":e[t].forEach(e=>$(s,z(a.to,e.data,r,n)))}}}else{const r=n.getModel(e);for(const e of m(t)){const a=r.getRelation(e);if(a)switch(typeof t[e]){case"object":$(s,z(a.to,U(t[e]),!1,n));break;case"boolean":s.add(a.to)}}}return s}function U(e){return e.select?e.select:e.include?e.include:{}}class q{constructor(e,t,r){this.client=e,this.name=t,this.accessedStores=Array.from(z(t,U(r),!1,this.client)),this.selectClause=C(t,this.client,r)}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 r=[],n=t.getStore(this.name);return await n.openCursor(async n=>{const s=await this.selectClause(n.value,t);return s&&r.push(s),(!e||!r.length)&&(n.continue(),!0)}),r})}}function G(e,t,n){return async s=>{if(!s)return!1;const a=s[e.primaryKey];for(const[o,c]of e.relations()){const{onDelete:l}=c.getActions(),u=s[o],d=t.getModel(c.to);switch(l){case"Cascade":if(c.isArray){n.assertIsArray(u);const e=new Set(u),r=G(d,t,n),s=n.getStore(c.to);await s.openCursor(async t=>(e.has(t.value[d.primaryKey])&&await r(t.value),t.continue(),!0)).catch(n.onRejection)}else u&&await Y(c.to,t,void 0,void 0,{tx:n,singleton:{id:u}});break;case"SetNull":{if(!u)break;const e=g(u),t=n.getStore(c.to),s=c.getRelatedKey(),o=d.getRelation(s);if(!o)throw new r(`Relation '${c.name}' has an invalid relation key '${c.getRelatedKey()}'`);if(!o.isNullable())throw new r(`Key '${s}' on model '${s}': Non-optional relation cannot have the 'SetNull' action`);for(const r of e){const e=await t.get(r);if(!e)continue;const i=e[s];if(o.isArray){n.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(u)&&u.length>0||u)throw new i(`Key '${o}' on model '${e.name}' deletion is restricted while there is an active relation`)}}return!0}}async function Y(e,t,r,n=!1,s={}){const{singleton:a,finalStep:o=!0}=s,i=t.getModel(e),c=s.tx?s.tx.storeNames:Array.from(i.getDeletedStores(t)),l=_.create(t.getDb(),c,"readwrite",s.tx);return await l.wrap(async s=>{const c=s.getStore(e);let l=0;const u=G(i,t,s);if(a)await u(await c.assertGet(a.id))&&(await c.delete(a.id),l++);else{const e=V(r);let t;await c.openCursor(async r=>{const a=r.value;return B(e,a)&&await u(a)&&(t=p(r.delete()).catch(s.onRejection)),!(n&&l>0)&&(r.continue(),!0)}),t&&o&&await t}return l})}class J{constructor(e,t,r){this.name=e,this.content=t,this.extension=r}download(e=`${this.name}_dump.${this.extension}`,t){const r=URL.createObjectURL(this.toFile(e,t)),n=document.createElement("a");n.href=r,n.download=e,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(r)}}class W extends J{constructor(e,t){super(e,t,"json")}getValue(){return this.content}toFile(e=`${this.name}_dump.json`,t={}){return new File([JSON.stringify(this.content,void 0,4)],e,t)}}class H extends J{constructor(e,t){super(e,t,"csv")}getValue(){return this.content}toFile(e=`${this.name}_dump.csv`,t){return new File([this.content],e,t)}}function X(e){return"string"!=typeof e?`${e}`:e.replaceAll(/~/g,"~0").replaceAll(/\//g,"~1")}async function Q(e,t,r,n){n=_.create(e.getDb(),[t],"readonly",n);const s=V(r),o=e.getModel(t);return new W(t,await n.wrap(async e=>{const r={};return await e.getStore(t).openCursor(async e=>{if(B(s,e.value)){for(const[t,r]of o.entries())if(O.is(r))if(r.isArray){if(!Array.isArray(e.value[t]))throw new a("Expected array type");const n=[];for(const s of e.value[t])n.push(`/${r.to}/${X(s)}`);e.value[t]=n}else(r.isOptional&&e.value[t]||!r.isNullable())&&(e.value[t]=`/${r.to}/${X(e.value[t])}`);else{if(!F.is(r)&&!N.is(r))throw new w(`Unrecognized model field on key '${t}'`);e.value[t]=await k.serialize(r.getType(),e.value[t])}if(r[e.value[o.primaryKey]])throw new w("Duplicate primary key detected "+JSON.stringify(r));r[e.value[o.primaryKey]]=e.value}return e.continue(),!0}),r}))}class Z{constructor(e,t){this.db=e,this.models=t,this.name=this.db.name,this.version=this.db.version,this.stores={};for(const r of this.models.keys())this.stores[r]=this.createInterface(r)}name;version;stores;getDb(){return this.db}getStore(e){return this.stores[e]}getStoreNames(){return this.models.keys()}createTransaction(e,t,r){return new _(this.db,t,e,r)}async deleteDb(){await p(window.indexedDB.deleteDatabase(this.name))}async dump(e,t){return"json"===e?await async function(e,t){const r={};t=t||e.getStoreNames();const n=e.createTransaction("readonly",t);for(const s of t)r[s]=(await Q(e,s,void 0,n)).getValue();return new W(e.name,r)}(this,t):new H("d","")}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,r,n){return n?n.storeNames:Array.from(z(e,t,r,this))}createInterface(e){return{add:async(t,r)=>await this.add(e,t,{tx:r}),addMany:async(t,r)=>{if(!r){const n=/* @__PURE__ */new Set;for(const r of t)$(n,z(e,r,!0,this));r=this.createTransaction("readwrite",Array.from(n))}const n=[];for(const s of t)n.push(await this.add(e,s,{tx:r}));return n},findFirst:async(t,r)=>(await this.find(e,t,!0,{tx:r}))[0],find:async(t,r)=>await this.find(e,t,!1,{tx:r}),get:async t=>{const r=this.createTransaction("readonly",e);return await r.getStore(e).get(t)},update:async(t,r)=>(await this.update(e,{data:r},!0,{singleton:{id:t}}))[0],updateFirst:async(t,r)=>(await this.update(e,t,!0,{tx:r}))[0],updateMany:async(t,r)=>await this.update(e,t,!1,{tx:r}),compileQuery:t=>new q(this,e,t),delete:async t=>await Y(e,this,void 0,void 0,{singleton:{id:t}})>0,deleteFirst:async t=>await Y(e,this,t,!0)>0,deleteMany:async t=>await Y(e,this,t,!1),dump:async(t,r)=>"json"===t?await Q(this,e,r):new H("","")}}async add(e,t,r={}){let{tx:n}=r;const{relation:a}=r,i=this.getAccessedStores(e,t,!0,n);return n=_.create(this.db,i,"readwrite",n),await n.wrap(async r=>{const n=r.getStore(e),i=this.getModel(e),c=i.getPrimaryKey(),l=a?{[a.key]:i.getRelation(a.key)?.isArray?[a.id]:a.id}:{},u=c.isAutoIncremented()?{...l}:{...l,[i.primaryKey]:t[i.primaryKey]??c.genKey()},d=await n.add(u),h={},y=/* @__PURE__ */new Set;for(const a of m(t)){y.add(a);const n=t[a];switch(i.keyType(a)){case E.Invalid:throw new s(`Key '${a}' does ont exist on model '${e}'`);case E.Property:{const e=i.parseField(a,n);if(!e)throw new o;if(!e.success)throw new s(`Key '${a}' has the following validation error: ${e.error}`);h[a]=e.data;break}case E.Relation:{if(!n)continue;const e=g(n),t=i.getRelation(a);if(t.isArray&&(h[a]=[],"$createMany"in n||"$connectMany"in n)){const t=[];for(const e of n.$createMany??[])t.push({$create:e});for(const e of n.$connectMany??[])t.push({$connect:e});e.push(...t)}const o=this.getModel(t.to).getRelation(t.getRelatedKey()),c=/* @__PURE__ */new Set;for(const n of e){const e=m(n)[0];if(!e)throw new s(`Key '${a}' cannot be an empty connection object`);switch(e){case"$connect":{const i=n[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,d,i,r),t.isArray?h[a].push(i):h[a]=i;break}case"$create":{const s=await this.add(t.to,n[e],{tx:r,relation:{id:d,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 E.PrimaryKey:}}const f=Array.from(new Set(i.keys()).difference(y));for(const e of f)switch(i.keyType(e)){case E.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`);h[e]=t.data;break}case E.Relation:{const t=i.getRelation(e),r=l[e];if(t.isArray)h[e]=r??[];else if(t.isOptional)h[e]=r??null;else{if(!r)throw new s(`Required relation '${e}' is not defined`);h[e]=r}break}case E.Invalid:case E.PrimaryKey:}return await n.put({[i.primaryKey]:d,...h})})}async clear(e,t){await Y(e,this,void 0,!1,t)}async find(e,t,r,n={}){let{tx:s}=n;const a=this.getAccessedStores(e,U(t),!1,s);s=_.create(this.db,a,"readonly",s);const o=[];return await s.wrap(async n=>{const s=n.getStore(e),a=C(e,this,t);return await s.openCursor(async e=>{const t=await a(e.value,n);return t&&o.push(t),(!r||!o.length)&&(e.continue(),!0)}),o})}async update(e,t,r,n={}){const{singleton:a}=n,i=n.singleton?t:t.data,c=this.getAccessedStores(e,i,!0,n.tx),d=_.create(this.db,c,"readwrite",n.tx);return await d.wrap(async n=>{const c=n.getStore(e),d=this.getModel(e),h=[];for(const e of m(i))switch(d.keyType(e)){case E.Property:h.push({key:e,isRelation:!1,updateFn:"function"==typeof i[e]?i[e]:()=>i[e]});break;case E.Relation:{const t=g(i[e]);if(!t)continue;const r=[];for(const e of t)for(const t in e){switch(t){case"$createMany":case"$connectMany":case"$updateMany":case"$deleteMany":case"$disconnectMany":{const n=t.substring(0,t.length-4);for(const s of e[t])r.push([n,s]);break}default:r.push([t,e[t]])}break}h.push({actions:r,key:e,isRelation:!0,relation:d.getRelation(e)});break}case E.PrimaryKey:throw new u("Primary key field cannot be updated");case E.Invalid:default:throw new o(`Unknown key '${e}'`)}const y=[],f=async e=>{const t=e[d.primaryKey];for(const{key:r,...a}of h){const o=a.relation;if(a.isRelation)for(const[i,c]of a.actions)switch(i){case"$connect":e[r]&&!o.isArray&&await this.disconnectDocument(o,t,e[r],n).catch(n.onRejection),await this.connectDocument(o,t,c,n).catch(n.onRejection),o.isArray?e[r].push(c):e[r]=c;break;case"$create":{const s=await this.add(o.to,c,{tx:n,relation:{id:t,key:o.getRelatedKey()}});o.isArray?e[r].push(s):e[r]=s;break}case"$delete":if(!o.isNullable())throw new s("Item cannot be deleted, relation is required");e[r]=o.isArray&&Array.isArray(e[r])?e[r].filter(e=>e!==c):null,await Y(o.to,this,{},!0,{tx:n,singleton:{id:c}});break;case"$disconnect":{if(!o.isNullable())throw new s("Item cannot be disconnected, relation is required");if(!e[r]||0===e[r]?.lenth)break;const a=this.getModel(o.to).getRelation(o.getRelatedKey());await this.disconnectDocument(o,t,a.isArray?c:e[r],n).catch(n.onRejection),e[r]=o.isArray&&Array.isArray(e[r])?e[r].filter(e=>e!==c):null;break}case"$update":o.isArray?await this.update(o.to,c,!1,{tx:n}):null!=e[r]&&await this.update(o.to,c,!1,{tx:n,singleton:{id:t}});break;case"$deleteAll":if(c&&o.isArray&&Array.isArray(e[r])){const t=this.getModel(o.to),s=new Set(e[r]);await Y(o.to,this,{[t.primaryKey]:e=>s.has(e)},!1,{tx:n}),e[r]=[]}break;case"$disconnectAll":if(c&&o.isArray&&Array.isArray(e[r])){for(const s of e[r])await this.disconnectDocument(o,t,s,n);e[r]=[]}}else e[r]=a.updateFn(e[r])}return e};if(a){const e=await c.get(a.id);if(!e)throw new l(`${d.name} with priamry key '${a.id}' not found`);const t=await f(e).catch(n.onRejection);return await c.put(t),[t]}{const e=V(t.where);return await c.openCursor(async t=>{const s=t.value;if(B(e,s)){const e=await f(s).catch(n.onRejection);if(await p(t.update(e)).then(()=>y.push(e)).catch(n.onRejection),r)return!1}return t.continue(),!0}),y}})}async connectDocument(e,t,r,n){const s=n.getStore(e.to),a=await s.get(r);if(!a)throw new l(`Document with Primary Key '${r}' 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 f;a[o]=t}return await s.put(a).catch(n.onRejection),r}async disconnectDocument(e,t,r,n){const s=n.getStore(e.to),a=await s.get(r);if(!a)throw new l(`Document with Primary Key '${r}' 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 f;a[e.getRelatedKey()]=null}return await s.put(a).catch(n.onRejection),r}}class ee{constructor(e,t){this.name=e,this.names=t,this.models={}}models;defineModel(e,t){if("object"==typeof e&&L.is(e))return this.models[e.name]=e,e;{if(!t)throw new Error("Model Fields must be defined");const r=new L(e,t);return this.models[e]=r,r}}compile(e){return new te(this.name,e)}}class te{constructor(e,t){this.name=e,this.models=t,this.modelKeys=m(this.models),this.schemas={};for(const n of this.modelKeys){const e=this.models[n],t={};for(const s of e.keys()){const a=e.get(s);if(x.is(a))t[s]=a.parse;else if(O.is(a)){const{onDelete:o}=a.getActions(),i=this.models[a.to],c=i.getPrimaryKey();t[s]=v[c.type.tag],a.isOptional?t[s]=new F(t[s],c.type).optional().parse:a.isArray&&(t[s]=t[s]=new F(t[s],c.type).array().parse);let l=!!a.getRelatedKey();if(!l)for(const[t,n]of i.relations())if(s!==t&&n.to===e.name&&n.name===a.name){if(l=!0,a.setRelatedKey(t),n.setRelatedKey(s),"SetNull"===o&&!n.isNullable())throw new r(`Key '${t}' on model '${i.name}': Non-optional relation cannot have the 'SetNull' action`);break}if(!l)throw new r(`Relation '${a.name}' of model ${n} does not have an equivalent relation on model '${a.to}'`)}else{if(!N.is(a))throw new r(`Unknown field value detected: ${JSON.stringify(a)}`);t[s]=v[a.type.tag]}}this.schemas[n]=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 r of this.modelKeys){const e=this.models[r];t.objectStoreNames.contains(e.name)||t.createObjectStore(e.name,{autoIncrement:e.getPrimaryKey().isAutoIncremented(),keyPath:e.primaryKey})}};const r=await p(t);return new Z(r,this)}keys(){return[...this.modelKeys]}}const re=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,AbstractProperty:x,ArrayRelation:D,BaseRelation:O,DbClient:Z,FieldTypes:E,Model:L,OptionalRelation:I,PrimaryKey:N,Property:F,Relation:M,Type:k,VALIDATORS:v},Symbol.toStringTag,{value:"Module"}));export{ee as Builder,q as CompiledQuery,L as Model,F as Property,e as StoreError,re as core};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CompiledDb } from '../builder.js';
|
|
2
|
+
import { ValidValue, BaseRelation, OptionalRelation, ArrayRelation, RelationOutput, Relation, AbstractProperty, PrimaryKey, ParseFnWrap } from '../field';
|
|
3
|
+
import { Dict, Keyof } from '../util-types.js';
|
|
4
|
+
import { default as Model } from './model.js';
|
|
5
|
+
export type FindPrimaryKey<F extends Record<string, ValidValue>> = Extract<{
|
|
6
|
+
[K in keyof F]: F[K] extends PrimaryKey<any, any> ? K : never;
|
|
7
|
+
}[keyof F], string>;
|
|
8
|
+
export type PrimaryKeyType<M extends Model<any, any, any>> = M extends Model<any, infer F, any> ? {
|
|
9
|
+
[K in keyof F]: F[K] extends PrimaryKey<any, infer Type> ? Type : never;
|
|
10
|
+
}[keyof F] : never;
|
|
11
|
+
export interface ModelCache {
|
|
12
|
+
delete?: Set<string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Gets the type of a relation given its model's name
|
|
16
|
+
*/
|
|
17
|
+
export type RelationValue<Name extends string, C> = Name extends keyof C ? C[Name] extends Model<any, infer Fields, infer PrimaryKey> ? RelationOutput<Fields[PrimaryKey]> : never : never;
|
|
18
|
+
/**
|
|
19
|
+
* Gets the primitive type of the relation field
|
|
20
|
+
*/
|
|
21
|
+
export type GetRelationField<F, C> = F extends Relation<infer To, any> ? RelationValue<To, C> : F extends OptionalRelation<infer To, any> ? RelationValue<To, C> | null : F extends ArrayRelation<infer To, any> ? RelationValue<To, C>[] : never;
|
|
22
|
+
export type ModelStructure<F extends Dict<ValidValue>, C> = {
|
|
23
|
+
[K in keyof F]: F[K] extends AbstractProperty<infer Output, any> ? Output : F[K] extends PrimaryKey<any, infer Type> ? Type : GetRelationField<F[K], C>;
|
|
24
|
+
};
|
|
25
|
+
export type ModelType<M extends Model<any, any, any>, C extends CompiledDb<any, any, any>> = M extends Model<any, infer Fields, any> ? C extends CompiledDb<any, any, infer Collection> ? ModelStructure<Fields, Collection> : never : never;
|
|
26
|
+
export type ExtractFields<M extends Model<any, any, any>> = M extends Model<any, infer Fields, any> ? Fields : never;
|
|
27
|
+
export type AllRelationKeys<M extends Model<any, any, any>> = M extends Model<any, infer Fields, any> ? {
|
|
28
|
+
[K in Keyof<Fields>]: Fields[K] extends BaseRelation<any, any> ? K : never;
|
|
29
|
+
}[Keyof<Fields>] : never;
|
|
30
|
+
export type RelationlessModelStructure<M extends Model<any, any, any>> = M extends Model<any, infer Fields, any> ? Omit<{
|
|
31
|
+
[K in Keyof<Fields>]: Fields[K] extends BaseRelation<any, any> ? unknown : Fields[K] extends AbstractProperty<infer Type, any> ? Type : Fields[K] extends PrimaryKey<any, infer Type> ? Type : never;
|
|
32
|
+
}, AllRelationKeys<M>> : never;
|
|
33
|
+
export type CollectionSchema<C> = C extends Record<infer Keys, Model<any, any, any>> ? {
|
|
34
|
+
[K in Keys]: C[K] extends Model<any, infer Fields, any> ? ParseFnWrap<ModelStructure<Fields, C>> : never;
|
|
35
|
+
} : never;
|
|
36
|
+
export type FindRelationKey<From extends string, RelationName extends string, M extends Model<any, any, any>> = M extends Model<any, infer Fields, any> ? {
|
|
37
|
+
[K in Keyof<Fields>]: Fields[K] extends BaseRelation<From, infer CurName> ? CurName extends RelationName ? K : never : never;
|
|
38
|
+
}[Keyof<Fields>] : never;
|
|
39
|
+
export type CollectionObject<Names extends string> = {
|
|
40
|
+
[K in Names]: Model<K, any>;
|
|
41
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
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';
|
|
5
|
+
export default class Model<Name extends string, F extends Record<string, ValidValue>, Primary extends FindPrimaryKey<F> = FindPrimaryKey<F>> {
|
|
6
|
+
readonly name: Name;
|
|
7
|
+
private readonly fields;
|
|
8
|
+
readonly symbol: symbol;
|
|
9
|
+
/**
|
|
10
|
+
* Array of all the model's fields
|
|
11
|
+
*/
|
|
12
|
+
private readonly fieldKeys;
|
|
13
|
+
/**
|
|
14
|
+
* Set of other models this model links to
|
|
15
|
+
*/
|
|
16
|
+
private readonly relationLinks;
|
|
17
|
+
private cache;
|
|
18
|
+
readonly primaryKey: Primary;
|
|
19
|
+
constructor(name: Name, fields: F);
|
|
20
|
+
get<K extends Keyof<F>>(key: K): F[K];
|
|
21
|
+
getPrimaryKey(): PrimaryKey<boolean, ValidKey>;
|
|
22
|
+
getRelation<Models extends string>(key: string): BaseRelation<Models, string> | undefined;
|
|
23
|
+
keyType(key: Keyof<F>): FieldTypes;
|
|
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]>;
|
|
36
|
+
keys(): Keyof<F>[];
|
|
37
|
+
parseField<K extends Keyof<F>>(field: K, value: unknown): ParseResult<any>;
|
|
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>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
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> {
|
|
6
|
+
private readonly tx;
|
|
7
|
+
readonly store: IDBObjectStore;
|
|
8
|
+
constructor(tx: Transaction<IDBTransactionMode, string>, store: IDBObjectStore);
|
|
9
|
+
add(item: T): Promise<ValidKey>;
|
|
10
|
+
/**
|
|
11
|
+
* Attempts to retrieve the value from the object store.
|
|
12
|
+
*
|
|
13
|
+
* Returns `undefined` if no value was found
|
|
14
|
+
*/
|
|
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>;
|
|
21
|
+
delete(key: ValidKey): Promise<undefined>;
|
|
22
|
+
openCursor(callback: (cursor: IDBCursorWithValue, tx: Transaction<IDBTransactionMode, string>) => Promisable<boolean>, options?: {
|
|
23
|
+
query?: IDBValidKey | IDBKeyRange;
|
|
24
|
+
direction?: IDBCursorDirection;
|
|
25
|
+
onError?: () => StoreError;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
private handleRequest;
|
|
28
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
}
|
|
10
|
+
export type TransactionEventHandler = (tx: Transaction<IDBTransactionMode>, ev: Event) => void;
|
|
11
|
+
export interface TransactionOptions extends Partial<{
|
|
12
|
+
onAbort: TransactionEventHandler;
|
|
13
|
+
onError: TransactionEventHandler;
|
|
14
|
+
onComplete: TransactionEventHandler;
|
|
15
|
+
}> {
|
|
16
|
+
}
|
|
17
|
+
export declare class Transaction<Mode extends IDBTransactionMode, Stores extends string = string> {
|
|
18
|
+
private internal;
|
|
19
|
+
status: TransactionStatus;
|
|
20
|
+
error: StoreError | null;
|
|
21
|
+
readonly storeNames: Stores[];
|
|
22
|
+
private inWrap;
|
|
23
|
+
readonly onRejection: (error: any) => never;
|
|
24
|
+
/**
|
|
25
|
+
* A record of store names to `IDBObjectStore` objects
|
|
26
|
+
*/
|
|
27
|
+
private readonly objectStores;
|
|
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>;
|
|
38
|
+
abort(error: StoreError): StoreError;
|
|
39
|
+
commit(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Gets the internal `IDBTransaction` object
|
|
42
|
+
*
|
|
43
|
+
* It's recommended you don't use this function and use the built-in functions of the wrapper
|
|
44
|
+
* @returns Internal transaction object
|
|
45
|
+
*/
|
|
46
|
+
getInternal(): IDBTransaction;
|
|
47
|
+
getStore(store: Stores): ObjectStore;
|
|
48
|
+
getAllStores(): Map<Stores, ObjectStore<import('./util-types.js').Dict>>;
|
|
49
|
+
get mode(): Mode;
|
|
50
|
+
is(status: TransactionStatus): boolean;
|
|
51
|
+
contains(stores: Arrayable<string>): boolean;
|
|
52
|
+
assertIsArray(value: any, message?: string): asserts value is any[];
|
|
53
|
+
private getObjectstore;
|
|
54
|
+
private registerHandler;
|
|
55
|
+
wrap<Output>(fn: (tx: this) => Promisable<Output>): Promise<Output>;
|
|
56
|
+
}
|