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
package/README.md
ADDED
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
# Edinburgh
|
|
2
|
+
**Very fast object persistence for TypeScript, supporting optimistic transactions, on-demand reference loading, automatic back-references and indexes.**
|
|
3
|
+
|
|
4
|
+
Edinburgh is a high-performance ORM built on [OLMDB](https://github.com/vanviegen/olmdb), providing type-safe model definitions with automatic field validation, ACID transactions, and efficient LMDB-based storage.
|
|
5
|
+
|
|
6
|
+
**Features:**
|
|
7
|
+
|
|
8
|
+
- 馃殌 **Type-Safe Models**: Define models with automatic TypeScript type inference and runtime validation
|
|
9
|
+
- 馃敀 **ACID Transactions**: Optimistic locking with automatic retry on conflicts
|
|
10
|
+
- 馃敆 **Relationship Management**: Automatic back-references and link handling between models
|
|
11
|
+
- 馃搳 **Custom Indexing**: Efficient querying with primary, unique, and multi-value indexes
|
|
12
|
+
- 馃摝 **Zero Dependencies**: Minimal footprint, built on LMDB for maximum performance
|
|
13
|
+
|
|
14
|
+
## Quick Demo
|
|
15
|
+
```typescript
|
|
16
|
+
import * as E from "edinburgh";
|
|
17
|
+
|
|
18
|
+
// Initialize the database (optional, defaults to "./.olmdb")
|
|
19
|
+
E.init("./my-database");
|
|
20
|
+
|
|
21
|
+
// Define a model
|
|
22
|
+
@E.registerModel
|
|
23
|
+
class User extends E.Model<User> {
|
|
24
|
+
// Define a primary key (optional, defaults to using the "id" field)
|
|
25
|
+
static pk = E.index(User, ["id"], "primary");
|
|
26
|
+
// Define a unique index on the email field
|
|
27
|
+
static byEmail = E.index(User, "email", "unique");
|
|
28
|
+
|
|
29
|
+
// Define fields with simple types -- they will be type-checked at compile time and validated at runtime.
|
|
30
|
+
id = E.field(E.identifier);
|
|
31
|
+
name = E.field(E.string);
|
|
32
|
+
email = E.field(E.string);
|
|
33
|
+
age = E.field(E.opt(E.number));
|
|
34
|
+
|
|
35
|
+
// A field with a more elaborate type. In Typescript: `User | User[] | "self" | "spouse"`
|
|
36
|
+
supervisor = E.field(E.choice(E.link(User), E.array(E.link(User)), E.literal("self"), E.literal("spouse")));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Use in transactions
|
|
40
|
+
await E.transact(() => {
|
|
41
|
+
const user = new User({
|
|
42
|
+
name: "John Doe",
|
|
43
|
+
email: "john@example.com"
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await E.transact(() => {
|
|
48
|
+
// Query by unique index
|
|
49
|
+
const user = User.byEmail.get("john@example.com")!;
|
|
50
|
+
// The transaction will retry if there's a conflict, such as another transaction
|
|
51
|
+
// modifying the same user (from another async function or another process)
|
|
52
|
+
user.age++;
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API Reference
|
|
57
|
+
|
|
58
|
+
The following is auto-generated from `src/edinburgh.ts`:
|
|
59
|
+
|
|
60
|
+
### transact 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L83)
|
|
61
|
+
|
|
62
|
+
Executes a function within a database transaction context.
|
|
63
|
+
|
|
64
|
+
Loading models (also through links in other models) and changing models can only be done from
|
|
65
|
+
within a transaction.
|
|
66
|
+
|
|
67
|
+
Transactions have a consistent view of the database, and changes made within a transaction are
|
|
68
|
+
isolated from other transactions until they are committed. In case a commit clashes with changes
|
|
69
|
+
made by another transaction, the transaction function will automatically be re-executed up to 10
|
|
70
|
+
times.
|
|
71
|
+
|
|
72
|
+
**Signature:** `<T>(fn: () => T) => Promise<T>`
|
|
73
|
+
|
|
74
|
+
**Type Parameters:**
|
|
75
|
+
|
|
76
|
+
- `T` - The return type of the transaction function.
|
|
77
|
+
|
|
78
|
+
**Parameters:**
|
|
79
|
+
|
|
80
|
+
- `fn: () => T` - - The function to execute within the transaction context.
|
|
81
|
+
|
|
82
|
+
**Returns:** A promise that resolves with the function's return value.
|
|
83
|
+
|
|
84
|
+
**Throws:**
|
|
85
|
+
|
|
86
|
+
- If nested transactions are attempted.
|
|
87
|
+
- With code "RACING_TRANSACTION" if the transaction fails after retries due to conflicts.
|
|
88
|
+
- With code "TRANSACTION_FAILED" if the transaction fails for other reasons.
|
|
89
|
+
- With code "TXN_LIMIT" if maximum number of transactions is reached.
|
|
90
|
+
- With code "LMDB-{code}" for LMDB-specific errors.
|
|
91
|
+
|
|
92
|
+
**Examples:**
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const paid = await E.transact(() => {
|
|
96
|
+
const user = User.load("john_doe");
|
|
97
|
+
// This is concurrency-safe - the function will rerun if it is raced by another transaction
|
|
98
|
+
if (user.credits > 0) {
|
|
99
|
+
user.credits--;
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
```typescript
|
|
106
|
+
// Transaction with automatic retry on conflicts
|
|
107
|
+
await E.transact(() => {
|
|
108
|
+
const counter = Counter.load("global") || new Counter({id: "global", value: 0});
|
|
109
|
+
counter.value++;
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### deleteEverything 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L112)
|
|
114
|
+
|
|
115
|
+
**Signature:** `() => Promise<void>`
|
|
116
|
+
|
|
117
|
+
### Model 路 [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
118
|
+
|
|
119
|
+
Base class for all database models in the Edinburgh ORM.
|
|
120
|
+
|
|
121
|
+
Models represent database entities with typed fields, automatic serialization,
|
|
122
|
+
change tracking, and relationship management. All model classes should extend
|
|
123
|
+
this base class and be decorated with `@registerModel`.
|
|
124
|
+
|
|
125
|
+
**Type Parameters:**
|
|
126
|
+
|
|
127
|
+
- `SUB` - The concrete model subclass (for proper typing).
|
|
128
|
+
|
|
129
|
+
**Examples:**
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
鈦E.registerModel
|
|
133
|
+
class User extends E.Model<User> {
|
|
134
|
+
static pk = E.index(User, ["id"], "primary");
|
|
135
|
+
|
|
136
|
+
id = E.field(E.identifier);
|
|
137
|
+
name = E.field(E.string);
|
|
138
|
+
email = E.field(E.string);
|
|
139
|
+
|
|
140
|
+
static byEmail = E.index(User, "email", "unique");
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Model.tableName 路 [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
145
|
+
|
|
146
|
+
The database table name (defaults to class name).
|
|
147
|
+
|
|
148
|
+
**Type:** `string`
|
|
149
|
+
|
|
150
|
+
#### Model.fields 路 [static property](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
151
|
+
|
|
152
|
+
Field configuration metadata.
|
|
153
|
+
|
|
154
|
+
**Type:** `Record<string, FieldConfig<unknown>>`
|
|
155
|
+
|
|
156
|
+
#### Model.load 路 [static method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
157
|
+
|
|
158
|
+
Load a model instance by primary key.
|
|
159
|
+
|
|
160
|
+
**Signature:** `<SUB>(this: typeof Model<SUB>, ...args: any[]) => SUB`
|
|
161
|
+
|
|
162
|
+
**Parameters:**
|
|
163
|
+
|
|
164
|
+
- `this: typeof Model<SUB>`
|
|
165
|
+
- `args: any[]` - - Primary key field values.
|
|
166
|
+
|
|
167
|
+
**Returns:** The model instance if found, undefined otherwise.
|
|
168
|
+
|
|
169
|
+
**Examples:**
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
const user = User.load("user123");
|
|
173
|
+
const post = Post.load("post456", "en");
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### model.preventPersist 路 [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
177
|
+
|
|
178
|
+
Prevent this instance from being persisted to the database.
|
|
179
|
+
|
|
180
|
+
Removes the instance from the modified instances set and disables
|
|
181
|
+
automatic persistence at transaction commit.
|
|
182
|
+
|
|
183
|
+
**Signature:** `() => this`
|
|
184
|
+
|
|
185
|
+
**Parameters:**
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
**Returns:** This model instance for chaining.
|
|
189
|
+
|
|
190
|
+
**Examples:**
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const user = User.load("user123");
|
|
194
|
+
user.name = "New Name";
|
|
195
|
+
user.preventPersist(); // Changes won't be saved
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### model.delete 路 [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
199
|
+
|
|
200
|
+
Delete this model instance from the database.
|
|
201
|
+
|
|
202
|
+
Removes the instance and all its index entries from the database and prevents further persistence.
|
|
203
|
+
|
|
204
|
+
**Signature:** `() => void`
|
|
205
|
+
|
|
206
|
+
**Parameters:**
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
**Examples:**
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const user = User.load("user123");
|
|
213
|
+
user.delete(); // Removes from database
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### model.validate 路 [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
217
|
+
|
|
218
|
+
Validate all fields in this model instance.
|
|
219
|
+
|
|
220
|
+
**Signature:** `(raise?: boolean) => DatabaseError[]`
|
|
221
|
+
|
|
222
|
+
**Parameters:**
|
|
223
|
+
|
|
224
|
+
- `raise: boolean` (optional) - - If true, throw on first validation error.
|
|
225
|
+
|
|
226
|
+
**Returns:** Array of validation errors (empty if valid).
|
|
227
|
+
|
|
228
|
+
**Examples:**
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const user = new User();
|
|
232
|
+
const errors = user.validate();
|
|
233
|
+
if (errors.length > 0) {
|
|
234
|
+
console.log("Validation failed:", errors);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### model.isValid 路 [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
239
|
+
|
|
240
|
+
Check if this model instance is valid.
|
|
241
|
+
|
|
242
|
+
**Signature:** `() => boolean`
|
|
243
|
+
|
|
244
|
+
**Parameters:**
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
**Returns:** true if all validations pass.
|
|
248
|
+
|
|
249
|
+
**Examples:**
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
const user = new User({name: "John"});
|
|
253
|
+
if (!user.isValid()) shoutAtTheUser();
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### registerModel 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
257
|
+
|
|
258
|
+
Register a model class with the Edinburgh ORM system.
|
|
259
|
+
|
|
260
|
+
This decorator function transforms the model class to use a proxy-based constructor
|
|
261
|
+
that enables change tracking and automatic field initialization. It also extracts
|
|
262
|
+
field metadata and sets up default values on the prototype.
|
|
263
|
+
|
|
264
|
+
**Signature:** `<T extends typeof Model<unknown>>(MyModel: T) => T`
|
|
265
|
+
|
|
266
|
+
**Type Parameters:**
|
|
267
|
+
|
|
268
|
+
- `T extends typeof Model<unknown>` - The model class type.
|
|
269
|
+
|
|
270
|
+
**Parameters:**
|
|
271
|
+
|
|
272
|
+
- `MyModel: T` - - The model class to register.
|
|
273
|
+
|
|
274
|
+
**Returns:** The enhanced model class with ORM capabilities.
|
|
275
|
+
|
|
276
|
+
**Examples:**
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
鈦E.registerModel
|
|
280
|
+
class User extends E.Model<User> {
|
|
281
|
+
static pk = E.index(User, ["id"], "primary");
|
|
282
|
+
id = E.field(E.identifier);
|
|
283
|
+
name = E.field(E.string);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### field 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L55)
|
|
288
|
+
|
|
289
|
+
Create a field definition for a model property.
|
|
290
|
+
|
|
291
|
+
This function uses TypeScript magic to return the field configuration object
|
|
292
|
+
while appearing to return the actual field value type to the type system.
|
|
293
|
+
This allows for both runtime introspection and compile-time type safety.
|
|
294
|
+
|
|
295
|
+
**Signature:** `<T>(type: TypeWrapper<T>, options?: Partial<FieldConfig<T>>) => T`
|
|
296
|
+
|
|
297
|
+
**Type Parameters:**
|
|
298
|
+
|
|
299
|
+
- `T` - The field type.
|
|
300
|
+
|
|
301
|
+
**Parameters:**
|
|
302
|
+
|
|
303
|
+
- `type: TypeWrapper<T>` - - The type wrapper for this field.
|
|
304
|
+
- `options: Partial<FieldConfig<T>>` (optional) - - Additional field configuration options.
|
|
305
|
+
|
|
306
|
+
**Returns:** The field value (typed as T, but actually returns FieldConfig<T>).
|
|
307
|
+
|
|
308
|
+
**Examples:**
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
class User extends E.Model<User> {
|
|
312
|
+
name = E.field(E.string, {description: "User's full name"});
|
|
313
|
+
age = E.field(E.opt(E.number), {description: "User's age", default: 25});
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### setOnSaveCallback 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L85)
|
|
318
|
+
|
|
319
|
+
Set a callback function to be called after a model is saved and committed.
|
|
320
|
+
|
|
321
|
+
**Signature:** `(callback: OnSaveType) => void`
|
|
322
|
+
|
|
323
|
+
**Parameters:**
|
|
324
|
+
|
|
325
|
+
- `callback: OnSaveType | undefined` - 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).
|
|
326
|
+
|
|
327
|
+
### string 路 [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
328
|
+
|
|
329
|
+
Constant representing the string type.
|
|
330
|
+
|
|
331
|
+
**Value:** `StringType`
|
|
332
|
+
|
|
333
|
+
### number 路 [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
334
|
+
|
|
335
|
+
Constant representing the number type.
|
|
336
|
+
|
|
337
|
+
**Value:** `NumberType`
|
|
338
|
+
|
|
339
|
+
### boolean 路 [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
340
|
+
|
|
341
|
+
Constant representing the boolean type.
|
|
342
|
+
|
|
343
|
+
**Value:** `BooleanType`
|
|
344
|
+
|
|
345
|
+
### identifier 路 [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
346
|
+
|
|
347
|
+
Constant representing the identifier type.
|
|
348
|
+
|
|
349
|
+
**Value:** `IdentifierType`
|
|
350
|
+
|
|
351
|
+
### undef 路 [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
352
|
+
|
|
353
|
+
Constant representing the 'undefined' type.
|
|
354
|
+
|
|
355
|
+
**Value:** `LiteralType<any>`
|
|
356
|
+
|
|
357
|
+
### opt 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
358
|
+
|
|
359
|
+
Create an optional type wrapper (allows undefined).
|
|
360
|
+
|
|
361
|
+
**Signature:** `<const T extends TypeWrapper<unknown> | BasicType>(inner: T) => OrType<any>`
|
|
362
|
+
|
|
363
|
+
**Type Parameters:**
|
|
364
|
+
|
|
365
|
+
- `T extends TypeWrapper<unknown>|BasicType` - Type wrapper or basic type to make optional.
|
|
366
|
+
|
|
367
|
+
**Parameters:**
|
|
368
|
+
|
|
369
|
+
- `inner: T` - - The inner type to make optional.
|
|
370
|
+
|
|
371
|
+
**Returns:** A union type that accepts the inner type or undefined.
|
|
372
|
+
|
|
373
|
+
**Examples:**
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
const optionalString = E.opt(E.string);
|
|
377
|
+
const optionalNumber = E.opt(E.number);
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### or 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
381
|
+
|
|
382
|
+
Create a union type wrapper from multiple type choices.
|
|
383
|
+
|
|
384
|
+
**Signature:** `<const T extends (TypeWrapper<unknown> | BasicType)[]>(...choices: T) => OrType<UnwrapTypes<T>>`
|
|
385
|
+
|
|
386
|
+
**Type Parameters:**
|
|
387
|
+
|
|
388
|
+
- `T extends (TypeWrapper<unknown>|BasicType)[]` - Array of type wrapper or basic types.
|
|
389
|
+
|
|
390
|
+
**Parameters:**
|
|
391
|
+
|
|
392
|
+
- `choices: T` - - The type choices for the union.
|
|
393
|
+
|
|
394
|
+
**Returns:** A union type instance.
|
|
395
|
+
|
|
396
|
+
**Examples:**
|
|
397
|
+
|
|
398
|
+
```typescript
|
|
399
|
+
const stringOrNumber = E.or(E.string, E.number);
|
|
400
|
+
const status = E.or("active", "inactive", "pending");
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### array 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
404
|
+
|
|
405
|
+
Create an array type wrapper with optional length constraints.
|
|
406
|
+
|
|
407
|
+
**Signature:** `<const T>(inner: TypeWrapper<T>, opts?: { min?: number; max?: number; }) => ArrayType<T>`
|
|
408
|
+
|
|
409
|
+
**Type Parameters:**
|
|
410
|
+
|
|
411
|
+
- `T` - The element type.
|
|
412
|
+
|
|
413
|
+
**Parameters:**
|
|
414
|
+
|
|
415
|
+
- `inner: TypeWrapper<T>` - - Type wrapper for array elements.
|
|
416
|
+
- `opts: {min?: number, max?: number}` (optional) - - Optional constraints (min/max length).
|
|
417
|
+
|
|
418
|
+
**Returns:** An array type instance.
|
|
419
|
+
|
|
420
|
+
**Examples:**
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
const stringArray = E.array(E.string);
|
|
424
|
+
const boundedArray = E.array(E.number, {min: 1, max: 10});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### literal 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
428
|
+
|
|
429
|
+
Create a literal type wrapper for a constant value.
|
|
430
|
+
|
|
431
|
+
**Signature:** `<const T>(value: T) => LiteralType<T>`
|
|
432
|
+
|
|
433
|
+
**Type Parameters:**
|
|
434
|
+
|
|
435
|
+
- `T` - The literal type.
|
|
436
|
+
|
|
437
|
+
**Parameters:**
|
|
438
|
+
|
|
439
|
+
- `value: T` - - The literal value.
|
|
440
|
+
|
|
441
|
+
**Returns:** A literal type instance.
|
|
442
|
+
|
|
443
|
+
**Examples:**
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
const statusType = E.literal("active");
|
|
447
|
+
const countType = E.literal(42);
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### link 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
451
|
+
|
|
452
|
+
Create a link type wrapper for model relationships.
|
|
453
|
+
|
|
454
|
+
**Signature:** `<const T extends typeof Model<any>>(TargetModel: T) => LinkType<T>`
|
|
455
|
+
|
|
456
|
+
**Type Parameters:**
|
|
457
|
+
|
|
458
|
+
- `T extends typeof Model<any>` - The target model class.
|
|
459
|
+
|
|
460
|
+
**Parameters:**
|
|
461
|
+
|
|
462
|
+
- `TargetModel: T` - - The model class this link points to.
|
|
463
|
+
|
|
464
|
+
**Returns:** A link type instance.
|
|
465
|
+
|
|
466
|
+
**Examples:**
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
class User extends E.Model<User> {
|
|
470
|
+
posts = E.field(E.array(E.link(Post, 'author')));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
class Post extends E.Model<Post> {
|
|
474
|
+
author = E.field(E.link(User));
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### index 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
479
|
+
|
|
480
|
+
Create a secondary index on model fields.
|
|
481
|
+
|
|
482
|
+
**Signature:** `{ <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): SecondaryIndex<M, [F]>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(MyModel: M, fields: FS): SecondaryIndex<...>; }`
|
|
483
|
+
|
|
484
|
+
**Type Parameters:**
|
|
485
|
+
|
|
486
|
+
- `M extends typeof Model` - The model class.
|
|
487
|
+
- `F extends (keyof InstanceType<M> & string)` - The field name (for single field index).
|
|
488
|
+
|
|
489
|
+
**Parameters:**
|
|
490
|
+
|
|
491
|
+
- `MyModel: M` - - The model class to create the index for.
|
|
492
|
+
- `field: F` - - Single field name for simple indexes.
|
|
493
|
+
|
|
494
|
+
**Returns:** A new SecondaryIndex instance.
|
|
495
|
+
|
|
496
|
+
**Examples:**
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
class User extends E.Model<User> {
|
|
500
|
+
static byAge = E.index(User, "age");
|
|
501
|
+
static byTagsDate = E.index(User, ["tags", "createdAt"]);
|
|
502
|
+
}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### primary 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
506
|
+
|
|
507
|
+
Create a primary index on model fields.
|
|
508
|
+
|
|
509
|
+
**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<...>; }`
|
|
510
|
+
|
|
511
|
+
**Type Parameters:**
|
|
512
|
+
|
|
513
|
+
- `M extends typeof Model` - The model class.
|
|
514
|
+
- `F extends (keyof InstanceType<M> & string)` - The field name (for single field index).
|
|
515
|
+
|
|
516
|
+
**Parameters:**
|
|
517
|
+
|
|
518
|
+
- `MyModel: M` - - The model class to create the index for.
|
|
519
|
+
- `field: F` - - Single field name for simple indexes.
|
|
520
|
+
|
|
521
|
+
**Returns:** A new PrimaryIndex instance.
|
|
522
|
+
|
|
523
|
+
**Examples:**
|
|
524
|
+
|
|
525
|
+
```typescript
|
|
526
|
+
class User extends E.Model<User> {
|
|
527
|
+
static pk = E.primary(User, ["id"]);
|
|
528
|
+
static pkSingle = E.primary(User, "id");
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### unique 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
533
|
+
|
|
534
|
+
Create a unique index on model fields.
|
|
535
|
+
|
|
536
|
+
**Signature:** `{ <M extends typeof Model, const F extends (keyof InstanceType<M> & string)>(MyModel: M, field: F): UniqueIndex<M, [F]>; <M extends typeof Model, const FS extends readonly (keyof InstanceType<M> & string)[]>(MyModel: M, fields: FS): UniqueIndex<...>; }`
|
|
537
|
+
|
|
538
|
+
**Type Parameters:**
|
|
539
|
+
|
|
540
|
+
- `M extends typeof Model` - The model class.
|
|
541
|
+
- `F extends (keyof InstanceType<M> & string)` - The field name (for single field index).
|
|
542
|
+
|
|
543
|
+
**Parameters:**
|
|
544
|
+
|
|
545
|
+
- `MyModel: M` - - The model class to create the index for.
|
|
546
|
+
- `field: F` - - Single field name for simple indexes.
|
|
547
|
+
|
|
548
|
+
**Returns:** A new UniqueIndex instance.
|
|
549
|
+
|
|
550
|
+
**Examples:**
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
class User extends E.Model<User> {
|
|
554
|
+
static byEmail = E.unique(User, "email");
|
|
555
|
+
static byNameAge = E.unique(User, ["name", "age"]);
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### dump 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
560
|
+
|
|
561
|
+
Dump database contents for debugging.
|
|
562
|
+
|
|
563
|
+
Prints all indexes and their data to the console for inspection.
|
|
564
|
+
This is primarily useful for development and debugging purposes.
|
|
565
|
+
|
|
566
|
+
**Signature:** `() => void`
|
|
567
|
+
|
|
568
|
+
### BaseIndex 路 [abstract class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L104)
|
|
569
|
+
|
|
570
|
+
Base class for database indexes for efficient lookups on model fields.
|
|
571
|
+
|
|
572
|
+
Indexes enable fast queries on specific field combinations and enforce uniqueness constraints.
|
|
573
|
+
|
|
574
|
+
**Type Parameters:**
|
|
575
|
+
|
|
576
|
+
- `M extends typeof Model` - The model class this index belongs to.
|
|
577
|
+
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
578
|
+
|
|
579
|
+
**Constructor Parameters:**
|
|
580
|
+
|
|
581
|
+
- `MyModel`: - The model class this index belongs to.
|
|
582
|
+
- `_fieldNames`: - Array of field names that make up this index.
|
|
583
|
+
|
|
584
|
+
#### baseIndex.find 路 [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
585
|
+
|
|
586
|
+
Find model instances using flexible range query options.
|
|
587
|
+
|
|
588
|
+
Supports exact matches, inclusive/exclusive range queries, and reverse iteration.
|
|
589
|
+
For single-field indexes, you can pass values directly or in arrays.
|
|
590
|
+
For multi-field indexes, pass arrays or partial arrays for prefix matching.
|
|
591
|
+
|
|
592
|
+
**Signature:** `(opts?: FindOptions<IndexArgTypes<M, F>>) => IndexRangeIterator<M, F>`
|
|
593
|
+
|
|
594
|
+
**Parameters:**
|
|
595
|
+
|
|
596
|
+
- `opts: FindOptions<IndexArgTypes<M, F>>` (optional) - - Query options object
|
|
597
|
+
|
|
598
|
+
**Returns:** An iterable of model instances matching the query
|
|
599
|
+
|
|
600
|
+
**Examples:**
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
// Exact match
|
|
604
|
+
for (const user of User.byEmail.find({is: "john@example.com"})) {
|
|
605
|
+
console.log(user.name);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Range query (inclusive)
|
|
609
|
+
for (const user of User.byEmail.find({from: "a@", to: "m@"})) {
|
|
610
|
+
console.log(user.email);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Range query (exclusive)
|
|
614
|
+
for (const user of User.byEmail.find({after: "a@", before: "m@"})) {
|
|
615
|
+
console.log(user.email);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// Open-ended ranges
|
|
619
|
+
for (const user of User.byEmail.find({from: "m@"})) { // m@ and later
|
|
620
|
+
console.log(user.email);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
for (const user of User.byEmail.find({to: "m@"})) { // up to and including m@
|
|
624
|
+
console.log(user.email);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Reverse iteration
|
|
628
|
+
for (const user of User.byEmail.find({reverse: true})) {
|
|
629
|
+
console.log(user.email); // Z to A order
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Multi-field index prefix matching
|
|
633
|
+
for (const item of CompositeModel.pk.find({from: ["electronics", "phones"]})) {
|
|
634
|
+
console.log(item.name); // All electronics/phones items
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// For single-field indexes, you can use the value directly
|
|
638
|
+
for (const user of User.byEmail.find({is: "john@example.com"})) {
|
|
639
|
+
console.log(user.name);
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### UniqueIndex 路 [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
644
|
+
|
|
645
|
+
Unique index that stores references to the primary key.
|
|
646
|
+
|
|
647
|
+
**Type Parameters:**
|
|
648
|
+
|
|
649
|
+
- `M extends typeof Model` - The model class this index belongs to.
|
|
650
|
+
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
651
|
+
|
|
652
|
+
#### uniqueIndex.get 路 [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
653
|
+
|
|
654
|
+
Get a model instance by unique index key values.
|
|
655
|
+
|
|
656
|
+
**Signature:** `(...args: IndexArgTypes<M, F>) => InstanceType<M>`
|
|
657
|
+
|
|
658
|
+
**Parameters:**
|
|
659
|
+
|
|
660
|
+
- `args: IndexArgTypes<M, F>` - - The unique index key values.
|
|
661
|
+
|
|
662
|
+
**Returns:** The model instance if found, undefined otherwise.
|
|
663
|
+
|
|
664
|
+
**Examples:**
|
|
665
|
+
|
|
666
|
+
```typescript
|
|
667
|
+
const userByEmail = User.byEmail.get("john@example.com");
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### PrimaryIndex 路 [class](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
671
|
+
|
|
672
|
+
Primary index that stores the actual model data.
|
|
673
|
+
|
|
674
|
+
**Type Parameters:**
|
|
675
|
+
|
|
676
|
+
- `M extends typeof Model` - The model class this index belongs to.
|
|
677
|
+
- `F extends readonly (keyof InstanceType<M> & string)[]` - The field names that make up this index.
|
|
678
|
+
|
|
679
|
+
#### primaryIndex.get 路 [method](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
680
|
+
|
|
681
|
+
Get a model instance by primary key values.
|
|
682
|
+
|
|
683
|
+
**Signature:** `(...args: IndexArgTypes<M, F>) => InstanceType<M>`
|
|
684
|
+
|
|
685
|
+
**Parameters:**
|
|
686
|
+
|
|
687
|
+
- `args: IndexArgTypes<M, F>` - - The primary key values.
|
|
688
|
+
|
|
689
|
+
**Returns:** The model instance if found, undefined otherwise.
|
|
690
|
+
|
|
691
|
+
**Examples:**
|
|
692
|
+
|
|
693
|
+
```typescript
|
|
694
|
+
const user = User.pk.get("john_doe");
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### init 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
698
|
+
|
|
699
|
+
Initialize the database with the specified directory path.
|
|
700
|
+
This function may only be called once. If it is not called before the first transact(),
|
|
701
|
+
the database will be automatically initialized with the default directory.
|
|
702
|
+
|
|
703
|
+
**Signature:** `(dbDir?: string) => void`
|
|
704
|
+
|
|
705
|
+
**Parameters:**
|
|
706
|
+
|
|
707
|
+
- `dbDir?: string` - - Optional directory path for the database (defaults to environment variable $OLMDB_DIR or "./.olmdb").
|
|
708
|
+
|
|
709
|
+
**Throws:**
|
|
710
|
+
|
|
711
|
+
- With code "DUP_INIT" if database is already initialized.
|
|
712
|
+
- With code "CREATE_DIR_FAILED" if directory creation fails.
|
|
713
|
+
- With code "LMDB-{code}" for LMDB-specific errors.
|
|
714
|
+
|
|
715
|
+
**Examples:**
|
|
716
|
+
|
|
717
|
+
```typescript
|
|
718
|
+
init("./my-database");
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### onCommit 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
722
|
+
|
|
723
|
+
Registers a callback to be executed when the current transaction commits successfully.
|
|
724
|
+
The callback will be executed outside of transaction context.
|
|
725
|
+
|
|
726
|
+
**Signature:** `(callback: (commitSeq: number) => void) => void`
|
|
727
|
+
|
|
728
|
+
**Parameters:**
|
|
729
|
+
|
|
730
|
+
- `callback: (commitSeq: number) => void` - - Function to execute when transaction commits. It receives the commit sequence, which is an always-increasing number that provides a global ordering of commits, as an argument.
|
|
731
|
+
|
|
732
|
+
**Throws:**
|
|
733
|
+
|
|
734
|
+
- If called outside of a transaction context
|
|
735
|
+
|
|
736
|
+
### onRevert 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
737
|
+
|
|
738
|
+
Registers a callback to be executed when the current transaction is reverted (aborted due to error).
|
|
739
|
+
The callback will be executed outside of transaction context.
|
|
740
|
+
|
|
741
|
+
**Signature:** `(callback: (commitSeq: number) => void) => void`
|
|
742
|
+
|
|
743
|
+
**Parameters:**
|
|
744
|
+
|
|
745
|
+
- `callback: (commitSeq: number) => void` - - Function to execute when transaction is reverted. It receives the dummy (always 0) commit sequence indicating failure as an argument.
|
|
746
|
+
|
|
747
|
+
**Throws:**
|
|
748
|
+
|
|
749
|
+
- If called outside of a transaction context
|
|
750
|
+
|
|
751
|
+
### getTransactionData 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L51)
|
|
752
|
+
|
|
753
|
+
Retrieves data from the current transaction context.
|
|
754
|
+
|
|
755
|
+
**Signature:** `(key: symbol) => any`
|
|
756
|
+
|
|
757
|
+
**Parameters:**
|
|
758
|
+
|
|
759
|
+
- `key: symbol` - - A symbol key to retrieve data from the current transaction context.
|
|
760
|
+
|
|
761
|
+
**Returns:** - The value associated with the key, or undefined if not set.
|
|
762
|
+
|
|
763
|
+
**Throws:**
|
|
764
|
+
|
|
765
|
+
- If called outside of a transaction context.
|
|
766
|
+
|
|
767
|
+
### setTransactionData 路 [function](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L44)
|
|
768
|
+
|
|
769
|
+
Attach some arbitrary user data to the current transaction context, which is
|
|
770
|
+
attached to the currently running (async) task.
|
|
771
|
+
|
|
772
|
+
**Signature:** `(key: symbol, value: any) => void`
|
|
773
|
+
|
|
774
|
+
**Parameters:**
|
|
775
|
+
|
|
776
|
+
- `key: symbol` - - A symbol key to store data in the current transaction context.
|
|
777
|
+
- `value: any` - - The value to store.
|
|
778
|
+
|
|
779
|
+
**Throws:**
|
|
780
|
+
|
|
781
|
+
- If called outside of a transaction context.
|
|
782
|
+
|
|
783
|
+
**Examples:**
|
|
784
|
+
|
|
785
|
+
```typescript
|
|
786
|
+
const MY_SYMBOL = Symbol("myKey");
|
|
787
|
+
await transact(async () => {
|
|
788
|
+
setTransactionData(MY_SYMBOL, "myValue");
|
|
789
|
+
await somethingAsync(); // Can be interleaved with other transactions
|
|
790
|
+
const value = getTransactionData(MY_SYMBOL);
|
|
791
|
+
console.log(value); // "myValue"
|
|
792
|
+
});
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
### DatabaseError 路 [constant](https://github.com/vanviegen/edinburgh/blob/main/src/edinburgh.ts#L120)
|
|
796
|
+
|
|
797
|
+
The DatabaseError class is used to represent errors that occur during database operations.
|
|
798
|
+
It extends the built-in Error class and has a machine readable error code string property.
|
|
799
|
+
|
|
800
|
+
The lowlevel API will throw DatabaseError instances for all database-related errors.
|
|
801
|
+
Invalid function arguments will throw TypeError.
|
|
802
|
+
|
|
803
|
+
**Value:** `DatabaseErrorConstructor`
|
|
804
|
+
|