metal-orm 1.1.7 → 1.1.9
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 +1 -1
- package/dist/index.cjs +481 -203
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -3
- package/dist/index.d.ts +58 -3
- package/dist/index.js +480 -203
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/scripts/generate-entities/schema.mjs +196 -195
- package/src/decorators/decorator-metadata.ts +52 -46
- package/src/decorators/entity.ts +73 -68
- package/src/orm/entity-metadata.ts +301 -301
- package/src/orm/entity.ts +199 -199
- package/src/orm/save-graph.ts +446 -446
- package/src/orm/unit-of-work.ts +6 -6
- package/src/query-builder/select/cursor-pagination.ts +323 -0
- package/src/query-builder/select.ts +42 -1
- package/src/tree/tree-decorator.ts +137 -54
package/src/decorators/entity.ts
CHANGED
|
@@ -1,85 +1,90 @@
|
|
|
1
|
-
import { TableHooks } from '../schema/table.js';
|
|
2
|
-
import { RelationKinds } from '../schema/relation.js';
|
|
1
|
+
import { TableHooks } from '../schema/table.js';
|
|
2
|
+
import { RelationKinds } from '../schema/relation.js';
|
|
3
3
|
import {
|
|
4
4
|
addColumnMetadata,
|
|
5
5
|
addRelationMetadata,
|
|
6
6
|
EntityConstructor,
|
|
7
|
-
ensureEntityMetadata,
|
|
7
|
+
ensureEntityMetadata,
|
|
8
8
|
setEntityTableName
|
|
9
9
|
} from '../orm/entity-metadata.js';
|
|
10
10
|
import { readMetadataBag } from './decorator-metadata.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
type
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
.replace(/[
|
|
26
|
-
.replace(/
|
|
27
|
-
.replace(
|
|
28
|
-
.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
45
|
-
* @
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
11
|
+
import { syncTreeEntityMetadata } from '../tree/tree-decorator.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Options for defining an entity.
|
|
15
|
+
*/
|
|
16
|
+
export interface EntityOptions {
|
|
17
|
+
tableName?: string;
|
|
18
|
+
hooks?: TableHooks;
|
|
19
|
+
/** Entity type: 'table' (default) or 'view'. Views are read-only. */
|
|
20
|
+
type?: 'table' | 'view';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const toSnakeCase = (value: string): string => {
|
|
24
|
+
return value
|
|
25
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
26
|
+
.replace(/[^a-z0-9_]+/gi, '_')
|
|
27
|
+
.replace(/__+/g, '_')
|
|
28
|
+
.replace(/^_|_$/g, '')
|
|
29
|
+
.toLowerCase();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const deriveTableNameFromConstructor = (ctor: EntityConstructor<unknown>): string => {
|
|
33
|
+
const fallback = 'unknown';
|
|
34
|
+
const rawName = ctor.name || fallback;
|
|
35
|
+
const strippedName = rawName.replace(/Entity$/i, '');
|
|
36
|
+
const normalized = toSnakeCase(strippedName || rawName);
|
|
37
|
+
if (!normalized) {
|
|
38
|
+
return fallback;
|
|
39
|
+
}
|
|
40
|
+
return normalized.endsWith('s') ? normalized : `${normalized}s`;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Class decorator to mark a class as an entity and configure its table mapping.
|
|
45
|
+
* @param options - Configuration options for the entity.
|
|
46
|
+
* @returns A class decorator that registers the entity metadata.
|
|
47
|
+
*/
|
|
48
|
+
export function Entity(options: EntityOptions = {}) {
|
|
49
|
+
return function <T extends EntityConstructor>(value: T, context: ClassDecoratorContext): T {
|
|
50
|
+
const ctor = value;
|
|
51
|
+
const tableName = options.tableName ?? deriveTableNameFromConstructor(ctor);
|
|
52
|
+
setEntityTableName(ctor, tableName, options.hooks, options.type);
|
|
53
|
+
|
|
54
|
+
const bag = readMetadataBag(context);
|
|
54
55
|
if (bag) {
|
|
55
56
|
const meta = ensureEntityMetadata(ctor);
|
|
56
57
|
for (const entry of bag.columns) {
|
|
57
|
-
if (meta.columns[entry.propertyName]) {
|
|
58
|
-
throw new Error(
|
|
59
|
-
`Column '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
63
|
-
}
|
|
64
|
-
for (const entry of bag.relations) {
|
|
65
|
-
if (meta.relations[entry.propertyName]) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
`Relation '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
const relationCopy =
|
|
71
|
-
entry.relation.kind === RelationKinds.BelongsToMany
|
|
72
|
-
? {
|
|
73
|
-
...entry.relation,
|
|
74
|
-
defaultPivotColumns: entry.relation.defaultPivotColumns
|
|
75
|
-
? [...entry.relation.defaultPivotColumns]
|
|
76
|
-
: undefined
|
|
77
|
-
}
|
|
78
|
-
: { ...entry.relation };
|
|
58
|
+
if (meta.columns[entry.propertyName]) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Column '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
|
|
64
|
+
}
|
|
65
|
+
for (const entry of bag.relations) {
|
|
66
|
+
if (meta.relations[entry.propertyName]) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Relation '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const relationCopy =
|
|
72
|
+
entry.relation.kind === RelationKinds.BelongsToMany
|
|
73
|
+
? {
|
|
74
|
+
...entry.relation,
|
|
75
|
+
defaultPivotColumns: entry.relation.defaultPivotColumns
|
|
76
|
+
? [...entry.relation.defaultPivotColumns]
|
|
77
|
+
: undefined
|
|
78
|
+
}
|
|
79
|
+
: { ...entry.relation };
|
|
79
80
|
addRelationMetadata(ctor, entry.propertyName, relationCopy);
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
// Supports both decorator orders:
|
|
85
|
+
// @Entity() above @Tree() and @Tree() above @Entity().
|
|
86
|
+
syncTreeEntityMetadata(ctor, bag?.tree);
|
|
87
|
+
|
|
83
88
|
return ctor;
|
|
84
89
|
};
|
|
85
90
|
}
|