edinburgh 0.1.2
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/LICENSE +15 -0
- package/README.md +804 -0
- package/build/src/bytes.d.ts +155 -0
- package/build/src/bytes.js +455 -0
- package/build/src/bytes.js.map +1 -0
- package/build/src/edinburgh.d.ts +47 -0
- package/build/src/edinburgh.js +93 -0
- package/build/src/edinburgh.js.map +1 -0
- package/build/src/indexes.d.ts +348 -0
- package/build/src/indexes.js +632 -0
- package/build/src/indexes.js.map +1 -0
- package/build/src/models.d.ts +192 -0
- package/build/src/models.js +457 -0
- package/build/src/models.js.map +1 -0
- package/build/src/types.d.ts +301 -0
- package/build/src/types.js +522 -0
- package/build/src/types.js.map +1 -0
- package/build/src/utils.d.ts +26 -0
- package/build/src/utils.js +32 -0
- package/build/src/utils.js.map +1 -0
- package/package.json +56 -0
- package/src/bytes.ts +500 -0
- package/src/edinburgh.ts +119 -0
- package/src/indexes.ts +810 -0
- package/src/models.ts +519 -0
- package/src/types.ts +635 -0
- package/src/utils.ts +39 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { DatabaseError } from "olmdb";
|
|
2
|
+
import { TypeWrapper } from "./types.js";
|
|
3
|
+
import { BaseIndex, PrimaryIndex } from "./indexes.js";
|
|
4
|
+
/**
|
|
5
|
+
* Configuration interface for model fields.
|
|
6
|
+
* @template T - The field type.
|
|
7
|
+
*/
|
|
8
|
+
export interface FieldConfig<T> {
|
|
9
|
+
/** The type wrapper that defines how this field is serialized/validated. */
|
|
10
|
+
type: TypeWrapper<T>;
|
|
11
|
+
/** Optional human-readable description of the field. */
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Optional default value or function that generates default values. */
|
|
14
|
+
default?: T | ((model: Record<string, any>) => T);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a field definition for a model property.
|
|
18
|
+
*
|
|
19
|
+
* This function uses TypeScript magic to return the field configuration object
|
|
20
|
+
* while appearing to return the actual field value type to the type system.
|
|
21
|
+
* This allows for both runtime introspection and compile-time type safety.
|
|
22
|
+
*
|
|
23
|
+
* @template T - The field type.
|
|
24
|
+
* @param type - The type wrapper for this field.
|
|
25
|
+
* @param options - Additional field configuration options.
|
|
26
|
+
* @returns The field value (typed as T, but actually returns FieldConfig<T>).
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* class User extends E.Model<User> {
|
|
31
|
+
* name = E.field(E.string, {description: "User's full name"});
|
|
32
|
+
* age = E.field(E.opt(E.number), {description: "User's age", default: 25});
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function field<T>(type: TypeWrapper<T>, options?: Partial<FieldConfig<T>>): T;
|
|
37
|
+
export declare const modelRegistry: Record<string, typeof Model>;
|
|
38
|
+
export declare function resetModelCaches(): void;
|
|
39
|
+
type OnSaveType = (model: InstanceType<typeof Model>, newKey: Uint8Array | undefined, oldKey: Uint8Array | undefined) => void;
|
|
40
|
+
/**
|
|
41
|
+
* Set a callback function to be called after a model is saved and committed.
|
|
42
|
+
*
|
|
43
|
+
* @param callback The callback function to set. As arguments, it receives the model instance, the new key (undefined in case of a delete), and the old key (undefined in case of a create).
|
|
44
|
+
*/
|
|
45
|
+
export declare function setOnSaveCallback(callback: OnSaveType | undefined): void;
|
|
46
|
+
/**
|
|
47
|
+
* Register a model class with the Edinburgh ORM system.
|
|
48
|
+
*
|
|
49
|
+
* This decorator function transforms the model class to use a proxy-based constructor
|
|
50
|
+
* that enables change tracking and automatic field initialization. It also extracts
|
|
51
|
+
* field metadata and sets up default values on the prototype.
|
|
52
|
+
*
|
|
53
|
+
* @template T - The model class type.
|
|
54
|
+
* @param MyModel - The model class to register.
|
|
55
|
+
* @returns The enhanced model class with ORM capabilities.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* @E.registerModel
|
|
60
|
+
* class User extends E.Model<User> {
|
|
61
|
+
* static pk = E.index(User, ["id"], "primary");
|
|
62
|
+
* id = E.field(E.identifier);
|
|
63
|
+
* name = E.field(E.string);
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function registerModel<T extends typeof Model<unknown>>(MyModel: T): T;
|
|
68
|
+
export declare function getMockModel<T extends typeof Model<unknown>>(OrgModel: T): T;
|
|
69
|
+
/** @internal Symbol used to attach modified instances to running transaction */
|
|
70
|
+
export declare const MODIFIED_INSTANCES_SYMBOL: unique symbol;
|
|
71
|
+
/** @internal Symbol used to access the underlying model from a proxy */
|
|
72
|
+
/**
|
|
73
|
+
* Model interface that ensures proper typing for the constructor property.
|
|
74
|
+
* @template SUB - The concrete model subclass.
|
|
75
|
+
*/
|
|
76
|
+
export interface Model<SUB> {
|
|
77
|
+
constructor: typeof Model<SUB>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Base class for all database models in the Edinburgh ORM.
|
|
81
|
+
*
|
|
82
|
+
* Models represent database entities with typed fields, automatic serialization,
|
|
83
|
+
* change tracking, and relationship management. All model classes should extend
|
|
84
|
+
* this base class and be decorated with `@registerModel`.
|
|
85
|
+
*
|
|
86
|
+
* @template SUB - The concrete model subclass (for proper typing).
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* @E.registerModel
|
|
91
|
+
* class User extends E.Model<User> {
|
|
92
|
+
* static pk = E.index(User, ["id"], "primary");
|
|
93
|
+
*
|
|
94
|
+
* id = E.field(E.identifier);
|
|
95
|
+
* name = E.field(E.string);
|
|
96
|
+
* email = E.field(E.string);
|
|
97
|
+
*
|
|
98
|
+
* static byEmail = E.index(User, "email", "unique");
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare abstract class Model<SUB> {
|
|
103
|
+
/** @internal Primary key index for this model. */
|
|
104
|
+
static _pk?: PrimaryIndex<any, any>;
|
|
105
|
+
/** @internal All indexes for this model, the primary key being first. */
|
|
106
|
+
static _indexes?: BaseIndex<any, any>[];
|
|
107
|
+
/** The database table name (defaults to class name). */
|
|
108
|
+
static tableName: string;
|
|
109
|
+
/** Field configuration metadata. */
|
|
110
|
+
static fields: Record<string, FieldConfig<unknown>>;
|
|
111
|
+
/** @internal Field configuration for this instance. */
|
|
112
|
+
_fields: Record<string, FieldConfig<unknown>>;
|
|
113
|
+
/**
|
|
114
|
+
* @internal State tracking for this model instance:
|
|
115
|
+
* - undefined: new instance, unmodified
|
|
116
|
+
* - 1: new instance, modified (and in modifiedInstances)
|
|
117
|
+
* - 2: loaded from disk, unmodified
|
|
118
|
+
* - 3: persistence disabled
|
|
119
|
+
* - array: loaded from disk, modified (and in modifiedInstances), array values are original index buffers
|
|
120
|
+
*/
|
|
121
|
+
_state: undefined | 1 | 2 | 3 | Array<Uint8Array>;
|
|
122
|
+
constructor(initial?: Partial<Omit<SUB, "constructor">>);
|
|
123
|
+
_save(): void;
|
|
124
|
+
/**
|
|
125
|
+
* Load a model instance by primary key.
|
|
126
|
+
* @param args - Primary key field values.
|
|
127
|
+
* @returns The model instance if found, undefined otherwise.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```typescript
|
|
131
|
+
* const user = User.load("user123");
|
|
132
|
+
* const post = Post.load("post456", "en");
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
static load<SUB>(this: typeof Model<SUB>, ...args: any[]): SUB | undefined;
|
|
136
|
+
/**
|
|
137
|
+
* Prevent this instance from being persisted to the database.
|
|
138
|
+
*
|
|
139
|
+
* Removes the instance from the modified instances set and disables
|
|
140
|
+
* automatic persistence at transaction commit.
|
|
141
|
+
*
|
|
142
|
+
* @returns This model instance for chaining.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const user = User.load("user123");
|
|
147
|
+
* user.name = "New Name";
|
|
148
|
+
* user.preventPersist(); // Changes won't be saved
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
preventPersist(): this;
|
|
152
|
+
/**
|
|
153
|
+
* Delete this model instance from the database.
|
|
154
|
+
*
|
|
155
|
+
* Removes the instance and all its index entries from the database and prevents further persistence.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* const user = User.load("user123");
|
|
160
|
+
* user.delete(); // Removes from database
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
delete(): void;
|
|
164
|
+
/**
|
|
165
|
+
* Validate all fields in this model instance.
|
|
166
|
+
* @param raise - If true, throw on first validation error.
|
|
167
|
+
* @returns Array of validation errors (empty if valid).
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* const user = new User();
|
|
172
|
+
* const errors = user.validate();
|
|
173
|
+
* if (errors.length > 0) {
|
|
174
|
+
* console.log("Validation failed:", errors);
|
|
175
|
+
* }
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
validate(raise?: boolean): DatabaseError[];
|
|
179
|
+
/**
|
|
180
|
+
* Check if this model instance is valid.
|
|
181
|
+
* @returns true if all validations pass.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const user = new User({name: "John"});
|
|
186
|
+
* if (!user.isValid()) shoutAtTheUser();
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
isValid(): boolean;
|
|
190
|
+
}
|
|
191
|
+
export declare const modificationTracker: ProxyHandler<any>;
|
|
192
|
+
export {};
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { DatabaseError } from "olmdb";
|
|
2
|
+
import * as olmdb from "olmdb";
|
|
3
|
+
import { TypeWrapper, identifier } from "./types.js";
|
|
4
|
+
import { TARGET_SYMBOL, PrimaryIndex } from "./indexes.js";
|
|
5
|
+
import { assert, addErrorPath, logLevel } from "./utils.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create a field definition for a model property.
|
|
8
|
+
*
|
|
9
|
+
* This function uses TypeScript magic to return the field configuration object
|
|
10
|
+
* while appearing to return the actual field value type to the type system.
|
|
11
|
+
* This allows for both runtime introspection and compile-time type safety.
|
|
12
|
+
*
|
|
13
|
+
* @template T - The field type.
|
|
14
|
+
* @param type - The type wrapper for this field.
|
|
15
|
+
* @param options - Additional field configuration options.
|
|
16
|
+
* @returns The field value (typed as T, but actually returns FieldConfig<T>).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* class User extends E.Model<User> {
|
|
21
|
+
* name = E.field(E.string, {description: "User's full name"});
|
|
22
|
+
* age = E.field(E.opt(E.number), {description: "User's age", default: 25});
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function field(type, options = {}) {
|
|
27
|
+
// Return the config object, but TypeScript sees it as type T
|
|
28
|
+
options.type = type;
|
|
29
|
+
return options;
|
|
30
|
+
}
|
|
31
|
+
// Model registration and initialization
|
|
32
|
+
let uninitializedModels = new Set();
|
|
33
|
+
export const modelRegistry = {};
|
|
34
|
+
export function resetModelCaches() {
|
|
35
|
+
for (const model of Object.values(modelRegistry)) {
|
|
36
|
+
for (const index of model._indexes || []) {
|
|
37
|
+
index._cachedIndexId = undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function isObjectEmpty(obj) {
|
|
42
|
+
for (let key in obj) {
|
|
43
|
+
if (obj.hasOwnProperty(key))
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
let onSave;
|
|
49
|
+
/**
|
|
50
|
+
* Set a callback function to be called after a model is saved and committed.
|
|
51
|
+
*
|
|
52
|
+
* @param callback The callback function to set. As arguments, it receives the model instance, the new key (undefined in case of a delete), and the old key (undefined in case of a create).
|
|
53
|
+
*/
|
|
54
|
+
export function setOnSaveCallback(callback) {
|
|
55
|
+
onSave = callback;
|
|
56
|
+
}
|
|
57
|
+
const onSaveQueue = [];
|
|
58
|
+
function onSaveRevert() {
|
|
59
|
+
onSaveQueue.length = 0;
|
|
60
|
+
}
|
|
61
|
+
function onSaveCommit() {
|
|
62
|
+
if (onSave) {
|
|
63
|
+
for (let arr of onSaveQueue) {
|
|
64
|
+
onSave(...arr);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
onSaveQueue.length = 0;
|
|
68
|
+
}
|
|
69
|
+
function queueOnSave(arr) {
|
|
70
|
+
if (onSave) {
|
|
71
|
+
if (!onSaveQueue.length) {
|
|
72
|
+
olmdb.onCommit(onSaveCommit);
|
|
73
|
+
olmdb.onRevert(onSaveRevert);
|
|
74
|
+
}
|
|
75
|
+
onSaveQueue.push(arr);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Register a model class with the Edinburgh ORM system.
|
|
80
|
+
*
|
|
81
|
+
* This decorator function transforms the model class to use a proxy-based constructor
|
|
82
|
+
* that enables change tracking and automatic field initialization. It also extracts
|
|
83
|
+
* field metadata and sets up default values on the prototype.
|
|
84
|
+
*
|
|
85
|
+
* @template T - The model class type.
|
|
86
|
+
* @param MyModel - The model class to register.
|
|
87
|
+
* @returns The enhanced model class with ORM capabilities.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* @E.registerModel
|
|
92
|
+
* class User extends E.Model<User> {
|
|
93
|
+
* static pk = E.index(User, ["id"], "primary");
|
|
94
|
+
* id = E.field(E.identifier);
|
|
95
|
+
* name = E.field(E.string);
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export function registerModel(MyModel) {
|
|
100
|
+
const MockModel = getMockModel(MyModel);
|
|
101
|
+
// Copy own static methods/properties
|
|
102
|
+
for (const name of Object.getOwnPropertyNames(MyModel)) {
|
|
103
|
+
if (name !== 'length' && name !== 'prototype' && name !== 'name' && name !== 'mock') {
|
|
104
|
+
MockModel[name] = MyModel[name];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Initialize an empty `fields` object, and set it on both constructors, as well as on the prototype.
|
|
108
|
+
MockModel.fields = MockModel.prototype._fields = {};
|
|
109
|
+
MockModel.tableName ||= MyModel.name; // Set the table name to the class name if not already set
|
|
110
|
+
// Register the constructor by name
|
|
111
|
+
if (MockModel.tableName in modelRegistry)
|
|
112
|
+
throw new DatabaseError(`Model with table name '${MockModel.tableName}' already registered`, 'INIT_ERROR');
|
|
113
|
+
modelRegistry[MockModel.tableName] = MockModel;
|
|
114
|
+
// Attempt to instantiate the class and gather field metadata
|
|
115
|
+
uninitializedModels.add(MyModel);
|
|
116
|
+
initModels();
|
|
117
|
+
return MockModel;
|
|
118
|
+
}
|
|
119
|
+
export function getMockModel(OrgModel) {
|
|
120
|
+
const AnyOrgModel = OrgModel;
|
|
121
|
+
if (AnyOrgModel._isMock)
|
|
122
|
+
return OrgModel;
|
|
123
|
+
if (AnyOrgModel._mock)
|
|
124
|
+
return AnyOrgModel._mock;
|
|
125
|
+
const MockModel = function (initial) {
|
|
126
|
+
if (uninitializedModels.has(this.constructor)) {
|
|
127
|
+
throw new DatabaseError("Cannot instantiate while linked models haven't been registered yet", 'INIT_ERROR');
|
|
128
|
+
}
|
|
129
|
+
if (initial && !isObjectEmpty(initial)) {
|
|
130
|
+
Object.assign(this, initial);
|
|
131
|
+
const modifiedInstances = olmdb.getTransactionData(MODIFIED_INSTANCES_SYMBOL);
|
|
132
|
+
modifiedInstances.add(this);
|
|
133
|
+
}
|
|
134
|
+
return new Proxy(this, modificationTracker);
|
|
135
|
+
};
|
|
136
|
+
// We want .constructor to point at our fake constructor function.
|
|
137
|
+
OrgModel.prototype.constructor = MockModel;
|
|
138
|
+
// Copy the prototype chain for the constructor as well as for instantiated objects
|
|
139
|
+
Object.setPrototypeOf(MockModel, Object.getPrototypeOf(OrgModel));
|
|
140
|
+
MockModel.prototype = OrgModel.prototype;
|
|
141
|
+
MockModel._isMock = true;
|
|
142
|
+
AnyOrgModel._mock = MockModel;
|
|
143
|
+
return MockModel;
|
|
144
|
+
}
|
|
145
|
+
function initModels() {
|
|
146
|
+
for (const OrgModel of uninitializedModels) {
|
|
147
|
+
const MockModel = getMockModel(OrgModel);
|
|
148
|
+
// Create an instance (the only one to ever exist) of the actual class,
|
|
149
|
+
// in order to gather field config data.
|
|
150
|
+
let instance;
|
|
151
|
+
try {
|
|
152
|
+
instance = new OrgModel(INIT_INSTANCE_SYMBOL);
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
if (!(e instanceof ReferenceError))
|
|
156
|
+
throw e;
|
|
157
|
+
// ReferenceError: Cannot access 'SomeLinkedClass' before initialization.
|
|
158
|
+
// We'll try again after the next class has successfully initialized.
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
uninitializedModels.delete(OrgModel);
|
|
162
|
+
// If no primary key exists, create one using 'id' field
|
|
163
|
+
if (!MockModel._pk) {
|
|
164
|
+
// If no `id` field exists, add it automatically
|
|
165
|
+
if (!instance.id) {
|
|
166
|
+
instance.id = { type: identifier };
|
|
167
|
+
}
|
|
168
|
+
// @ts-ignore-next-line - `id` is not part of the type, but the user probably shouldn't touch it anyhow
|
|
169
|
+
new PrimaryIndex(MockModel, ['id']);
|
|
170
|
+
}
|
|
171
|
+
for (const key in instance) {
|
|
172
|
+
const value = instance[key];
|
|
173
|
+
// Check if this property contains field metadata
|
|
174
|
+
if (value && value.type instanceof TypeWrapper) {
|
|
175
|
+
// Set the configuration on the constructor's `fields` property
|
|
176
|
+
MockModel.fields[key] = value;
|
|
177
|
+
// Set default value on the prototype
|
|
178
|
+
const defObj = value.default === undefined ? value.type : value;
|
|
179
|
+
const def = defObj.default;
|
|
180
|
+
if (typeof def === 'function') {
|
|
181
|
+
// The default is a function. We'll define a getter on the property in the model prototype,
|
|
182
|
+
// and once it is read, we'll run the function and set the value as a plain old property
|
|
183
|
+
// on the instance object.
|
|
184
|
+
Object.defineProperty(MockModel.prototype, key, {
|
|
185
|
+
get() {
|
|
186
|
+
// This will call set(), which will define the property on the instance.
|
|
187
|
+
return (this[key] = def.call(defObj, this));
|
|
188
|
+
},
|
|
189
|
+
set(val) {
|
|
190
|
+
Object.defineProperty(this, key, {
|
|
191
|
+
value: val,
|
|
192
|
+
configurable: true,
|
|
193
|
+
writable: true
|
|
194
|
+
});
|
|
195
|
+
},
|
|
196
|
+
configurable: true,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
else if (def !== undefined) {
|
|
200
|
+
MockModel.prototype[key] = def;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (logLevel >= 1) {
|
|
205
|
+
console.log(`Registered model ${MockModel.tableName}[${MockModel._pk._fieldNames.join(',')}] with fields: ${Object.keys(MockModel.fields).join(' ')}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Model base class and related symbols/state
|
|
210
|
+
const INIT_INSTANCE_SYMBOL = Symbol();
|
|
211
|
+
/** @internal Symbol used to attach modified instances to running transaction */
|
|
212
|
+
export const MODIFIED_INSTANCES_SYMBOL = Symbol('modifiedInstances');
|
|
213
|
+
/**
|
|
214
|
+
* Base class for all database models in the Edinburgh ORM.
|
|
215
|
+
*
|
|
216
|
+
* Models represent database entities with typed fields, automatic serialization,
|
|
217
|
+
* change tracking, and relationship management. All model classes should extend
|
|
218
|
+
* this base class and be decorated with `@registerModel`.
|
|
219
|
+
*
|
|
220
|
+
* @template SUB - The concrete model subclass (for proper typing).
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* @E.registerModel
|
|
225
|
+
* class User extends E.Model<User> {
|
|
226
|
+
* static pk = E.index(User, ["id"], "primary");
|
|
227
|
+
*
|
|
228
|
+
* id = E.field(E.identifier);
|
|
229
|
+
* name = E.field(E.string);
|
|
230
|
+
* email = E.field(E.string);
|
|
231
|
+
*
|
|
232
|
+
* static byEmail = E.index(User, "email", "unique");
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export class Model {
|
|
237
|
+
/** @internal Primary key index for this model. */
|
|
238
|
+
static _pk;
|
|
239
|
+
/** @internal All indexes for this model, the primary key being first. */
|
|
240
|
+
static _indexes;
|
|
241
|
+
/** The database table name (defaults to class name). */
|
|
242
|
+
static tableName;
|
|
243
|
+
/** Field configuration metadata. */
|
|
244
|
+
static fields;
|
|
245
|
+
/*
|
|
246
|
+
* IMPORTANT: We cannot use instance property initializers here, because we will be
|
|
247
|
+
* initializing the class through a fake constructor that will skip these. This is
|
|
248
|
+
* intentional, as we don't want to run the initializers for the fields.
|
|
249
|
+
*/
|
|
250
|
+
/** @internal Field configuration for this instance. */
|
|
251
|
+
_fields;
|
|
252
|
+
/**
|
|
253
|
+
* @internal State tracking for this model instance:
|
|
254
|
+
* - undefined: new instance, unmodified
|
|
255
|
+
* - 1: new instance, modified (and in modifiedInstances)
|
|
256
|
+
* - 2: loaded from disk, unmodified
|
|
257
|
+
* - 3: persistence disabled
|
|
258
|
+
* - array: loaded from disk, modified (and in modifiedInstances), array values are original index buffers
|
|
259
|
+
*/
|
|
260
|
+
_state;
|
|
261
|
+
constructor(initial = {}) {
|
|
262
|
+
// This constructor will only be called once, from `initModels`. All other instances will
|
|
263
|
+
// be created by the 'fake' constructor. The typing for `initial` *is* important though.
|
|
264
|
+
if (initial !== INIT_INSTANCE_SYMBOL) {
|
|
265
|
+
throw new DatabaseError("The model needs a @registerModel decorator", 'INIT_ERROR');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
_save() {
|
|
269
|
+
// For performance, we'll work on the unproxied object, as we know we don't require change tracking for save.
|
|
270
|
+
const unproxiedModel = (this[TARGET_SYMBOL] || this);
|
|
271
|
+
unproxiedModel.validate(true);
|
|
272
|
+
// Handle unique indexes
|
|
273
|
+
const indexes = this.constructor._indexes;
|
|
274
|
+
const originalKeys = typeof unproxiedModel._state === 'object' ? unproxiedModel._state : undefined;
|
|
275
|
+
const newPk = indexes[0]._save(unproxiedModel, originalKeys?.[0]);
|
|
276
|
+
for (let i = 1; i < indexes.length; i++) {
|
|
277
|
+
indexes[i]._save(unproxiedModel, originalKeys?.[i]);
|
|
278
|
+
}
|
|
279
|
+
queueOnSave([this, newPk, originalKeys?.[0]]);
|
|
280
|
+
unproxiedModel._state = 2; // Loaded from disk, unmodified
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Load a model instance by primary key.
|
|
284
|
+
* @param args - Primary key field values.
|
|
285
|
+
* @returns The model instance if found, undefined otherwise.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* const user = User.load("user123");
|
|
290
|
+
* const post = Post.load("post456", "en");
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
static load(...args) {
|
|
294
|
+
return this._pk.get(...args);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Prevent this instance from being persisted to the database.
|
|
298
|
+
*
|
|
299
|
+
* Removes the instance from the modified instances set and disables
|
|
300
|
+
* automatic persistence at transaction commit.
|
|
301
|
+
*
|
|
302
|
+
* @returns This model instance for chaining.
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```typescript
|
|
306
|
+
* const user = User.load("user123");
|
|
307
|
+
* user.name = "New Name";
|
|
308
|
+
* user.preventPersist(); // Changes won't be saved
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
preventPersist() {
|
|
312
|
+
const modifiedInstances = olmdb.getTransactionData(MODIFIED_INSTANCES_SYMBOL);
|
|
313
|
+
const unproxiedModel = this[TARGET_SYMBOL] || this;
|
|
314
|
+
modifiedInstances.delete(unproxiedModel);
|
|
315
|
+
unproxiedModel._state = 3; // no persist
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Delete this model instance from the database.
|
|
320
|
+
*
|
|
321
|
+
* Removes the instance and all its index entries from the database and prevents further persistence.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```typescript
|
|
325
|
+
* const user = User.load("user123");
|
|
326
|
+
* user.delete(); // Removes from database
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
329
|
+
delete() {
|
|
330
|
+
const unproxiedModel = (this[TARGET_SYMBOL] || this);
|
|
331
|
+
if (this._state === 2 || typeof this._state === 'object') {
|
|
332
|
+
for (const index of unproxiedModel.constructor._indexes) {
|
|
333
|
+
const key = index._getKeyFromModel(unproxiedModel, true);
|
|
334
|
+
olmdb.del(key);
|
|
335
|
+
if (index instanceof PrimaryIndex)
|
|
336
|
+
queueOnSave([this, undefined, key]);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
this.preventPersist();
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Validate all fields in this model instance.
|
|
343
|
+
* @param raise - If true, throw on first validation error.
|
|
344
|
+
* @returns Array of validation errors (empty if valid).
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```typescript
|
|
348
|
+
* const user = new User();
|
|
349
|
+
* const errors = user.validate();
|
|
350
|
+
* if (errors.length > 0) {
|
|
351
|
+
* console.log("Validation failed:", errors);
|
|
352
|
+
* }
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
validate(raise = false) {
|
|
356
|
+
const errors = [];
|
|
357
|
+
for (const [key, fieldConfig] of Object.entries(this._fields)) {
|
|
358
|
+
for (const error of fieldConfig.type.getErrors(this, key)) {
|
|
359
|
+
addErrorPath(error, key);
|
|
360
|
+
if (raise)
|
|
361
|
+
throw error;
|
|
362
|
+
errors.push(error);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return errors;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Check if this model instance is valid.
|
|
369
|
+
* @returns true if all validations pass.
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```typescript
|
|
373
|
+
* const user = new User({name: "John"});
|
|
374
|
+
* if (!user.isValid()) shoutAtTheUser();
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
isValid() {
|
|
378
|
+
return this.validate().length === 0;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
// We use recursive proxies to track modifications made to, say, arrays within models. In
|
|
382
|
+
// order to know which model a nested object belongs to, we maintain a WeakMap that maps
|
|
383
|
+
// objects to their owner (unproxied) model.
|
|
384
|
+
const modificationOwnerMap = new WeakMap();
|
|
385
|
+
// A cache for the proxies around nested objects, so that we don't need to recreate them
|
|
386
|
+
// every time we access a property on a nested object (and so that their identity remains
|
|
387
|
+
// the same).
|
|
388
|
+
const modificationProxyCache = new WeakMap();
|
|
389
|
+
// Single proxy handler for both models and nested objects
|
|
390
|
+
export const modificationTracker = {
|
|
391
|
+
get(target, prop) {
|
|
392
|
+
if (prop === TARGET_SYMBOL)
|
|
393
|
+
return target;
|
|
394
|
+
const value = target[prop];
|
|
395
|
+
if (!value || typeof value !== 'object' || (value instanceof Model))
|
|
396
|
+
return value;
|
|
397
|
+
// Check cache first
|
|
398
|
+
let proxy = modificationProxyCache.get(value);
|
|
399
|
+
if (proxy)
|
|
400
|
+
return proxy;
|
|
401
|
+
let model;
|
|
402
|
+
if (target instanceof Model) {
|
|
403
|
+
if (!target._fields[prop]) {
|
|
404
|
+
// No need to track properties that are not model fields.
|
|
405
|
+
return value;
|
|
406
|
+
}
|
|
407
|
+
model = target;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
model = modificationOwnerMap.get(target);
|
|
411
|
+
assert(model);
|
|
412
|
+
}
|
|
413
|
+
let state = model._state;
|
|
414
|
+
if (state !== undefined && state !== 2) {
|
|
415
|
+
// We don't need to track changes for this model (anymore). So we can just return the unproxied object.
|
|
416
|
+
// As we doing the modificationProxyCache lookup first, the identity of returned objects will not change:
|
|
417
|
+
// once a proxied object is returned, the same property will always return a proxied object.
|
|
418
|
+
return value;
|
|
419
|
+
}
|
|
420
|
+
if (modificationOwnerMap.get(value)) {
|
|
421
|
+
throw new DatabaseError("Object cannot be embedded in multiple model instances", 'VALUE_ERROR');
|
|
422
|
+
}
|
|
423
|
+
modificationOwnerMap.set(value, model);
|
|
424
|
+
proxy = new Proxy(value, modificationTracker);
|
|
425
|
+
modificationProxyCache.set(value, proxy);
|
|
426
|
+
return proxy;
|
|
427
|
+
},
|
|
428
|
+
set(target, prop, value) {
|
|
429
|
+
let model;
|
|
430
|
+
if (target instanceof Model) {
|
|
431
|
+
model = target;
|
|
432
|
+
if (!model._fields[prop]) {
|
|
433
|
+
// No need to track properties that are not model fields.
|
|
434
|
+
target[prop] = value;
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
model = modificationOwnerMap.get(target);
|
|
440
|
+
assert(model);
|
|
441
|
+
}
|
|
442
|
+
let state = model._state;
|
|
443
|
+
if (state === undefined || state === 2) {
|
|
444
|
+
const modifiedInstances = olmdb.getTransactionData(MODIFIED_INSTANCES_SYMBOL);
|
|
445
|
+
modifiedInstances.add(model);
|
|
446
|
+
if (state === 2) {
|
|
447
|
+
model._state = model.constructor._indexes.map(idx => idx._getKeyFromModel(model, true));
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
model._state = 1;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
target[prop] = value;
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
//# sourceMappingURL=models.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/models.ts"],"names":[],"mappings":"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"}
|