stabilize-orm 1.2.0 → 1.3.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/CHANGELOG.md +33 -5
- package/README.md +165 -129
- package/client.ts +7 -82
- package/hooks.ts +65 -22
- package/index.ts +7 -39
- package/migrations.ts +23 -38
- package/model.ts +115 -0
- package/package.json +3 -9
- package/repository.ts +56 -66
- package/decorators.ts +0 -170
package/repository.ts
CHANGED
|
@@ -9,24 +9,17 @@ import { DBClient } from "./client";
|
|
|
9
9
|
import { ConsoleLogger, type Logger } from "./logger";
|
|
10
10
|
import { QueryBuilder } from "./query-builder";
|
|
11
11
|
import {
|
|
12
|
+
DataTypes,
|
|
12
13
|
DBType,
|
|
13
14
|
RelationType,
|
|
14
15
|
StabilizeError,
|
|
15
16
|
type CacheConfig,
|
|
16
17
|
} from "./types";
|
|
17
|
-
import {
|
|
18
|
-
ModelKey,
|
|
19
|
-
ColumnKey,
|
|
20
|
-
ValidatorKey,
|
|
21
|
-
RelationKey,
|
|
22
|
-
SoftDeleteKey,
|
|
23
|
-
VersionedKey,
|
|
24
|
-
} from "./decorators";
|
|
18
|
+
import { MetadataStorage } from "./model";
|
|
25
19
|
import { getHooks, type HookType } from "./hooks";
|
|
26
20
|
|
|
27
21
|
type VersionOperation = "insert" | "update" | "delete";
|
|
28
22
|
|
|
29
|
-
|
|
30
23
|
/**
|
|
31
24
|
* Provides a generic repository for a model `T`.
|
|
32
25
|
* This class abstracts the database interactions for a specific model,
|
|
@@ -57,7 +50,7 @@ export class Repository<T> {
|
|
|
57
50
|
/**
|
|
58
51
|
* Creates an instance of Repository.
|
|
59
52
|
* @param client The database client instance for executing queries.
|
|
60
|
-
* @param model The model class constructor,
|
|
53
|
+
* @param model The model class constructor, defined with `defineModel`.
|
|
61
54
|
* @param cacheConfig Optional configuration for caching.
|
|
62
55
|
* @param logger A logger instance for logging messages.
|
|
63
56
|
*/
|
|
@@ -69,14 +62,30 @@ export class Repository<T> {
|
|
|
69
62
|
) {
|
|
70
63
|
this.client = client;
|
|
71
64
|
this.cache = cacheConfig.enabled ? new Cache(cacheConfig, logger) : null;
|
|
72
|
-
this.table =
|
|
73
|
-
this.columns =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
this.table = MetadataStorage.getTableName(model);
|
|
66
|
+
this.columns = Object.fromEntries(
|
|
67
|
+
Object.entries(MetadataStorage.getColumns(model)).map(([key, col]) => [
|
|
68
|
+
key,
|
|
69
|
+
{ name: col.name ?? key, type: typeof col.type === 'string' ? col.type : DataTypes[col.type] },
|
|
70
|
+
])
|
|
71
|
+
);
|
|
72
|
+
this.relations = Object.fromEntries(
|
|
73
|
+
Object.entries(MetadataStorage.getRelations(model)).map(([key, rel]) => [
|
|
74
|
+
key,
|
|
75
|
+
{
|
|
76
|
+
type: rel.type,
|
|
77
|
+
targetModel: rel.target,
|
|
78
|
+
foreignKey: rel.foreignKey,
|
|
79
|
+
inverseKey: rel.inverseKey,
|
|
80
|
+
joinTable: rel.joinTable,
|
|
81
|
+
},
|
|
82
|
+
])
|
|
83
|
+
);
|
|
84
|
+
this.validators = MetadataStorage.getValidators(model);
|
|
85
|
+
|
|
86
|
+
this.softDeleteField = MetadataStorage.getSoftDeleteField(model);
|
|
78
87
|
this.logger = logger;
|
|
79
|
-
this.versioned =
|
|
88
|
+
this.versioned = MetadataStorage.isVersioned(model);
|
|
80
89
|
this.historyTable = `${this.table}_history`;
|
|
81
90
|
}
|
|
82
91
|
|
|
@@ -93,7 +102,7 @@ export class Repository<T> {
|
|
|
93
102
|
|
|
94
103
|
/**
|
|
95
104
|
* @internal
|
|
96
|
-
* Validates an entity against the 'required' constraints defined in
|
|
105
|
+
* Validates an entity against the 'required' constraints defined in the model configuration.
|
|
97
106
|
* @param entity The partial entity to validate.
|
|
98
107
|
*/
|
|
99
108
|
private validate(entity: Partial<T>) {
|
|
@@ -112,13 +121,13 @@ export class Repository<T> {
|
|
|
112
121
|
}
|
|
113
122
|
|
|
114
123
|
/**
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
124
|
+
* Runs lifecycle hooks of a given type for the entity.
|
|
125
|
+
* @param entity The entity instance.
|
|
126
|
+
* @param type The hook type (e.g., 'beforeCreate').
|
|
127
|
+
*/
|
|
119
128
|
private async runHooks(entity: any, type: HookType): Promise<void> {
|
|
120
129
|
for (const hook of getHooks(entity, type)) {
|
|
121
|
-
await hook();
|
|
130
|
+
await hook.callback(entity);
|
|
122
131
|
}
|
|
123
132
|
}
|
|
124
133
|
|
|
@@ -173,8 +182,8 @@ export class Repository<T> {
|
|
|
173
182
|
}
|
|
174
183
|
|
|
175
184
|
/**
|
|
176
|
-
|
|
177
|
-
|
|
185
|
+
* Snapshot query: get record as it was at a point in time.
|
|
186
|
+
*/
|
|
178
187
|
async asOf(
|
|
179
188
|
id: number | string,
|
|
180
189
|
asOfDate: Date,
|
|
@@ -190,8 +199,8 @@ export class Repository<T> {
|
|
|
190
199
|
}
|
|
191
200
|
|
|
192
201
|
/**
|
|
193
|
-
|
|
194
|
-
|
|
202
|
+
* Get all history for a record.
|
|
203
|
+
*/
|
|
195
204
|
async history(
|
|
196
205
|
id: number | string,
|
|
197
206
|
_client?: DBClient
|
|
@@ -204,8 +213,6 @@ export class Repository<T> {
|
|
|
204
213
|
);
|
|
205
214
|
}
|
|
206
215
|
|
|
207
|
-
|
|
208
|
-
|
|
209
216
|
/**
|
|
210
217
|
* Rollback a record to a previous version.
|
|
211
218
|
*/
|
|
@@ -237,21 +244,12 @@ export class Repository<T> {
|
|
|
237
244
|
});
|
|
238
245
|
}
|
|
239
246
|
|
|
240
|
-
|
|
241
247
|
/**
|
|
242
248
|
* Writes a versioned history row for the entity to the history table.
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
* This function works for Postgres, MySQL, and SQLite, and uses positional parameters
|
|
249
|
-
* (properly formatted for the target database) for safety and compatibility.
|
|
250
|
-
*
|
|
251
|
-
* @param entity - The entity object being versioned
|
|
252
|
-
* @param operation - The operation performed ("insert", "update", "delete")
|
|
253
|
-
* @param client - The database client to use for the insert
|
|
254
|
-
* @param user - The user/system responsible for the change (default: "system")
|
|
249
|
+
* @param entity The entity object being versioned
|
|
250
|
+
* @param operation The operation performed ("insert", "update", "delete")
|
|
251
|
+
* @param client The database client to use for the insert
|
|
252
|
+
* @param user The user/system responsible for the change (default: "system")
|
|
255
253
|
*/
|
|
256
254
|
private async writeHistory(
|
|
257
255
|
entity: any,
|
|
@@ -261,11 +259,9 @@ export class Repository<T> {
|
|
|
261
259
|
) {
|
|
262
260
|
if (!this.versioned) return;
|
|
263
261
|
|
|
264
|
-
// Get property keys and corresponding SQL column names
|
|
265
262
|
const propertyKeys = Object.keys(this.columns);
|
|
266
263
|
const sqlColumnNames = propertyKeys.map((k) => this.columns[k]!.name);
|
|
267
264
|
|
|
268
|
-
// Build historyColumns using SQL column names
|
|
269
265
|
const historyColumns = [
|
|
270
266
|
...sqlColumnNames,
|
|
271
267
|
"operation",
|
|
@@ -276,9 +272,7 @@ export class Repository<T> {
|
|
|
276
272
|
"modified_at"
|
|
277
273
|
];
|
|
278
274
|
|
|
279
|
-
// Map values from entity using property keys
|
|
280
275
|
const values = propertyKeys.map((k) => entity[k]);
|
|
281
|
-
|
|
282
276
|
const params = [
|
|
283
277
|
...values,
|
|
284
278
|
operation,
|
|
@@ -288,7 +282,7 @@ export class Repository<T> {
|
|
|
288
282
|
user || "system",
|
|
289
283
|
new Date()
|
|
290
284
|
];
|
|
291
|
-
|
|
285
|
+
|
|
292
286
|
let placeholders: string;
|
|
293
287
|
if (client.config.type === DBType.Postgres) {
|
|
294
288
|
placeholders = params.map((_, i) => `$${i + 1}`).join(", ");
|
|
@@ -332,6 +326,7 @@ export class Repository<T> {
|
|
|
332
326
|
return result;
|
|
333
327
|
});
|
|
334
328
|
}
|
|
329
|
+
|
|
335
330
|
/**
|
|
336
331
|
* @internal
|
|
337
332
|
* The private implementation for creating a record, executed within a transaction.
|
|
@@ -407,7 +402,6 @@ export class Repository<T> {
|
|
|
407
402
|
options: { relations?: string[]; batchSize?: number } = {},
|
|
408
403
|
): Promise<T[]> {
|
|
409
404
|
return this.client.transaction(async (txClient) => {
|
|
410
|
-
// Prepare entity instances for hooks
|
|
411
405
|
const preparedEntities = entities.map(data => {
|
|
412
406
|
const instance = new (this as any).model();
|
|
413
407
|
Object.assign(instance, data);
|
|
@@ -464,7 +458,6 @@ export class Repository<T> {
|
|
|
464
458
|
);
|
|
465
459
|
|
|
466
460
|
if (dbType === DBType.Postgres) {
|
|
467
|
-
// PostgreSQL: numbered placeholders ($1, $2, ...)
|
|
468
461
|
let paramIdx = 1;
|
|
469
462
|
const valuePlaceholders = batch
|
|
470
463
|
.map(
|
|
@@ -476,7 +469,6 @@ export class Repository<T> {
|
|
|
476
469
|
const batchResults = await client.query<T>(query, params);
|
|
477
470
|
const ids = batchResults.map((r) => (r as any).id);
|
|
478
471
|
|
|
479
|
-
// Handle relation loading if needed
|
|
480
472
|
let finalResults = batchResults;
|
|
481
473
|
if (ids.length > 0 && batchResults.length === 0) {
|
|
482
474
|
const queryBuilder = this.find().where(
|
|
@@ -493,7 +485,6 @@ export class Repository<T> {
|
|
|
493
485
|
results.push(...finalResults);
|
|
494
486
|
|
|
495
487
|
} else {
|
|
496
|
-
// SQLite/MySQL: ? placeholders
|
|
497
488
|
const placeholders = `(${keys.map(() => "?").join(", ")})`;
|
|
498
489
|
query = `INSERT INTO ${this.table} (${columnNames}) VALUES ${batch.map(() => placeholders).join(", ")}`;
|
|
499
490
|
await client.query(query, params);
|
|
@@ -642,17 +633,14 @@ export class Repository<T> {
|
|
|
642
633
|
for (let i = 0; i < updates.length; i += batchSize) {
|
|
643
634
|
const batch = updates.slice(i, i + batchSize);
|
|
644
635
|
for (const update of batch) {
|
|
645
|
-
// Find all IDs matching the where clause
|
|
646
636
|
const rows = await client.query<{ id: number | string }>(
|
|
647
637
|
`SELECT id FROM ${this.table} WHERE ${update.where.condition}${this.softDeleteField ? ` AND ${this.softDeleteField} IS NULL` : ""}`,
|
|
648
638
|
update.where.params,
|
|
649
639
|
);
|
|
650
640
|
for (const { id } of rows) {
|
|
651
|
-
// Fetch record before update for versioning
|
|
652
641
|
const before = await this.findOne(id, {}, client);
|
|
653
642
|
if (!before) continue;
|
|
654
643
|
|
|
655
|
-
// Prepare instance for hooks
|
|
656
644
|
const instance = new ((this as any).model || Object)();
|
|
657
645
|
Object.assign(instance, before, update.set);
|
|
658
646
|
|
|
@@ -693,6 +681,7 @@ export class Repository<T> {
|
|
|
693
681
|
`Bulk updated ${updates.length} ${this.table} entities in ${(performance.now() - start).toFixed(2)}ms`,
|
|
694
682
|
);
|
|
695
683
|
}
|
|
684
|
+
|
|
696
685
|
/**
|
|
697
686
|
* Performs an "update or insert" operation based on a set of unique keys.
|
|
698
687
|
* @param entity The entity to upsert.
|
|
@@ -728,6 +717,7 @@ export class Repository<T> {
|
|
|
728
717
|
const columns = Object.keys(entity).filter((k) => this.columns[k]);
|
|
729
718
|
const columnNames = columns.map((k) => this.columns[k]?.name).join(", ");
|
|
730
719
|
const placeholders = columns.map(() => "?").join(", ");
|
|
720
|
+
|
|
731
721
|
const updateClause = columns
|
|
732
722
|
.filter((c) => !keys.includes(c))
|
|
733
723
|
.map((c) => `${this.columns[c]?.name} = ?`).join(", ");
|
|
@@ -737,7 +727,6 @@ export class Repository<T> {
|
|
|
737
727
|
const insertParams = columns.map((k) => (entity as any)[k]);
|
|
738
728
|
let params = [...insertParams, ...updateParams];
|
|
739
729
|
|
|
740
|
-
// Try to find the record before upsert
|
|
741
730
|
let before: T | null = null;
|
|
742
731
|
let isUpdate = false;
|
|
743
732
|
if (this.versioned && keys.length > 0) {
|
|
@@ -751,7 +740,6 @@ export class Repository<T> {
|
|
|
751
740
|
isUpdate = !!before;
|
|
752
741
|
}
|
|
753
742
|
|
|
754
|
-
// Prepare instance for hooks
|
|
755
743
|
const instance = new ((this as any).model || Object)();
|
|
756
744
|
Object.assign(instance, before || {}, entity);
|
|
757
745
|
|
|
@@ -767,7 +755,7 @@ export class Repository<T> {
|
|
|
767
755
|
query = `INSERT INTO ${this.table} (${columnNames}) VALUES (${placeholders}) ON CONFLICT(${keys.map((k) => this.columns[k]!.name).join(", ")}) DO UPDATE SET ${updateClause}`;
|
|
768
756
|
} else if (dbType === DBType.MySQL) {
|
|
769
757
|
query = `INSERT INTO ${this.table} (${columnNames}) VALUES (${placeholders}) ON DUPLICATE KEY UPDATE ${updateClause}`;
|
|
770
|
-
} else {
|
|
758
|
+
} else {
|
|
771
759
|
const pgUpdateClause = columns
|
|
772
760
|
.filter((c) => !keys.includes(c))
|
|
773
761
|
.map((c) => `${this.columns[c]?.name} = EXCLUDED.${this.columns[c]?.name}`).join(", ");
|
|
@@ -799,13 +787,6 @@ export class Repository<T> {
|
|
|
799
787
|
await this.runHooks(result, "afterSave");
|
|
800
788
|
}
|
|
801
789
|
|
|
802
|
-
if (this.cache) {
|
|
803
|
-
await this.cache.invalidatePattern(`find:${this.table}:*`);
|
|
804
|
-
if (this.cache.getStrategy() === "write-through") {
|
|
805
|
-
await this.cache.set(`findOne:${this.table}:${id}`, [result], 60);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
|
|
809
790
|
if (this.versioned) {
|
|
810
791
|
await this.writeHistory(
|
|
811
792
|
{ ...result, version: before ? ((before as any).version ? (before as any).version + 1 : 1) : 1 },
|
|
@@ -814,11 +795,19 @@ export class Repository<T> {
|
|
|
814
795
|
);
|
|
815
796
|
}
|
|
816
797
|
|
|
798
|
+
if (this.cache) {
|
|
799
|
+
await this.cache.invalidatePattern(`find:${this.table}:*`);
|
|
800
|
+
if (this.cache.getStrategy() === "write-through") {
|
|
801
|
+
await this.cache.set(`findOne:${this.table}:${id}`, [result], 60);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
817
805
|
this.logger.logDebug(
|
|
818
806
|
`Upserted ${this.table} with ID ${id} in ${(performance.now() - start).toFixed(2)}ms`,
|
|
819
807
|
);
|
|
820
808
|
return result;
|
|
821
809
|
}
|
|
810
|
+
|
|
822
811
|
/**
|
|
823
812
|
* Deletes a record by its ID. Performs a soft delete if enabled on the model.
|
|
824
813
|
* @param id The ID of the record to delete.
|
|
@@ -929,6 +918,7 @@ export class Repository<T> {
|
|
|
929
918
|
`Bulk deleted ${ids.length} ${this.table} entities in ${(performance.now() - start).toFixed(2)}ms`,
|
|
930
919
|
);
|
|
931
920
|
}
|
|
921
|
+
|
|
932
922
|
/**
|
|
933
923
|
* Recovers a soft-deleted record by its ID.
|
|
934
924
|
* Throws an error if soft delete is not enabled on the model.
|
|
@@ -1014,7 +1004,7 @@ export class Repository<T> {
|
|
|
1014
1004
|
"RELATION_ERROR",
|
|
1015
1005
|
);
|
|
1016
1006
|
|
|
1017
|
-
const relatedTable =
|
|
1007
|
+
const relatedTable = MetadataStorage.getTableName(rel.targetModel());
|
|
1018
1008
|
if (
|
|
1019
1009
|
rel.type === RelationType.OneToOne ||
|
|
1020
1010
|
rel.type === RelationType.ManyToOne
|
|
@@ -1040,4 +1030,4 @@ export class Repository<T> {
|
|
|
1040
1030
|
);
|
|
1041
1031
|
}
|
|
1042
1032
|
}
|
|
1043
|
-
}
|
|
1033
|
+
}
|
package/decorators.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file decorators.ts
|
|
3
|
-
* @description Contains all the decorators used by the Stabilize ORM.
|
|
4
|
-
* @author ElectronSz
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import "reflect-metadata";
|
|
8
|
-
import { RelationType, DataTypes } from "./types";
|
|
9
|
-
|
|
10
|
-
export const ModelKey = Symbol("model");
|
|
11
|
-
export const ColumnKey = Symbol("column");
|
|
12
|
-
export const ValidatorKey = Symbol("validator");
|
|
13
|
-
export const RelationKey = Symbol("relation");
|
|
14
|
-
export const SoftDeleteKey = Symbol("softDelete");
|
|
15
|
-
export const DefaultKey = Symbol("default");
|
|
16
|
-
export const IndexKey = Symbol("index");
|
|
17
|
-
export const VersionedKey = Symbol("versioned");
|
|
18
|
-
|
|
19
|
-
export interface ColumnOptions {
|
|
20
|
-
name?: string;
|
|
21
|
-
type: DataTypes;
|
|
22
|
-
length?: number;
|
|
23
|
-
precision?: number;
|
|
24
|
-
scale?: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Decorator to mark a class as a database model.
|
|
29
|
-
* @param tableName The name of the table in the database.
|
|
30
|
-
*/
|
|
31
|
-
export function Model(tableName: string) {
|
|
32
|
-
return function (constructor: Function) {
|
|
33
|
-
Reflect.defineMetadata(ModelKey, tableName, constructor);
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Decorator to mark a property as a database column.
|
|
39
|
-
* @param options The configuration for the column, including name, type, and length.
|
|
40
|
-
*/
|
|
41
|
-
export function Column(options: ColumnOptions | DataTypes) {
|
|
42
|
-
return function (target: any, propertyKey: string) {
|
|
43
|
-
const columns = Reflect.getMetadata(ColumnKey, target) || {};
|
|
44
|
-
const columnOptions: ColumnOptions = typeof options === 'object' ? options : { type: options };
|
|
45
|
-
columns[propertyKey] = {
|
|
46
|
-
name: columnOptions.name || propertyKey,
|
|
47
|
-
...columnOptions,
|
|
48
|
-
};
|
|
49
|
-
Reflect.defineMetadata(ColumnKey, columns, target);
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Decorator to enforce a NOT NULL constraint on a column.
|
|
55
|
-
*/
|
|
56
|
-
export function Required() {
|
|
57
|
-
return function (target: any, propertyKey: string) {
|
|
58
|
-
const validators = Reflect.getMetadata(ValidatorKey, target) || {};
|
|
59
|
-
validators[propertyKey] = [...(validators[propertyKey] || []), "required"];
|
|
60
|
-
Reflect.defineMetadata(ValidatorKey, validators, target);
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Decorator to enforce a UNIQUE constraint on a column.
|
|
66
|
-
*/
|
|
67
|
-
export function Unique() {
|
|
68
|
-
return function (target: any, propertyKey: string) {
|
|
69
|
-
const validators = Reflect.getMetadata(ValidatorKey, target) || {};
|
|
70
|
-
validators[propertyKey] = [...(validators[propertyKey] || []), "unique"];
|
|
71
|
-
Reflect.defineMetadata(ValidatorKey, validators, target);
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Decorator to set a default value for a column.
|
|
77
|
-
* @param value The default value.
|
|
78
|
-
*/
|
|
79
|
-
export function Default(value: any) {
|
|
80
|
-
return function (target: any, propertyKey: string) {
|
|
81
|
-
Reflect.defineMetadata(DefaultKey, value, target, propertyKey);
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Decorator to create a non-unique index on a column for performance.
|
|
87
|
-
* @param indexName Optional: A custom name for the index.
|
|
88
|
-
*/
|
|
89
|
-
export function Index(indexName?: string) {
|
|
90
|
-
return function (target: any, propertyKey: string) {
|
|
91
|
-
const indexes = Reflect.getMetadata(IndexKey, target) || {};
|
|
92
|
-
indexes[propertyKey] = indexName || `idx_${propertyKey}`;
|
|
93
|
-
Reflect.defineMetadata(IndexKey, indexes, target);
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Decorator to enable soft-delete functionality on a model.
|
|
99
|
-
* The decorated property will store the deletion timestamp.
|
|
100
|
-
*/
|
|
101
|
-
export function SoftDelete() {
|
|
102
|
-
return function (target: any, propertyKey: string) {
|
|
103
|
-
Reflect.defineMetadata(SoftDeleteKey, propertyKey, target);
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Decorator to enable versioning (history, snapshot & time-travel) on a model.
|
|
109
|
-
*/
|
|
110
|
-
export function Versioned() {
|
|
111
|
-
return function (target: any) {
|
|
112
|
-
Reflect.defineMetadata(VersionedKey, true, target);
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
export function OneToOne(model: () => any, foreignKey: string) {
|
|
118
|
-
return function (target: any, propertyKey: string) {
|
|
119
|
-
const relations = Reflect.getMetadata(RelationKey, target) || {};
|
|
120
|
-
relations[propertyKey] = {
|
|
121
|
-
type: RelationType.OneToOne,
|
|
122
|
-
targetModel: model,
|
|
123
|
-
foreignKey,
|
|
124
|
-
};
|
|
125
|
-
Reflect.defineMetadata(RelationKey, relations, target);
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function ManyToOne(model: () => any, foreignKey: string) {
|
|
130
|
-
return function (target: any, propertyKey: string) {
|
|
131
|
-
const relations = Reflect.getMetadata(RelationKey, target) || {};
|
|
132
|
-
relations[propertyKey] = {
|
|
133
|
-
type: RelationType.ManyToOne,
|
|
134
|
-
targetModel: model,
|
|
135
|
-
foreignKey,
|
|
136
|
-
};
|
|
137
|
-
Reflect.defineMetadata(RelationKey, relations, target);
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function OneToMany(model: () => any, inverseKey: string) {
|
|
142
|
-
return function (target: any, propertyKey: string) {
|
|
143
|
-
const relations = Reflect.getMetadata(RelationKey, target) || {};
|
|
144
|
-
relations[propertyKey] = {
|
|
145
|
-
type: RelationType.OneToMany,
|
|
146
|
-
targetModel: model,
|
|
147
|
-
inverseKey,
|
|
148
|
-
};
|
|
149
|
-
Reflect.defineMetadata(RelationKey, relations, target);
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function ManyToMany(
|
|
154
|
-
model: () => any,
|
|
155
|
-
joinTable: string,
|
|
156
|
-
foreignKey: string,
|
|
157
|
-
inverseKey: string,
|
|
158
|
-
) {
|
|
159
|
-
return function (target: any, propertyKey: string) {
|
|
160
|
-
const relations = Reflect.getMetadata(RelationKey, target) || {};
|
|
161
|
-
relations[propertyKey] = {
|
|
162
|
-
type: RelationType.ManyToMany,
|
|
163
|
-
targetModel: model,
|
|
164
|
-
joinTable,
|
|
165
|
-
foreignKey,
|
|
166
|
-
inverseKey,
|
|
167
|
-
};
|
|
168
|
-
Reflect.defineMetadata(RelationKey, relations, target);
|
|
169
|
-
};
|
|
170
|
-
}
|