@idb-orm/core 1.0.11 → 1.0.13

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/README.md CHANGED
@@ -1,39 +1,198 @@
1
- # IDB-ORM
1
+ # IDB-ORM Core
2
2
 
3
- > THIS PROJECT IS STILL A (ROUGH) WORK IN PROGRESS. I HOPE TO HAVE A GOOD WORKING VERSION SOON.
4
- >
5
- > PLEASE CHECK BACK IN A FEW WEEKS/MONTHS
3
+ > # IMPORTANT: THIS PROJECT IS STILL IN THE VERY EARLY STAGES. USE AT YOUR OWN RISK
6
4
 
7
- ## Roadmap
5
+ A simple object relational mapper for the [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API). IndexedDB (IDB) is a NoSQL database built into modern web browsers. This package wraps around that API and turns it into a pseudo-relational database. This allows features like:
6
+
7
+ - Defining relations between documents
8
+ - Querying on these relations (and the relations of the related document)
9
+ - Performing actions when the corresponding item of the relation changes
10
+ - Updating items based on nested relation querying
11
+
12
+ ## Installation
13
+
14
+ The minimum you need to get started is the `core` package. Although there are other supplemental packages that add extra features.
15
+
16
+ ```
17
+ npm install @idb-orm/core
18
+ ```
19
+
20
+ ## Getting Started
21
+
22
+ First thing you'll need to do is create a `builder` object. This will create the IDB object stores. The constructor takes in the name of the database and a list of object store names.
23
+
24
+ ```ts
25
+ import { Builder, Property as P } from "@idb-orm/core";
26
+
27
+ const builder = new Builder("test_db", ["users", "posts", "comments"]);
28
+ ```
29
+
30
+ ## Understanding the Different Components
31
+
32
+ Before you can define a model, you need to understand the different components of one. A model definition is made up of three different components.
33
+
34
+ - One primary key definition
35
+ - Zero or more Property definitions
36
+ - Zero or more Relation definitions
37
+
38
+ Each component is slightly different in how it is instantiated and used when defining a model.
39
+
40
+ ### Primary Key Definition
41
+
42
+ A primary key is a **unique** identifier used to store your document in the database. A primary key can be a `string`, `number`, or `Date` type (I may include support for more types down the line):
43
+
44
+ ```ts
45
+ // A number primary key (default)
46
+ P.primaryKey();
47
+
48
+ // A string primary key
49
+ P.primaryKey("string");
50
+
51
+ // A date primary key
52
+ P.primaryKey("date");
53
+ ```
54
+
55
+ In their base states, when creating a document the primary key must be supplied. However you can attach generators which will automatically generate the primary key when a document is created.
56
+
57
+ ```ts
58
+ // Creates a auto-incrementing number primary key
59
+ P.primaryKey().autoIncrement();
60
+
61
+ // Creates a string primary key that is a UUIDv4
62
+ P.primaryKey().uuid();
63
+
64
+ // Or, define your own generator
65
+ P.primaryKey("string").generator(
66
+ () => `${new Date()}-${Math.round(Math.random() * 10000)}`
67
+ );
68
+ ```
69
+
70
+ > **Note:** If the given primary key of a document is not unique, the creation of that document will fail. It's recommended to use either the `.autoIncrement()` utility for number primary keys or `.uuid()` for string primary keys.
71
+
72
+ ### Property Definition
73
+
74
+ This is the basic building block for a model. It lets you define static fields of the document. They are used for validating model input and providing the proper typescript interface for later queries/mutations.
8
75
 
9
- - [x] "Include" query field
10
- - [x] Enforce that either "include" xor "select" is in the query object
11
- - [x] modify the query object so that on relations it is recursive
12
- - [x] Make sure non-optional and non-array relations do not have the `SetNull` onDelete action on model compilation
13
- - [x] Complete update action
14
- - [x] Redo Mutation type. It should provide structurally no change:
15
- - [x] Split `add` and `update` mutation until completely separate interfaces?
16
- - [x] -Many or -All are only present on `ArrayRelation`'s,
17
- - [x] Cannot use `delete` or `disconnect` on non-nullable (1-1) relations
18
- - [x] Add additional functions to the storeInterface
19
- - [x] get([primaryKey], [include/select])
20
- - [x] update([primaryKey], [updateMutation without where])
21
- - [x] Error Handling: Instead of needing to type `tx.abort(...)` just use the `throw new ...` syntax and catch the error and automatically abort the transaction. This will require actions to be wrapped in some kind of try-catch block.
22
- - [ ] Dump database to different formats:
76
+ - `P.string()`: Defines a string field
77
+ - `P.number()`: Defines a number field
78
+ - `P.boolean()`: Defines a boolean field
79
+ - `P.date()`: Defines a date field
80
+ - `P.literal([value])`: Defines a literal type. Meaning that the field will always consist of `[value]`
81
+ - `P.array([Property])`: Defines an array field where the array's elements are defined by `[Property]`
82
+ - `P.set([Property])`: Defines a set field where the set's elements are defined by `[Property]`
83
+ - `P.union([Property1, Property2, ...])`: Defines a union type where any value that matches the given `[PropertyX]` will satisfy the validation.
84
+ - `P.custom<T>((test: unknown) => boolean)`: Defines a field for a custom type that is validated by a function passed in as the first argument.
85
+
86
+ For this type of field, if you plan on dumping your database to other formats, it's also recommended you populate the second `options` argument with these functions:
87
+
88
+ - `serialize: (value: T) -> unknown`: Serializes the type to JSON.
89
+ - `deserialize: (value: unknown) -> T`: De-serializes the type to JSON.
90
+
91
+ If these functions are omitted it will use `JSON.stringify()` and `JSON.parse()` respectfully.
92
+
93
+ Additionally, there are methods of the `Property` class that allows you to attach identifiers to these properties:
94
+
95
+ - `.array()`: Makes the field an array of the preceeding property.
96
+ - `.optional()`: Makes a field optional. It can now be omitted when a document is being created. The value in the resulting document will be undefined. This is functionally equivalent to doing `P.union([..., P.literal(undefined)])`, but with less overhead.
97
+ - `.default([value])`: Same behavior as optional, but instead of being undefined the value will be filled in with the given default value.
98
+
99
+ ### Relation Definition
100
+
101
+ Relation definitions are how you define relations between models/stores. Relations can be between different stores or the same store. There are three types of relation definitions:
102
+
103
+ - `P.relation([modelName], options?)`: The default, describing a relation from the current model to a `[modelName]` document.
104
+ - `P.relation([modelName], options?).optional()`: Describes a relation from the current model to a `[modelName]` document, where it's possible that the value on this not defined (null).
105
+ - `P.relation([modelName], options?).array()`: Describes a relation from the current model to several different documents in model `[modelName]`.
106
+
107
+ ```ts
108
+ interface RelationOptions {
109
+ name?: string;
110
+ onDelete?: "SetNull" | "None" | "Restrict" | "Cascade";
111
+ }
112
+ ```
113
+
114
+ All relations must be bidirectional, so for every relation on some model X to model Y, there must be a corresponding relation object on model Y that points to model X. If you omit it, the builder will throw an error. You can pass in additional options to the relation, such as a name. Giving a relation a name is highly recommended to ensure the builder correctly relates model fields. Under the hood, this relation field is storing the primary keys of the documents you are relating to.
115
+
116
+ Additionally, you can attach actions to be performed when a document is deleted:
117
+
118
+ - `SetNull`: Only usable when the relation this one is pointing to is optional or an array. In which case it sets the corresponding field to null or removes the element respectively.
119
+ - `None`: Performs no action when a delete occurs.
120
+ - `Restrict`: This item essentially cannot be deleted. Attempted to delete it will throw an error.
121
+ - `Cascade`: Deleting this document will try to delete the pointed to document(s).
122
+
123
+ ## Putting it all together
124
+
125
+ ```ts
126
+ import { Builder, Property as P } from "@idb-orm/core";
127
+
128
+ const builder = new Builder("test_db", ["users", "posts", "comments"]);
129
+
130
+ const userStore = builder.defineModel("users", {
131
+ id: P.primaryKey().uuid(),
132
+ name: P.string(),
133
+ email: P.string(),
134
+ password: P.string(),
135
+ accountCreated: P.date().default(() => new Date()),
136
+ posts: P.relation("posts", { name: "postsToUsers" }).array({
137
+ // If this user account gets deleted, delete all their posts
138
+ onDelete: "Cascade",
139
+ }),
140
+ comments: P.relation("comments", { name: "commentsToUsers" }).array(),
141
+ });
142
+
143
+ const postStore = builder.defineModel("posts", {
144
+ id: P.primaryKey().autoIncrement(),
145
+ created: P.date().default(() => new Date()),
146
+ title: P.string(),
147
+ body: P.string().array(),
148
+ likes: P.number().default(0),
149
+ dislikes: P.number().default(0),
150
+ author: P.relation("users", { name: "postsToUsers" }),
151
+ comments: P.relation("comments", { name: "postToComments" }).array({
152
+ onDelete: "Cascade",
153
+ }),
154
+ });
155
+
156
+ const commentStore = builder.defineModel("comments", {
157
+ id: P.primaryKey().autoIncrement(),
158
+ created: P.date().default(() => new Date()),
159
+ modified: P.date().default(() => new Date()),
160
+ content: P.string(),
161
+ likes: P.number().default(0),
162
+ dislikes: P.number().default(0),
163
+ author: P.relation("users", { name: "commentsToUsers" }),
164
+ post: P.relation("posts", { name: "postToComments" }),
165
+ });
166
+ ```
167
+
168
+ Then once you have all of your model definitions, call the `compile` function. This steps performs sanity checks on your model definitions and will throw errors if anything goes wrong. Once the model is compiled, you can create the client.
169
+
170
+ ```ts
171
+ const compiledDb = builder.compile({
172
+ users: userStore,
173
+ posts: postStore,
174
+ comments: commentStore,
175
+ });
176
+
177
+ const client = await compiledDb.createClient();
178
+ ```
179
+
180
+ _To be continued..._
181
+
182
+ ## Roadmap
183
+ - [ ] Restore database to different formats
23
184
  - [ ] JSON
24
185
  - [ ] CSV
25
- - [ ] Make package to wrap Tanstack query for react application
26
186
  - [ ] Add extra object syntax to "where" clause (i.e. `in`/`ne`/`gt`/...)
27
187
  - [ ] Allow object types in where clauses
28
- - [x] Convert internal string unions to enums
29
188
  - [ ] Make subpackages for adapters for different validation languages
30
189
  - [x] Zod
31
190
  - [ ] Yup
32
191
  - [ ] Joi
33
192
  - [ ] schema.js
34
- - [ ] Migrate to vite instead of rollup
35
193
 
36
194
  ### Roadmap - Maybe
37
195
 
38
196
  - [ ] Optimize batch `add` editing with cursor functionality
39
197
  - [ ] Discriminated union models: Be able to differentiate subtypes of a model by a discriminator key
198
+
@@ -1,7 +1,7 @@
1
1
  import { CollectionObject } from '../model';
2
2
  import { DbClient } from './index.ts';
3
- import { FindInput, FindOutput } from './types/find.ts';
4
- export declare class CompiledQuery<Stores extends string, Models extends CollectionObject<string>, Db extends DbClient<string, Stores, Models>, Input extends FindInput<Stores, Models[Stores], Models> = FindInput<Stores, Models[Stores], Models>, Output = FindOutput<Stores, Models[Stores], Models, Input>> {
3
+ import { FindInput, FindOutput } from './types/find';
4
+ export declare class CompiledQuery<Stores extends string, Models extends CollectionObject<string>, Db extends DbClient<string, Stores, Models>, Input extends FindInput<Stores, Stores, Models> = FindInput<Stores, Stores, Models>, Output = FindOutput<Stores, Stores, Models, Input>> {
5
5
  private readonly client;
6
6
  private readonly name;
7
7
  private readonly accessedStores;
@@ -0,0 +1,27 @@
1
+ import { Dict } from '../util-types';
2
+ import { ExportFormat } from './types';
3
+ import { DbClient } from '.';
4
+ import { WhereObject } from './types/find.js';
5
+ import { ValidValue } from '../field';
6
+ import { CollectionObject, Model } from '../model';
7
+ import { Transaction } from '../transaction.js';
8
+ /**
9
+ * Removes reserved characters from a JSON pointer string
10
+ */
11
+ export declare function clean(text: unknown): string;
12
+ export declare function getStoreData<Current extends Names, Names extends string, Models extends CollectionObject<Names>>(db: DbClient<string, Names, CollectionObject<Names>>, store: Current, where?: WhereObject<Models[Current] extends Dict<ValidValue> ? Models[Current] : never>, tx?: Transaction<"readonly", Names>): Promise<Dict>;
13
+ export declare function getDatabaseData<Names extends string>(db: DbClient<string, Names, any>, stores?: Names[]): Promise<Dict<Dict>>;
14
+ export interface DumpOptions {
15
+ pretty?: boolean;
16
+ }
17
+ export declare class Dump<F extends ExportFormat> {
18
+ protected readonly name: string;
19
+ protected readonly content: string;
20
+ protected readonly extension: F;
21
+ constructor(name: string, content: string, extension: F);
22
+ toFile(filename?: string, options?: FilePropertyBag): File;
23
+ download(filename?: string, options?: FilePropertyBag): void;
24
+ static toJson(name: string, content: Dict, options?: DumpOptions): Dump<"json">;
25
+ static toCsvStore(model: Model<string, any, string>, content: Dict): Dump<"csv">;
26
+ static toCsvDb(db: DbClient<string, string, CollectionObject<string>>, stores: string[], content: Dict<Dict>): Dump<"csv">;
27
+ }
@@ -1,6 +1,6 @@
1
1
  import { Dict, Promisable } from '../util-types.js';
2
2
  import { DbClient } from './index.ts';
3
- import { QueryInput } from './types/find.ts';
3
+ import { QueryInput } from './types/find';
4
4
  import { Transaction } from '../transaction.js';
5
5
  import { CollectionObject } from '../model';
6
6
  type WhereClauseElement = [key: string, isFun: true, fn: (value: unknown) => boolean] | [key: string, isFun: false, value: unknown];
@@ -14,5 +14,5 @@ export declare function generateWhereClause(where?: Dict): WhereClauseElement[];
14
14
  export declare function parseWhere(whereArray: WhereClauseElement[], obj: unknown): boolean;
15
15
  export declare function generateSelector<ModelNames extends string, Models extends CollectionObject<ModelNames>, Db extends DbClient<string, ModelNames, Models>, Q extends QueryInput<ModelNames, any, Models> = QueryInput<ModelNames, any, Models>>(name: ModelNames, client: Db, query?: Q, initTx?: Transaction<IDBTransactionMode, ModelNames>): (item: Dict, tx: Transaction<IDBTransactionMode, ModelNames>) => Promisable<Dict | undefined>;
16
16
  export declare function getAccessedStores<ModelNames extends string, Models extends CollectionObject<ModelNames>>(name: ModelNames, query: Dict, isMutation: boolean, client: DbClient<string, ModelNames, Models>): Set<ModelNames>;
17
- export declare function getSearchableQuery(q: QueryInput<any, any, any>): import('./types/find.ts').SelectObject<any, any, any>;
17
+ export declare function getSearchableQuery(q: QueryInput<string, any, any>): import('./types/find').SelectObject<string, any, any, 10>;
18
18
  export {};
@@ -2,8 +2,8 @@ import { CompiledDb } from '../builder';
2
2
  import { Arrayable } from '../util-types';
3
3
  import { CollectionObject } from '../model';
4
4
  import { Transaction, TransactionOptions } from '../transaction';
5
- import { InterfaceMap } from './types';
6
- import { CsvDump, JsonDump } from '../dump/class.js';
5
+ import { InterfaceMap, ExportFormat } from './types';
6
+ import { Dump, DumpOptions } from './dump';
7
7
  export declare class DbClient<Name extends string, ModelNames extends string, Models extends CollectionObject<ModelNames>> {
8
8
  private readonly db;
9
9
  private readonly models;
@@ -15,8 +15,8 @@ export declare class DbClient<Name extends string, ModelNames extends string, Mo
15
15
  getStore<Name extends ModelNames>(name: Name): (typeof this.stores)[Name];
16
16
  getStoreNames(): ModelNames[];
17
17
  createTransaction<Mode extends IDBTransactionMode, Names extends ModelNames>(mode: Mode, stores: Arrayable<Names>, options?: TransactionOptions): Transaction<Mode, Names>;
18
- deleteDb(): Promise<void>;
19
- dump<Format extends "json" | "csv", Return = Format extends "json" ? JsonDump : CsvDump>(format: Format, stores?: ModelNames[]): Promise<Return>;
18
+ drop(): Promise<void>;
19
+ dump<const Format extends ExportFormat>(format: Format, stores?: ModelNames[], options?: DumpOptions): Promise<Dump<Format>>;
20
20
  deleteAllStores(): void;
21
21
  deleteStore(storeNames: Arrayable<ModelNames>): void;
22
22
  getModel<N extends ModelNames>(name: N): Models[N];
@@ -0,0 +1,14 @@
1
+ import { DbClient } from '.';
2
+ import { ValidKey } from '../field';
3
+ import { CollectionObject } from '../model';
4
+ import { Transaction } from '../transaction';
5
+ import { Dict } from '../util-types';
6
+ /**
7
+ * Pushes the data found in the data parameter to the given store
8
+ * @param db Database client instance
9
+ * @param store Name of the store to add to
10
+ * @param data Data object, where each key-value pair is a primary key and its document
11
+ * @param primaryKeys Map of all primary keys of other stores (and this one) that were included within the source file
12
+ * @param tx Transaction object
13
+ */
14
+ export declare function pushStoreData<Current extends Names, Names extends string>(db: DbClient<string, Names, CollectionObject<Names>>, store: Current, data: Dict, primaryKeys: Map<Names, Set<ValidKey>>, tx?: Transaction<"readwrite", Names>): Promise<void>;
@@ -1,29 +1,45 @@
1
- import { Dict, If, Keyof, MakeRequired, NoUndefined, RemoveNeverValues, Simplify } from '../../util-types.js';
2
- import { ExtractFields, ModelStructure, RelationlessModelStructure, RelationValue } from '../../model/model-types';
1
+ import { Dec, Dict, Keyof, MakeRequired, NoUndefined, RecursionLimit, RemoveNeverValues, Simplify } from '../../util-types';
2
+ import { ModelStructure, RelationlessModelStructure, RelationValue } from '../../model/model-types';
3
3
  import { Model, CollectionObject } from '../../model';
4
- import { BaseRelation, AbstractProperty, PrimaryKey, RelationOutputStructure, ValidValue, Relation } from '../../field';
4
+ import { BaseRelation, PrimaryKey, RelationOutputStructure, ValidValue, Relation, Property } from '../../field';
5
5
  export type FilterFn<Input> = (item: Input) => boolean;
6
6
  /**
7
7
  * If an property is an object type (dictionary, array, map, set, etc...) return never. If it's a union it strips out any object types
8
8
  */
9
9
  export type ProhibitObjects<T> = T extends Date ? Date : T extends object ? never : T;
10
+ type ModelFields<C, K extends keyof C> = C[K] extends Model<any, infer Fields, any> ? Fields : never;
10
11
  export type WhereObject<Fields extends Dict<ValidValue>> = Partial<RemoveNeverValues<{
11
- [K in keyof Fields]: Fields[K] extends AbstractProperty<infer Output, any> ? ProhibitObjects<Output> | FilterFn<Output> : Fields[K] extends PrimaryKey<any, infer Type> ? ProhibitObjects<Type> | FilterFn<Type> : never;
12
+ [K in keyof Fields]: Fields[K] extends Property<infer Output, any> ? ProhibitObjects<Output> | FilterFn<Output> : Fields[K] extends PrimaryKey<any, infer Type> ? ProhibitObjects<Type> | FilterFn<Type> : never;
12
13
  }>>;
13
- export type SelectObject<All extends string, Fields extends Dict<ValidValue>, C extends CollectionObject<All>> = {
14
- [K in keyof Fields]?: Fields[K] extends AbstractProperty<any, any> ? true : Fields[K] extends PrimaryKey<any, any> ? true : Fields[K] extends BaseRelation<infer To, any> ? true | (To extends Keyof<C> ? C[To] extends Model<any, infer SubFields, any> ? QueryInput<All, SubFields, C> : never : never) : never;
14
+ export type SelectObject<All extends string, Fields extends Dict<ValidValue>, C extends CollectionObject<All>, Depth extends number> = {
15
+ [K in keyof Fields]?: Fields[K] extends Property<any, any> ? true : Fields[K] extends PrimaryKey<any, any> ? true : Fields[K] extends BaseRelation<infer To, any> ? true | (To extends Keyof<C> ? C[To] extends Model<any, infer SubFields, any> ? QueryInput<All, SubFields, C, Depth> : never : never) : never;
15
16
  };
16
- export interface QueryInput<All extends string, Fields extends Dict<ValidValue>, C extends CollectionObject<All>> {
17
+ export interface QueryInput<All extends string, Fields extends Dict<ValidValue>, C extends CollectionObject<All>, Depth extends number = RecursionLimit> {
17
18
  where?: WhereObject<Fields>;
18
- select?: SelectObject<All, Fields, C>;
19
- include?: SelectObject<All, Fields, C>;
19
+ select?: SelectObject<All, Fields, C, Depth>;
20
+ include?: SelectObject<All, Fields, C, Depth>;
20
21
  }
21
- export type FindInput<All extends string, Struct extends object, C extends CollectionObject<All>> = Struct extends Model<any, infer Fields, any> ? QueryInput<All, Fields, C> : never;
22
- type SelectOutput<All extends string, Select extends Dict<Dict | true>, Fields extends Dict<ValidValue>, C extends CollectionObject<All>> = {
23
- [K in Keyof<Select>]: Fields[K] extends BaseRelation<infer To, any> ? To extends Keyof<C> ? C[To] extends Model<any, any, any> ? If<Select[K] extends true ? true : false, RelationOutputStructure<Fields[K], RelationlessModelStructure<C[To]>>, Select[K] extends FindInput<All, C[To], C> ? RelationOutputStructure<Fields[K], FindOutput<All, C[To], C, Select[K]>> : never> : never : never : Fields[K] extends PrimaryKey<any, infer Type> ? Type : Fields[K] extends AbstractProperty<infer Type, any> ? Type : never;
22
+ export type FindInput<All extends string, To extends keyof C, C extends CollectionObject<All>, Depth extends number = RecursionLimit> = Depth extends 0 ? never : QueryInput<All, ModelFields<C, To>, C, Dec<Depth>>;
23
+ type NormalizeQuery<F> = F extends {
24
+ select: infer S;
25
+ } ? {
26
+ mode: "select";
27
+ value: S;
28
+ } : F extends {
29
+ include: infer I;
30
+ } ? {
31
+ mode: "include";
32
+ value: I;
33
+ } : {
34
+ mode: "none";
35
+ value: any;
24
36
  };
25
- type IncludeOutput<All extends string, Include extends Dict<Dict | true>, Fields extends Dict<ValidValue>, C extends CollectionObject<All>> = Simplify<{
26
- [K in Keyof<Fields>]: Fields[K] extends BaseRelation<infer To, any> ? To extends Keyof<C> ? C[To] extends Model<any, any, any> ? K extends Keyof<Include> ? Include[K] extends true ? RelationOutputStructure<Fields[K], RelationlessModelStructure<C[To]>> : Include[K] extends FindInput<All, C[To], C> ? MakeRequired<Fields[K] extends Relation<any, any> ? true : false, NoUndefined<RelationOutputStructure<Fields[K], NoUndefined<FindOutput<All, C[To], C, Include[K]>>>>> : unknown : RelationOutputStructure<Fields[K], RelationValue<To, C>> : never : never : Fields[K] extends PrimaryKey<any, infer Type> ? Type : Fields[K] extends AbstractProperty<infer Type, any> ? Type : never;
27
- }>;
28
- export type FindOutput<All extends string, Struct extends Model<any, any, any>, C extends CollectionObject<All>, F extends FindInput<All, Struct, C>> = Struct extends Model<any, infer Fields, any> ? Simplify<F["select"] extends Dict<true | Dict> ? SelectOutput<All, F["select"], Fields, C> : F["include"] extends Dict<true | Dict> ? IncludeOutput<All, F["include"], Fields, C> : ModelStructure<ExtractFields<Struct>, C>> | undefined : never;
37
+ type _SelectOutput<All extends string, Select extends Dict<Dict | true>, Fields extends Dict<ValidValue>, C extends CollectionObject<All>, Depth extends number> = {
38
+ [K in Keyof<Select>]: Fields[K] extends BaseRelation<infer To, any> ? To extends keyof C ? Select[K] extends true ? RelationOutputStructure<Fields[K], RelationlessModelStructure<C[To]>> : Select[K] extends FindInput<All, To, C, Depth> ? RelationOutputStructure<Fields[K], FindOutput<All, To, C, Select[K]>> : never : never : Fields[K] extends PrimaryKey<any, infer Type> ? Type : Fields[K] extends Property<infer Type, any> ? Type : never;
39
+ };
40
+ type _IncludeOutput<All extends string, Include extends Record<Keys, Dict | true>, Fields extends Dict<ValidValue>, C extends CollectionObject<All>, Depth extends number, Keys extends Keyof<Fields> = Keyof<Fields>> = {
41
+ [K in Keys]: Fields[K] extends BaseRelation<infer To, any> ? To extends keyof C ? Include[K] extends true ? RelationOutputStructure<Fields[K], RelationlessModelStructure<C[To]>> : Include[K] extends FindInput<All, To, C, Depth> ? MakeRequired<Fields[K] extends Relation<any, any> ? true : false, NoUndefined<RelationOutputStructure<Fields[K], NoUndefined<FindOutput<All, To, C, Include[K]>>>>> : unknown : RelationOutputStructure<Fields[K], RelationValue<To, C>> : Fields[K] extends PrimaryKey<any, infer Type> ? Type : Fields[K] extends Property<infer Type, any> ? Type : never;
42
+ };
43
+ type _OutputFromQuery<Q extends NormalizeQuery<any>, Fields extends Dict<ValidValue>, All extends string, C extends CollectionObject<All>, Depth extends number> = Q["mode"] extends "none" ? ModelStructure<Fields, C> : Q["mode"] extends "select" ? _SelectOutput<All, Q["value"], Fields, C, Depth> : Q["mode"] extends "include" ? _IncludeOutput<All, Q["value"], Fields, C, Depth> : never;
44
+ export type FindOutput<All extends string, Name extends keyof C, C extends CollectionObject<All>, FIn extends FindInput<All, Name, C>, Depth extends number = RecursionLimit> = Depth extends 0 ? unknown : C[Name] extends Model<any, infer Fields, any> ? Simplify<_OutputFromQuery<NormalizeQuery<FIn>, Fields, All, C, Dec<Depth>>> | undefined : never;
29
45
  export {};
@@ -1,28 +1,28 @@
1
1
  import { Dict, Simplify } from '../../util-types.js';
2
2
  import { ExtractFields, Model, ModelStructure, PrimaryKeyType, CollectionObject } from '../../model';
3
3
  import { AddMutation, MutationAction, UpdateMutation } from './mutation.ts';
4
- import { FindInput, FindOutput, WhereObject } from './find.ts';
4
+ import { FindInput, FindOutput, WhereObject } from './find.js';
5
5
  import { CompiledQuery } from '../compiled-query.ts';
6
6
  import { DbClient } from '../index.ts';
7
7
  import { Transaction } from '../../transaction.js';
8
8
  import { BaseRelation, ValidKey } from '../../field';
9
- import { CsvDump, JsonDump } from '../../dump/class.js';
9
+ import { Dump } from '../dump.js';
10
10
  export type GetStructure<N extends string, C extends Dict> = C[N] extends Model<N, infer F, any> ? Simplify<ModelStructure<F, C>> : never;
11
- export type ExportFormat = "json";
11
+ export type ExportFormat = "json" | "csv";
12
12
  export interface StoreInterface<Name extends Names, Names extends string, C extends CollectionObject<Names>, KeyType = PrimaryKeyType<C[Name]>, Add = AddMutation<Name, Names, C[Name], C>, Update extends UpdateMutation<Name, Names, C[Name], C> = UpdateMutation<Name, Names, C[Name], C>> {
13
13
  add(mutation: Add, transaction?: Transaction<"readwrite", Names>): Promise<KeyType>;
14
14
  addMany(mutations: Add[], transaction?: Transaction<"readwrite", Names>): Promise<KeyType[]>;
15
- find<T extends FindInput<Names, C[Name], C>>(query: T, transaction?: Transaction<IDBTransactionMode, Names>): Promise<NonNullable<FindOutput<Names, C[Name], C, T>>[]>;
16
- findFirst<T extends FindInput<Names, C[Name], C>>(query: T, transaction?: Transaction<IDBTransactionMode, Names>): Promise<FindOutput<Names, C[Name], C, T>>;
15
+ find<T extends FindInput<Names, Name, C>>(query: T, transaction?: Transaction<IDBTransactionMode, Names>): Promise<NonNullable<FindOutput<Names, Name, C, T>>[]>;
16
+ findFirst<T extends FindInput<Names, Name, C>>(query: T, transaction?: Transaction<IDBTransactionMode, Names>): Promise<FindOutput<Names, Name, C, T>>;
17
17
  update(key: KeyType, data: Update["data"]): Promise<GetStructure<Name, C>>;
18
18
  updateFirst(item: Update, transaction?: Transaction<"readwrite", Names>): Promise<GetStructure<Name, C> | undefined>;
19
19
  updateMany(item: Update, transaction?: Transaction<"readwrite", Names>): Promise<GetStructure<Name, C>[]>;
20
20
  delete(key: KeyType): Promise<boolean>;
21
21
  deleteFirst(where?: WhereObject<ExtractFields<C[Name]>>): Promise<boolean>;
22
22
  deleteMany(where: WhereObject<ExtractFields<C[Name]>>): Promise<number>;
23
- compileQuery<T extends FindInput<Names, C[Name], C>>(query: T): CompiledQuery<Names, C, DbClient<string, Names, C>, T>;
23
+ compileQuery<T extends FindInput<Names, Name, C>>(query: T): CompiledQuery<Names, C, DbClient<string, Names, C>, T>;
24
24
  get(key: KeyType): Promise<GetStructure<Name, C> | undefined>;
25
- dump<Format extends ExportFormat>(format: Format, where?: WhereObject<C[Name] extends Model<any, infer Fields, any> ? Fields : never>): Promise<Format extends "json" ? JsonDump : CsvDump>;
25
+ dump<Format extends ExportFormat>(format: Format, where?: WhereObject<C[Name] extends Model<any, infer Fields, any> ? Fields : never>): Promise<Dump<Format>>;
26
26
  }
27
27
  export type InterfaceMap<Names extends string, C extends CollectionObject<Names>> = {
28
28
  [K in Names]: Simplify<StoreInterface<K, Names, C>>;
@@ -1,49 +1,50 @@
1
- import { MakeArrayable, MakeOptional, RemoveNeverValues, PartialOnUndefined, Extends, If, Or, Keyof } from '../../util-types.js';
2
- import { BaseRelation, AbstractProperty, OptionalRelation, PrimaryKey, ArrayRelation } from '../../field';
3
- import { WhereObject } from './find.js';
1
+ import { MakeArrayable, MakeOptional, RemoveNeverValues, PartialOnUndefined, Extends, If, Or, Keyof } from '../../util-types';
2
+ import { BaseRelation, Property, OptionalRelation, PrimaryKey, ArrayRelation } from '../../field';
3
+ import { WhereObject } from './find';
4
4
  import { Model, FindRelationKey, RelationValue, CollectionObject } from '../../model';
5
5
  export type MutationAction = "$connect" | "$connectMany" | "$create" | "$createMany" | "$update" | "$updateMany" | "$delete" | "$deleteMany" | "$deleteAll" | "$disconnect" | "$disconnectMany" | "$disconnectAll";
6
6
  type WhereSelection<Struct extends object> = Struct extends Model<any, infer Fields, any> ? WhereObject<Fields> : never;
7
- type _UpdateRelationMutation<This extends All, All extends string, C extends CollectionObject<All>, To extends All, Name extends string, Relation extends BaseRelation<To, Name>, ThisKey extends string, OmitKeys extends string, IsOptional extends boolean = Extends<Relation, OptionalRelation<any, any>>, IsArray extends boolean = Extends<Relation, ArrayRelation<any, any>>, IsNullable extends boolean = Or<IsOptional, IsArray>> = MakeOptional<IsNullable, MakeArrayable<IsArray, {
8
- $connect: RelationValue<To, C>;
7
+ type _UpdateRelationMutation<This extends All, All extends string, C extends CollectionObject<All>, To extends All, Name extends string, Relation extends BaseRelation<To, Name>, ThisKey extends string, OmitKeys extends string, IsOptional extends boolean = Extends<Relation, OptionalRelation<any, any>>, IsArray extends boolean = Extends<Relation, ArrayRelation<any, any>>, IsNullable extends boolean = Or<IsOptional, IsArray>, Value = RelationValue<To, C>, Dest extends C[To] = C[To]> = MakeOptional<IsNullable, MakeArrayable<IsArray, {
8
+ $connect: Value;
9
9
  } | {
10
- $create: Omit<AddMutation<To, All, C[To], C>, OmitKeys | FindRelationKey<This, Name, C[To]>>;
10
+ $create: Omit<AddMutation<To, All, Dest, C>, OmitKeys | FindRelationKey<This, Name, Dest>>;
11
11
  } | {
12
- $update: If<IsArray, UpdateMutation<To, All, C[To], C, OmitKeys | ThisKey>, Omit<UpdateMutation<To, All, C[To], C>["data"], OmitKeys>>;
12
+ $update: If<IsArray, UpdateMutation<To, All, Dest, C, OmitKeys | ThisKey>, Omit<UpdateMutation<To, All, Dest, C>["data"], OmitKeys>>;
13
13
  } | If<IsNullable, {
14
- $delete: If<IsArray, RelationValue<To, C>, true>;
14
+ $delete: If<IsArray, Value, true>;
15
15
  } | {
16
- $disconnect: If<IsArray, RelationValue<To, C>, true>;
16
+ $disconnect: If<IsArray, Value, true>;
17
17
  }, never>> | If<IsArray, {
18
- $connectMany: RelationValue<To, C>[];
18
+ $connectMany: Value[];
19
19
  } | {
20
- $createMany: Omit<AddMutation<To, All, C[To], C>, OmitKeys | FindRelationKey<This, Name, C[To]>>[];
20
+ $createMany: Omit<AddMutation<To, All, Dest, C>, OmitKeys | FindRelationKey<This, Name, Dest>>[];
21
21
  } | {
22
- $updateMany: UpdateMutation<To, All, C[To], C, OmitKeys | ThisKey>[];
22
+ $updateMany: UpdateMutation<To, All, Dest, C, OmitKeys | ThisKey>[];
23
23
  } | {
24
- $deleteMany: RelationValue<To, C>[];
24
+ $deleteMany: Value[];
25
25
  } | {
26
26
  $deleteAll: true;
27
27
  } | {
28
- $disconnectMany: RelationValue<To, C>[];
28
+ $disconnectMany: Value[];
29
29
  } | {
30
30
  $disconnectAll: true;
31
31
  }, never>>;
32
32
  export type UpdateMutation<This extends All, All extends string, Struct extends object, C extends CollectionObject<All>, OmitKeys extends string = never> = {
33
33
  where?: WhereSelection<Struct>;
34
34
  data: PartialOnUndefined<RemoveNeverValues<Struct extends Model<any, infer Fields, any> ? {
35
- [K in Exclude<Keyof<Fields>, OmitKeys>]: Fields[K] extends AbstractProperty<infer Type, any> ? Type | undefined | ((value: Type) => Type) : Fields[K] extends PrimaryKey<any, any> ? never : Fields[K] extends BaseRelation<infer To, infer Name> ? To extends All ? _UpdateRelationMutation<This, All, C, To, Name, Fields[K], K, OmitKeys> | undefined : never : never;
35
+ [K in Exclude<Keyof<Fields>, OmitKeys>]: Fields[K] extends Property<infer Type, any> ? Type | undefined | ((value: Type) => Type) : Fields[K] extends PrimaryKey<any, any> ? never : Fields[K] extends BaseRelation<infer To, infer Name> ? To extends All ? _UpdateRelationMutation<This, All, C, To, Name, Fields[K], K, OmitKeys> | undefined : never : never;
36
36
  } : never>>;
37
37
  };
38
+ type AddMutationRelation<This extends All, All extends string, C extends CollectionObject<All>, To extends All, RelationName extends string, Relation extends BaseRelation<any, any>, IsArray extends boolean = Extends<Relation, ArrayRelation<any, any>>, Value = RelationValue<To, C>> = MakeOptional<Or<IsArray, Extends<Relation, OptionalRelation<any, any>>>, MakeArrayable<IsArray, {
39
+ $connect: Value;
40
+ } | {
41
+ $create: Omit<AddMutation<To, All, C[To], C>, FindRelationKey<This, RelationName, C[To]>>;
42
+ }> | If<IsArray, {
43
+ $connectMany: Value[];
44
+ } | {
45
+ $createMany: Omit<AddMutation<To, All, C[To], C>, FindRelationKey<This, RelationName, C[To]>>[];
46
+ }, never>>;
38
47
  export type AddMutation<This extends All, All extends string, Struct extends object, C extends CollectionObject<All>> = PartialOnUndefined<RemoveNeverValues<Struct extends Model<any, infer Fields, any> ? {
39
- [K in keyof Fields]: Fields[K] extends AbstractProperty<infer Type, infer HasDefault> ? HasDefault extends true ? Type | undefined : Type : Fields[K] extends PrimaryKey<infer IsAuto, infer Type> ? IsAuto extends true ? never : Type : Fields[K] extends BaseRelation<infer To, infer Name> ? To extends All ? MakeOptional<Fields[K] extends OptionalRelation<any, any> ? true : Fields[K] extends ArrayRelation<any, any> ? true : false, MakeArrayable<Fields[K] extends ArrayRelation<any, any> ? true : false, {
40
- $connect: RelationValue<To, C>;
41
- } | {
42
- $create: Omit<AddMutation<To, All, C[To], C>, FindRelationKey<This, Name, C[To]>>;
43
- }> | (Fields[K] extends ArrayRelation<any, any> ? {
44
- $connectMany: RelationValue<To, C>[];
45
- } | {
46
- $createMany: Omit<AddMutation<To, All, C[To], C>, FindRelationKey<This, Name, C[To]>>[];
47
- } : never)> : never : never;
48
+ [K in keyof Fields]: Fields[K] extends Property<infer Type, infer HasDefault> ? HasDefault extends true ? Type | undefined : Type : Fields[K] extends PrimaryKey<infer IsAuto, infer Type> ? IsAuto extends true ? never : Type : Fields[K] extends BaseRelation<infer To, infer Name> ? To extends All ? AddMutationRelation<This, All, C, To, Name, Fields[K]> : never : never;
48
49
  } : never>>;
49
50
  export {};
package/dist/core.d.ts CHANGED
@@ -1,14 +1,10 @@
1
- export { AbstractProperty } from './field/property';
2
1
  export type { ParseFn, PropertyOptions, PropertyInputOptions, } from './field/property';
3
2
  export type { PropertyUnion } from './field/field-types';
4
3
  export * from './util-types';
5
4
  export { Model } from './model';
6
5
  export type { FindPrimaryKey, CollectionObject, ModelStructure, PrimaryKeyType, } from './model';
7
- export { VALIDATORS } from './field/validators.js';
8
6
  export * from './field';
9
7
  export * from './client';
10
- export { Type } from './field/type-wrapper';
11
- export type { TypeTag } from './field/type-wrapper';
12
8
  export type { FindInput, FindOutput } from './client/types/find';
13
9
  export type * from './client/types';
14
- export * as Typing from './field/type-wrapper';
10
+ export * from './typing';
package/dist/error.d.ts CHANGED
@@ -6,7 +6,7 @@ export type ErrorType = "ID_EXISTS" | "INVALID_ITEM" | "ADD_FAILED" | "UPDATE_FA
6
6
  /**
7
7
  * The database is not found
8
8
  */
9
- | "NO_DB" | "CUSTOM" | "INVALID_CONFIG" | "ASSERTION_FAILED" | "OPEN_CURSOR" | "UNKNOWN";
9
+ | "NO_DB" | "CUSTOM" | "INVALID_CONFIG" | "ASSERTION_FAILED" | "IMPORT_FAILED" | "OPEN_CURSOR" | "SERIALIZATION_FAILED" | "DESERIALIZATION_FAILED" | "UNKNOWN";
10
10
  export declare class StoreError extends Error {
11
11
  readonly code: ErrorType;
12
12
  constructor(code: ErrorType, message: string);
@@ -221,3 +221,48 @@ export declare const ExportError: {
221
221
  prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
222
222
  stackTraceLimit: number;
223
223
  };
224
+ export declare const ImportError: {
225
+ new (message?: string): {
226
+ readonly code: ErrorType;
227
+ name: string;
228
+ message: string;
229
+ stack?: string;
230
+ cause?: unknown;
231
+ };
232
+ readonly code: "IMPORT_FAILED";
233
+ of(message: string): void;
234
+ isError(error: unknown): error is Error;
235
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
236
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
237
+ stackTraceLimit: number;
238
+ };
239
+ export declare const SerializationError: {
240
+ new (message?: string): {
241
+ readonly code: ErrorType;
242
+ name: string;
243
+ message: string;
244
+ stack?: string;
245
+ cause?: unknown;
246
+ };
247
+ readonly code: "SERIALIZATION_FAILED";
248
+ of(message: string): void;
249
+ isError(error: unknown): error is Error;
250
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
251
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
252
+ stackTraceLimit: number;
253
+ };
254
+ export declare const DeserializationError: {
255
+ new (message?: string): {
256
+ readonly code: ErrorType;
257
+ name: string;
258
+ message: string;
259
+ stack?: string;
260
+ cause?: unknown;
261
+ };
262
+ readonly code: "DESERIALIZATION_FAILED";
263
+ of(message: string): void;
264
+ isError(error: unknown): error is Error;
265
+ captureStackTrace(targetObject: object, constructorOpt?: Function): void;
266
+ prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
267
+ stackTraceLimit: number;
268
+ };
@@ -1,8 +1,8 @@
1
1
  import { Dict } from '../util-types.js';
2
2
  import { default as PrimaryKey } from './primary-key.js';
3
- import { AbstractProperty, ParseFn, Property } from './property.js';
3
+ import { ParseFn, Property } from './property.js';
4
4
  import { BaseRelation, OptionalRelation, ArrayRelation } from './relation.js';
5
- import { DateTag, NumberTag, StringTag } from './type-wrapper.js';
5
+ import { DateTag, NumberTag, StringTag } from '../typing';
6
6
  export type ValidKey = string | number | Date;
7
7
  export type StringValidKeyType = "string" | "date" | "number";
8
8
  export type ValidKeyType = StringTag | DateTag | NumberTag;
@@ -21,7 +21,7 @@ export declare const enum FieldTypes {
21
21
  PrimaryKey = 2,
22
22
  Invalid = 3
23
23
  }
24
- export type GenFunction<T extends ValidKey> = () => T;
24
+ export type GenFunction<T extends ValidKey> = (...args: unknown[]) => T;
25
25
  export type FunctionMatch<E> = E extends "string" ? string : E extends "number" ? number : E extends "date" ? Date : never;
26
26
  export type GetPrimaryKeyType<T> = T extends PrimaryKey<any, infer Type> ? Type : never;
27
27
  export interface FieldOptions {
@@ -29,8 +29,8 @@ export interface FieldOptions {
29
29
  }
30
30
  export type RelationOutput<T> = T extends PrimaryKey<any, infer Type> ? Type : never;
31
31
  export type RelationOutputStructure<R extends BaseRelation<any, any>, Output> = R extends ArrayRelation<any, any> ? Output[] : R extends OptionalRelation<any, any> ? Output | null : Output;
32
- export type NonRelationOutput<T> = T extends AbstractProperty<infer Out, any> ? Out : T extends PrimaryKey<any, infer Type> ? Type : never;
33
- export type ValidValue<N extends string = string> = BaseRelation<N, string> | AbstractProperty<any, any> | PrimaryKey<boolean, ValidKey>;
32
+ export type NonRelationOutput<T> = T extends Property<infer Out, any> ? Out : T extends PrimaryKey<any, infer Type> ? Type : never;
33
+ export type ValidValue<N extends string = string> = BaseRelation<N, string> | Property<any, any> | PrimaryKey<boolean, ValidKey>;
34
34
  export type ParseFnWrap<T extends Dict> = {
35
35
  [K in keyof T]: ParseFn<T[K]>;
36
36
  };
@@ -3,4 +3,4 @@ export { PrimaryKey };
3
3
  export * from './relation.js';
4
4
  export * from './field-types.js';
5
5
  export * from './property.js';
6
- export * from './type-wrapper.js';
6
+ export * from '../typing';