edinburgh 0.4.6 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -381
- package/build/src/datapack.js +1 -1
- package/build/src/datapack.js.map +1 -1
- package/build/src/edinburgh.d.ts +5 -5
- package/build/src/edinburgh.js +6 -7
- package/build/src/edinburgh.js.map +1 -1
- package/build/src/indexes.d.ts +44 -113
- package/build/src/indexes.js +145 -175
- package/build/src/indexes.js.map +1 -1
- package/build/src/migrate.js +11 -31
- package/build/src/migrate.js.map +1 -1
- package/build/src/models.d.ts +73 -54
- package/build/src/models.js +110 -171
- package/build/src/models.js.map +1 -1
- package/build/src/types.d.ts +29 -21
- package/build/src/types.js +16 -30
- package/build/src/types.js.map +1 -1
- package/package.json +1 -3
- package/skill/BaseIndex_batchProcess.md +1 -1
- package/skill/BaseIndex_find.md +2 -2
- package/skill/BaseIndex_find_2.md +7 -0
- package/skill/BaseIndex_find_3.md +7 -0
- package/skill/BaseIndex_find_4.md +7 -0
- package/skill/Model.md +5 -7
- package/skill/Model_batchProcess.md +8 -0
- package/skill/Model_delete.md +1 -1
- package/skill/Model_migrate.md +2 -4
- package/skill/Model_preCommit.md +2 -4
- package/skill/Model_preventPersist.md +1 -1
- package/skill/Model_replaceInto.md +2 -2
- package/skill/NonPrimaryIndex.md +10 -0
- package/skill/SKILL.md +140 -150
- package/skill/SecondaryIndex.md +2 -2
- package/skill/UniqueIndex.md +2 -2
- package/skill/defineModel.md +22 -0
- package/skill/field.md +2 -2
- package/skill/link.md +11 -9
- package/skill/transact.md +2 -2
- package/src/datapack.ts +1 -1
- package/src/edinburgh.ts +6 -9
- package/src/indexes.ts +155 -271
- package/src/migrate.ts +9 -30
- package/src/models.ts +186 -180
- package/src/types.ts +31 -26
- package/skill/Model_findAll.md +0 -12
- package/skill/PrimaryIndex.md +0 -8
- package/skill/PrimaryIndex_get.md +0 -17
- package/skill/PrimaryIndex_getLazy.md +0 -13
- package/skill/UniqueIndex_get.md +0 -17
- package/skill/index.md +0 -32
- package/skill/primary.md +0 -26
- package/skill/registerModel.md +0 -26
- package/skill/unique.md +0 -32
package/src/types.ts
CHANGED
|
@@ -2,7 +2,6 @@ import DataPack from "./datapack.js";
|
|
|
2
2
|
import { DatabaseError } from "olmdb/lowlevel";
|
|
3
3
|
import { Model, modelRegistry, FieldConfig, currentTxn } from "./models.js";
|
|
4
4
|
import { assert, addErrorPath, dbGet } from "./utils.js";
|
|
5
|
-
import { PrimaryIndex, BaseIndex, IndexRangeIterator } from "./indexes.js";
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -71,7 +70,7 @@ export abstract class TypeWrapper<const T> {
|
|
|
71
70
|
return value1 === value2;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
getLinkedModel():
|
|
73
|
+
getLinkedModel(): undefined | typeof Model<unknown> {
|
|
75
74
|
return;
|
|
76
75
|
}
|
|
77
76
|
}
|
|
@@ -355,7 +354,7 @@ class RecordType<T> extends TypeWrapper<Record<string | number, T>> {
|
|
|
355
354
|
|
|
356
355
|
serialize(value: Record<string | number, T>, pack: DataPack) {
|
|
357
356
|
pack.writeCollectionBoundary('object');
|
|
358
|
-
for (const key
|
|
357
|
+
for (const key in value) {
|
|
359
358
|
pack.writeObjectKey(key);
|
|
360
359
|
this.inner.serialize(value[key], pack);
|
|
361
360
|
}
|
|
@@ -374,7 +373,7 @@ class RecordType<T> extends TypeWrapper<Record<string | number, T>> {
|
|
|
374
373
|
}
|
|
375
374
|
|
|
376
375
|
getError(value: Record<string | number, T>) {
|
|
377
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
376
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value) || (typeof value.length === 'number' && typeof value[Symbol.iterator as any] === 'function')) {
|
|
378
377
|
return new DatabaseError(`Expected object, got ${typeof value}`, 'INVALID_TYPE');
|
|
379
378
|
}
|
|
380
379
|
for (const key of Object.keys(value)) {
|
|
@@ -605,17 +604,22 @@ class IdentifierType extends TypeWrapper<string> {
|
|
|
605
604
|
* @internal Type wrapper for model relationships (foreign keys).
|
|
606
605
|
* @template T - The target model class type.
|
|
607
606
|
*/
|
|
608
|
-
export class LinkType<T extends
|
|
607
|
+
export class LinkType<T extends new (...args: any[]) => Model<any>> extends TypeWrapper<InstanceType<T>> {
|
|
609
608
|
kind = 'link';
|
|
610
|
-
|
|
609
|
+
private TargetModel: T | (() => T);
|
|
611
610
|
|
|
612
611
|
/**
|
|
613
612
|
* Create a new LinkType.
|
|
614
|
-
* @param TargetModel - The model class this link points to.
|
|
613
|
+
* @param TargetModel - The model class this link points to, or a thunk for forward references.
|
|
615
614
|
*/
|
|
616
|
-
constructor(TargetModel: T) {
|
|
615
|
+
constructor(TargetModel: T | (() => T)) {
|
|
617
616
|
super();
|
|
618
|
-
this.
|
|
617
|
+
this.TargetModel = TargetModel;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
getLinkedModel(): typeof Model<unknown> {
|
|
621
|
+
if (!('getLazy' in this.TargetModel)) this.TargetModel = (this.TargetModel as unknown as () => T)();
|
|
622
|
+
return this.TargetModel as any;
|
|
619
623
|
}
|
|
620
624
|
|
|
621
625
|
serialize(model: InstanceType<T>, pack: DataPack) {
|
|
@@ -623,31 +627,28 @@ export class LinkType<T extends typeof Model<unknown>> extends TypeWrapper<Insta
|
|
|
623
627
|
}
|
|
624
628
|
|
|
625
629
|
deserialize(pack: DataPack) {
|
|
626
|
-
return
|
|
630
|
+
return this.getLinkedModel()._primary._get(currentTxn(), pack.readUint8Array(), false);
|
|
627
631
|
}
|
|
628
632
|
|
|
629
633
|
getError(value: InstanceType<T>) {
|
|
630
|
-
|
|
631
|
-
|
|
634
|
+
const TargetModel = this.getLinkedModel();
|
|
635
|
+
if (!((value as any) instanceof TargetModel)) {
|
|
636
|
+
return new DatabaseError(`Expected instance of ${TargetModel.tableName}, got ${typeof value}`, 'VALUE_ERROR');
|
|
632
637
|
}
|
|
633
638
|
}
|
|
634
639
|
|
|
635
640
|
serializeType(pack: DataPack): void {
|
|
636
|
-
pack.write(this.tableName);
|
|
641
|
+
pack.write(this.getLinkedModel().tableName);
|
|
637
642
|
}
|
|
638
643
|
|
|
639
644
|
static deserializeType(pack: DataPack, featureFlags: number): LinkType<any> {
|
|
640
645
|
const tableName = pack.readString();
|
|
641
646
|
const targetModel = modelRegistry[tableName];
|
|
642
647
|
if (!targetModel) throw new DatabaseError(`Could not deserialize undefined model ${tableName}`, 'DESERIALIZATION_ERROR');
|
|
643
|
-
return new LinkType(targetModel);
|
|
648
|
+
return new LinkType(targetModel as any);
|
|
644
649
|
}
|
|
645
650
|
|
|
646
|
-
toString() { return `link<${this.tableName}>`; }
|
|
647
|
-
|
|
648
|
-
getLinkedModel(): T {
|
|
649
|
-
return modelRegistry[this.tableName] as T;
|
|
650
|
-
}
|
|
651
|
+
toString() { return `link<${this.getLinkedModel().tableName}>`; }
|
|
651
652
|
}
|
|
652
653
|
|
|
653
654
|
/** Type wrapper instance for the string type. */
|
|
@@ -781,16 +782,20 @@ export function record<const T>(inner: TypeWrapper<T>): TypeWrapper<Record<strin
|
|
|
781
782
|
*
|
|
782
783
|
* @example
|
|
783
784
|
* ```typescript
|
|
784
|
-
*
|
|
785
|
-
*
|
|
786
|
-
*
|
|
785
|
+
* const Author = E.defineModel(class {
|
|
786
|
+
* id = E.field(E.identifier);
|
|
787
|
+
* posts = E.field(E.array(E.link(() => Book)));
|
|
788
|
+
* }, { pk: "id" });
|
|
787
789
|
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
790
|
+
* const Book = E.defineModel(class {
|
|
791
|
+
* id = E.field(E.identifier);
|
|
792
|
+
* author = E.field(E.link(Author));
|
|
793
|
+
* }, { pk: "id" });
|
|
791
794
|
* ```
|
|
792
795
|
*/
|
|
793
|
-
export function link<const T extends
|
|
796
|
+
export function link<const T extends new (...args: any[]) => Model<any>>(TargetModel: T): TypeWrapper<InstanceType<T>>;
|
|
797
|
+
export function link<const T extends new (...args: any[]) => Model<any>>(TargetModel: () => T): TypeWrapper<InstanceType<T>>;
|
|
798
|
+
export function link(TargetModel: any): TypeWrapper<any> {
|
|
794
799
|
return new LinkType(TargetModel);
|
|
795
800
|
}
|
|
796
801
|
|
package/skill/Model_findAll.md
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#### Model.findAll · static method
|
|
2
|
-
|
|
3
|
-
Find all instances of this model in the database, ordered by primary key.
|
|
4
|
-
|
|
5
|
-
**Signature:** `<T extends typeof Model<unknown>>(this: T, opts?: { reverse?: boolean; }) => IndexRangeIterator<T>`
|
|
6
|
-
|
|
7
|
-
**Parameters:**
|
|
8
|
-
|
|
9
|
-
- `this: T`
|
|
10
|
-
- `opts?: {reverse?: boolean}` - - Optional parameters.
|
|
11
|
-
|
|
12
|
-
**Returns:** An iterator.
|
package/skill/PrimaryIndex.md
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
### PrimaryIndex · class
|
|
2
|
-
|
|
3
|
-
Primary index that stores the actual model data.
|
|
4
|
-
|
|
5
|
-
**Type Parameters:**
|
|
6
|
-
|
|
7
|
-
- `M extends typeof Model` - The model class this index belongs to.
|
|
8
|
-
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#### primaryIndex.get · method
|
|
2
|
-
|
|
3
|
-
Get a model instance by primary key values.
|
|
4
|
-
|
|
5
|
-
**Signature:** `(...args: IndexArgTypes<M, F>) => InstanceType<M>`
|
|
6
|
-
|
|
7
|
-
**Parameters:**
|
|
8
|
-
|
|
9
|
-
- `args: IndexArgTypes<M, F>` - - The primary key values.
|
|
10
|
-
|
|
11
|
-
**Returns:** The model instance if found, undefined otherwise.
|
|
12
|
-
|
|
13
|
-
**Examples:**
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
const user = User.pk.get("john_doe");
|
|
17
|
-
```
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#### primaryIndex.getLazy · method
|
|
2
|
-
|
|
3
|
-
Does the same as as `get()`, but will delay loading the instance from disk until the first
|
|
4
|
-
property access. In case it turns out the instance doesn't exist, an error will be thrown
|
|
5
|
-
at that time.
|
|
6
|
-
|
|
7
|
-
**Signature:** `(...args: IndexArgTypes<M, F>) => InstanceType<M>`
|
|
8
|
-
|
|
9
|
-
**Parameters:**
|
|
10
|
-
|
|
11
|
-
- `args: IndexArgTypes<M, F>` - Primary key field values. (Or a single Uint8Array containing the key.)
|
|
12
|
-
|
|
13
|
-
**Returns:** The (lazily loaded) model instance.
|
package/skill/UniqueIndex_get.md
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#### uniqueIndex.get · method
|
|
2
|
-
|
|
3
|
-
Get a model instance by unique index key values.
|
|
4
|
-
|
|
5
|
-
**Signature:** `(...args: ARGS) => InstanceType<M>`
|
|
6
|
-
|
|
7
|
-
**Parameters:**
|
|
8
|
-
|
|
9
|
-
- `args: ARGS` - - The unique index key values.
|
|
10
|
-
|
|
11
|
-
**Returns:** The model instance if found, undefined otherwise.
|
|
12
|
-
|
|
13
|
-
**Examples:**
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
const userByEmail = User.byEmail.get("john@example.com");
|
|
17
|
-
```
|
package/skill/index.md
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
### index · function
|
|
2
|
-
|
|
3
|
-
Create a secondary index on model fields, or a computed secondary index using a function.
|
|
4
|
-
|
|
5
|
-
For field-based indexes, pass a field name or array of field names.
|
|
6
|
-
For computed indexes, pass a function that takes a model instance and returns an array of
|
|
7
|
-
index keys. Return `[]` to skip indexing for that instance. Each array element creates a
|
|
8
|
-
separate index entry, enabling multi-value indexes (e.g., indexing by each word in a name).
|
|
9
|
-
|
|
10
|
-
**Signature:** `{ <M extends typeof Model, V>(MyModel: M, fn: (instance: InstanceType<M>) => V[]): SecondaryIndex<M, [], [V]>; <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): SecondaryIndex<...>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(...`
|
|
11
|
-
|
|
12
|
-
**Type Parameters:**
|
|
13
|
-
|
|
14
|
-
- `M extends typeof Model` - The model class.
|
|
15
|
-
- `V` - The computed index value type (for function-based indexes).
|
|
16
|
-
|
|
17
|
-
**Parameters:**
|
|
18
|
-
|
|
19
|
-
- `MyModel: M` - - The model class to create the index for.
|
|
20
|
-
- `fn: (instance: InstanceType<M>) => V[]`
|
|
21
|
-
|
|
22
|
-
**Returns:** A new SecondaryIndex instance.
|
|
23
|
-
|
|
24
|
-
**Examples:**
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
class User extends E.Model<User> {
|
|
28
|
-
static byAge = E.index(User, "age");
|
|
29
|
-
static byTagsDate = E.index(User, ["tags", "createdAt"]);
|
|
30
|
-
static byWord = E.index(User, (u: User) => u.name.split(" "));
|
|
31
|
-
}
|
|
32
|
-
```
|
package/skill/primary.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
### primary · function
|
|
2
|
-
|
|
3
|
-
Create a primary index on model fields.
|
|
4
|
-
|
|
5
|
-
**Signature:** `{ <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): PrimaryIndex<M, [F]>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(MyModel: M, fields: FS): PrimaryIndex<...>; }`
|
|
6
|
-
|
|
7
|
-
**Type Parameters:**
|
|
8
|
-
|
|
9
|
-
- `M extends typeof Model` - The model class.
|
|
10
|
-
- `F extends (keyof InstanceType<M> & string)` - The field name (for single field index).
|
|
11
|
-
|
|
12
|
-
**Parameters:**
|
|
13
|
-
|
|
14
|
-
- `MyModel: M` - - The model class to create the index for.
|
|
15
|
-
- `field: F` - - Single field name for simple indexes.
|
|
16
|
-
|
|
17
|
-
**Returns:** A new PrimaryIndex instance.
|
|
18
|
-
|
|
19
|
-
**Examples:**
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
class User extends E.Model<User> {
|
|
23
|
-
static pk = E.primary(User, ["id"]);
|
|
24
|
-
static pkSingle = E.primary(User, "id");
|
|
25
|
-
}
|
|
26
|
-
```
|
package/skill/registerModel.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
### registerModel · function
|
|
2
|
-
|
|
3
|
-
Register a model class with the Edinburgh ORM system.
|
|
4
|
-
|
|
5
|
-
**Signature:** `<T extends typeof Model<unknown>>(MyModel: T) => T`
|
|
6
|
-
|
|
7
|
-
**Type Parameters:**
|
|
8
|
-
|
|
9
|
-
- `T extends typeof Model<unknown>` - The model class type.
|
|
10
|
-
|
|
11
|
-
**Parameters:**
|
|
12
|
-
|
|
13
|
-
- `MyModel: T` - - The model class to register.
|
|
14
|
-
|
|
15
|
-
**Returns:** The enhanced model class with ORM capabilities.
|
|
16
|
-
|
|
17
|
-
**Examples:**
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
@E.registerModel
|
|
21
|
-
class User extends E.Model<User> {
|
|
22
|
-
static pk = E.index(User, ["id"], "primary");
|
|
23
|
-
id = E.field(E.identifier);
|
|
24
|
-
name = E.field(E.string);
|
|
25
|
-
}
|
|
26
|
-
```
|
package/skill/unique.md
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
### unique · function
|
|
2
|
-
|
|
3
|
-
Create a unique index on model fields, or a computed unique index using a function.
|
|
4
|
-
|
|
5
|
-
For field-based indexes, pass a field name or array of field names.
|
|
6
|
-
For computed indexes, pass a function that takes a model instance and returns an array of
|
|
7
|
-
index keys. Return `[]` to skip indexing for that instance. Each array element creates a
|
|
8
|
-
separate index entry, enabling multi-value indexes (e.g., indexing by each word in a name).
|
|
9
|
-
|
|
10
|
-
**Signature:** `{ <M extends typeof Model, V>(MyModel: M, fn: (instance: InstanceType<M>) => V[]): UniqueIndex<M, [], [V]>; <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): UniqueIndex<...>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(MyMode...`
|
|
11
|
-
|
|
12
|
-
**Type Parameters:**
|
|
13
|
-
|
|
14
|
-
- `M extends typeof Model` - The model class.
|
|
15
|
-
- `V` - The computed index value type (for function-based indexes).
|
|
16
|
-
|
|
17
|
-
**Parameters:**
|
|
18
|
-
|
|
19
|
-
- `MyModel: M` - - The model class to create the index for.
|
|
20
|
-
- `fn: (instance: InstanceType<M>) => V[]`
|
|
21
|
-
|
|
22
|
-
**Returns:** A new UniqueIndex instance.
|
|
23
|
-
|
|
24
|
-
**Examples:**
|
|
25
|
-
|
|
26
|
-
```typescript
|
|
27
|
-
class User extends E.Model<User> {
|
|
28
|
-
static byEmail = E.unique(User, "email");
|
|
29
|
-
static byNameAge = E.unique(User, ["name", "age"]);
|
|
30
|
-
static byFullName = E.unique(User, (u: User) => [`${u.firstName} ${u.lastName}`]);
|
|
31
|
-
}
|
|
32
|
-
```
|