metal-orm 1.0.57 → 1.0.59
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 +23 -13
- package/dist/index.cjs +1750 -733
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +244 -157
- package/dist/index.d.ts +244 -157
- package/dist/index.js +1745 -733
- package/dist/index.js.map +1 -1
- package/package.json +69 -69
- package/src/core/ddl/schema-generator.ts +44 -1
- package/src/decorators/bootstrap.ts +186 -113
- package/src/decorators/column-decorator.ts +8 -49
- package/src/decorators/decorator-metadata.ts +10 -46
- package/src/decorators/entity.ts +30 -40
- package/src/decorators/relations.ts +30 -56
- package/src/orm/entity-hydration.ts +72 -0
- package/src/orm/entity-meta.ts +18 -13
- package/src/orm/entity-metadata.ts +240 -238
- package/src/orm/entity-relation-cache.ts +39 -0
- package/src/orm/entity-relations.ts +207 -0
- package/src/orm/entity.ts +124 -343
- package/src/orm/execute.ts +87 -20
- package/src/orm/lazy-batch/belongs-to-many.ts +134 -0
- package/src/orm/lazy-batch/belongs-to.ts +108 -0
- package/src/orm/lazy-batch/has-many.ts +69 -0
- package/src/orm/lazy-batch/has-one.ts +68 -0
- package/src/orm/lazy-batch/shared.ts +125 -0
- package/src/orm/lazy-batch.ts +4 -309
- package/src/orm/relations/belongs-to.ts +2 -2
- package/src/orm/relations/has-many.ts +23 -9
- package/src/orm/relations/has-one.ts +2 -2
- package/src/orm/relations/many-to-many.ts +29 -14
- package/src/orm/save-graph-types.ts +2 -2
- package/src/orm/save-graph.ts +18 -18
- package/src/query-builder/relation-conditions.ts +80 -59
- package/src/query-builder/relation-cte-builder.ts +63 -0
- package/src/query-builder/relation-filter-utils.ts +159 -0
- package/src/query-builder/relation-include-strategies.ts +177 -0
- package/src/query-builder/relation-join-planner.ts +80 -0
- package/src/query-builder/relation-service.ts +103 -159
- package/src/query-builder/relation-types.ts +43 -12
- package/src/query-builder/select/projection-facet.ts +23 -23
- package/src/query-builder/select/select-operations.ts +145 -0
- package/src/query-builder/select.ts +373 -426
- package/src/schema/relation.ts +22 -18
- package/src/schema/table.ts +22 -9
- package/src/schema/types.ts +103 -84
package/src/schema/relation.ts
CHANGED
|
@@ -57,12 +57,15 @@ export interface BelongsToRelation<TTarget extends TableDef = TableDef> {
|
|
|
57
57
|
/**
|
|
58
58
|
* Many-to-many relationship definition with rich pivot metadata
|
|
59
59
|
*/
|
|
60
|
-
export interface BelongsToManyRelation<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
export interface BelongsToManyRelation<
|
|
61
|
+
TTarget extends TableDef = TableDef,
|
|
62
|
+
TPivot extends TableDef = TableDef
|
|
63
|
+
> {
|
|
64
|
+
type: typeof RelationKinds.BelongsToMany;
|
|
65
|
+
target: TTarget;
|
|
66
|
+
pivotTable: TPivot;
|
|
67
|
+
pivotForeignKeyToRoot: string;
|
|
68
|
+
pivotForeignKeyToTarget: string;
|
|
66
69
|
localKey?: string;
|
|
67
70
|
targetKey?: string;
|
|
68
71
|
pivotPrimaryKey?: string;
|
|
@@ -156,24 +159,25 @@ export const belongsTo = <TTarget extends TableDef>(
|
|
|
156
159
|
* @param options - Pivot metadata configuration
|
|
157
160
|
* @returns BelongsToManyRelation definition
|
|
158
161
|
*/
|
|
159
|
-
export const belongsToMany = <
|
|
160
|
-
TTarget extends TableDef
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
export const belongsToMany = <
|
|
163
|
+
TTarget extends TableDef,
|
|
164
|
+
TPivot extends TableDef = TableDef
|
|
165
|
+
>(
|
|
166
|
+
target: TTarget,
|
|
167
|
+
pivotTable: TPivot,
|
|
168
|
+
options: {
|
|
169
|
+
pivotForeignKeyToRoot: string;
|
|
170
|
+
pivotForeignKeyToTarget: string;
|
|
167
171
|
localKey?: string;
|
|
168
172
|
targetKey?: string;
|
|
169
173
|
pivotPrimaryKey?: string;
|
|
170
174
|
defaultPivotColumns?: string[];
|
|
171
175
|
cascade?: CascadeMode;
|
|
172
176
|
}
|
|
173
|
-
): BelongsToManyRelation<TTarget> => ({
|
|
174
|
-
type: RelationKinds.BelongsToMany,
|
|
175
|
-
target,
|
|
176
|
-
pivotTable,
|
|
177
|
+
): BelongsToManyRelation<TTarget, TPivot> => ({
|
|
178
|
+
type: RelationKinds.BelongsToMany,
|
|
179
|
+
target,
|
|
180
|
+
pivotTable,
|
|
177
181
|
pivotForeignKeyToRoot: options.pivotForeignKeyToRoot,
|
|
178
182
|
pivotForeignKeyToTarget: options.pivotForeignKeyToTarget,
|
|
179
183
|
localKey: options.localKey,
|
package/src/schema/table.ts
CHANGED
|
@@ -85,13 +85,13 @@ export interface TableDef<T extends Record<string, ColumnDef> = Record<string, C
|
|
|
85
85
|
* });
|
|
86
86
|
* ```
|
|
87
87
|
*/
|
|
88
|
-
export const defineTable = <T extends Record<string, ColumnDef>>(
|
|
89
|
-
name: string,
|
|
90
|
-
columns: T,
|
|
91
|
-
relations: Record<string, RelationDef> = {},
|
|
92
|
-
hooks?: TableHooks,
|
|
93
|
-
options: TableOptions = {}
|
|
94
|
-
): TableDef<T> => {
|
|
88
|
+
export const defineTable = <T extends Record<string, ColumnDef>>(
|
|
89
|
+
name: string,
|
|
90
|
+
columns: T,
|
|
91
|
+
relations: Record<string, RelationDef> = {},
|
|
92
|
+
hooks?: TableHooks,
|
|
93
|
+
options: TableOptions = {}
|
|
94
|
+
): TableDef<T> => {
|
|
95
95
|
// Runtime mutability to assign names to column definitions for convenience
|
|
96
96
|
const colsWithNames = Object.entries(columns).reduce((acc, [key, def]) => {
|
|
97
97
|
const colDef = { ...def, name: key, table: name };
|
|
@@ -112,8 +112,21 @@ export const defineTable = <T extends Record<string, ColumnDef>>(
|
|
|
112
112
|
engine: options.engine,
|
|
113
113
|
charset: options.charset,
|
|
114
114
|
collation: options.collation
|
|
115
|
-
};
|
|
116
|
-
};
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Assigns relations to a table definition while preserving literal typing.
|
|
120
|
+
*/
|
|
121
|
+
export function setRelations<
|
|
122
|
+
TTable extends TableDef,
|
|
123
|
+
TRelations extends Record<string, RelationDef>
|
|
124
|
+
>(
|
|
125
|
+
table: TTable,
|
|
126
|
+
relations: TRelations
|
|
127
|
+
): asserts table is TTable & { relations: TRelations } {
|
|
128
|
+
table.relations = relations;
|
|
129
|
+
}
|
|
117
130
|
|
|
118
131
|
type DirectColumnKeys<T extends TableDef> =
|
|
119
132
|
Exclude<keyof T["columns"] & string, keyof T | "$">;
|
package/src/schema/types.ts
CHANGED
|
@@ -1,111 +1,130 @@
|
|
|
1
|
-
import type { ColumnDef } from './column-types.js';
|
|
2
|
-
export type { ColumnDef };
|
|
3
|
-
import { TableDef } from './table.js';
|
|
4
|
-
import {
|
|
5
|
-
RelationDef,
|
|
6
|
-
HasManyRelation,
|
|
7
|
-
HasOneRelation,
|
|
8
|
-
BelongsToRelation,
|
|
9
|
-
BelongsToManyRelation
|
|
10
|
-
} from './relation.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Resolves a relation definition to its target table type.
|
|
14
|
-
*/
|
|
1
|
+
import type { ColumnDef } from './column-types.js';
|
|
2
|
+
export type { ColumnDef };
|
|
3
|
+
import { TableDef } from './table.js';
|
|
4
|
+
import {
|
|
5
|
+
RelationDef,
|
|
6
|
+
HasManyRelation,
|
|
7
|
+
HasOneRelation,
|
|
8
|
+
BelongsToRelation,
|
|
9
|
+
BelongsToManyRelation
|
|
10
|
+
} from './relation.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Resolves a relation definition to its target table type.
|
|
14
|
+
*/
|
|
15
15
|
export type RelationTargetTable<TRel extends RelationDef> =
|
|
16
16
|
TRel extends HasManyRelation<infer TTarget> ? TTarget :
|
|
17
17
|
TRel extends HasOneRelation<infer TTarget> ? TTarget :
|
|
18
18
|
TRel extends BelongsToRelation<infer TTarget> ? TTarget :
|
|
19
|
-
TRel extends BelongsToManyRelation<infer TTarget> ? TTarget :
|
|
19
|
+
TRel extends BelongsToManyRelation<infer TTarget, TableDef> ? TTarget :
|
|
20
20
|
never;
|
|
21
|
-
|
|
22
|
-
type NormalizedColumnType<T extends ColumnDef> = Lowercase<T['type'] & string>;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Maps a ColumnDef to its TypeScript type representation
|
|
26
|
-
*/
|
|
27
|
-
export type ColumnToTs<T extends ColumnDef> =
|
|
28
|
-
[unknown] extends [T['tsType']]
|
|
29
|
-
? NormalizedColumnType<T> extends 'int' | 'integer' ? number :
|
|
30
|
-
NormalizedColumnType<T> extends 'bigint' ? number | bigint :
|
|
31
|
-
NormalizedColumnType<T> extends 'decimal' | 'float' | 'double' ? number :
|
|
32
|
-
NormalizedColumnType<T> extends 'boolean' ? boolean :
|
|
33
|
-
NormalizedColumnType<T> extends 'json' ? unknown :
|
|
34
|
-
NormalizedColumnType<T> extends 'blob' | 'binary' | 'varbinary' | 'bytea' ? Buffer :
|
|
35
|
-
NormalizedColumnType<T> extends 'date' | 'datetime' | 'timestamp' | 'timestamptz' ? string :
|
|
36
|
-
string
|
|
37
|
-
: Exclude<T['tsType'], undefined>;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Infers a row shape from a table definition
|
|
41
|
-
*/
|
|
42
|
-
export type InferRow<TTable extends TableDef> = {
|
|
43
|
-
[K in keyof TTable['columns']]: ColumnToTs<TTable['columns'][K]>;
|
|
44
|
-
};
|
|
45
|
-
|
|
21
|
+
|
|
22
|
+
type NormalizedColumnType<T extends ColumnDef> = Lowercase<T['type'] & string>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Maps a ColumnDef to its TypeScript type representation
|
|
26
|
+
*/
|
|
27
|
+
export type ColumnToTs<T extends ColumnDef> =
|
|
28
|
+
[unknown] extends [T['tsType']]
|
|
29
|
+
? NormalizedColumnType<T> extends 'int' | 'integer' ? number :
|
|
30
|
+
NormalizedColumnType<T> extends 'bigint' ? number | bigint :
|
|
31
|
+
NormalizedColumnType<T> extends 'decimal' | 'float' | 'double' ? number :
|
|
32
|
+
NormalizedColumnType<T> extends 'boolean' ? boolean :
|
|
33
|
+
NormalizedColumnType<T> extends 'json' ? unknown :
|
|
34
|
+
NormalizedColumnType<T> extends 'blob' | 'binary' | 'varbinary' | 'bytea' ? Buffer :
|
|
35
|
+
NormalizedColumnType<T> extends 'date' | 'datetime' | 'timestamp' | 'timestamptz' ? string :
|
|
36
|
+
string
|
|
37
|
+
: Exclude<T['tsType'], undefined>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Infers a row shape from a table definition
|
|
41
|
+
*/
|
|
42
|
+
export type InferRow<TTable extends TableDef> = {
|
|
43
|
+
[K in keyof TTable['columns']]: ColumnToTs<TTable['columns'][K]>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
46
|
type RelationResult<T extends RelationDef> =
|
|
47
47
|
T extends HasManyRelation<infer TTarget> ? InferRow<TTarget>[] :
|
|
48
48
|
T extends HasOneRelation<infer TTarget> ? InferRow<TTarget> | null :
|
|
49
49
|
T extends BelongsToRelation<infer TTarget> ? InferRow<TTarget> | null :
|
|
50
|
-
T extends BelongsToManyRelation<infer TTarget> ? (InferRow<TTarget> & { _pivot?: unknown })[] :
|
|
50
|
+
T extends BelongsToManyRelation<infer TTarget, TableDef> ? (InferRow<TTarget> & { _pivot?: Record<string, unknown> })[] :
|
|
51
51
|
never;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Maps relation names to the expected row results
|
|
55
|
-
*/
|
|
56
|
-
export type RelationMap<TTable extends TableDef> = {
|
|
57
|
-
[K in keyof TTable['relations']]: RelationResult<TTable['relations'][K]>;
|
|
58
|
-
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Maps relation names to the expected row results
|
|
55
|
+
*/
|
|
56
|
+
export type RelationMap<TTable extends TableDef> = {
|
|
57
|
+
[K in keyof TTable['relations']]: RelationResult<TTable['relations'][K]>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type RelationWrapper<TRel extends RelationDef> =
|
|
61
|
+
TRel extends HasManyRelation<infer TTarget>
|
|
62
|
+
? HasManyCollection<EntityInstance<TTarget>> & ReadonlyArray<EntityInstance<TTarget>>
|
|
63
|
+
: TRel extends HasOneRelation<infer TTarget>
|
|
64
|
+
? HasOneReference<EntityInstance<TTarget>>
|
|
65
|
+
: TRel extends BelongsToManyRelation<infer TTarget>
|
|
66
|
+
? ManyToManyCollection<EntityInstance<TTarget> & { _pivot?: Record<string, unknown> }>
|
|
67
|
+
& ReadonlyArray<EntityInstance<TTarget> & { _pivot?: Record<string, unknown> }>
|
|
68
|
+
: TRel extends BelongsToRelation<infer TTarget>
|
|
69
|
+
? BelongsToReference<EntityInstance<TTarget>>
|
|
70
|
+
: never;
|
|
59
71
|
|
|
60
72
|
export interface HasManyCollection<TChild> {
|
|
73
|
+
length: number;
|
|
74
|
+
[Symbol.iterator](): Iterator<TChild>;
|
|
61
75
|
load(): Promise<TChild[]>;
|
|
62
76
|
getItems(): TChild[];
|
|
63
77
|
add(data: Partial<TChild>): TChild;
|
|
64
78
|
attach(entity: TChild): void;
|
|
65
79
|
remove(entity: TChild): void;
|
|
66
|
-
clear(): void;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface
|
|
70
|
-
load(): Promise<TParent | null>;
|
|
71
|
-
get(): TParent | null;
|
|
72
|
-
set(data: Partial<TParent> | TParent | null): TParent | null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
clear(): void;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface BelongsToReferenceApi<TParent extends object = object> {
|
|
84
|
+
load(): Promise<TParent | null>;
|
|
85
|
+
get(): TParent | null;
|
|
86
|
+
set(data: Partial<TParent> | TParent | null): TParent | null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type BelongsToReference<TParent extends object = object> = BelongsToReferenceApi<TParent> & Partial<TParent>;
|
|
90
|
+
|
|
91
|
+
export interface HasOneReferenceApi<TChild extends object = object> {
|
|
92
|
+
load(): Promise<TChild | null>;
|
|
93
|
+
get(): TChild | null;
|
|
94
|
+
set(data: Partial<TChild> | TChild | null): TChild | null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type HasOneReference<TChild extends object = object> = HasOneReferenceApi<TChild> & Partial<TChild>;
|
|
98
|
+
|
|
99
|
+
export interface ManyToManyCollection<TTarget, TPivot extends object | undefined = undefined> {
|
|
100
|
+
length: number;
|
|
101
|
+
[Symbol.iterator](): Iterator<TTarget>;
|
|
82
102
|
load(): Promise<TTarget[]>;
|
|
83
103
|
getItems(): TTarget[];
|
|
84
104
|
attach(target: TTarget | number | string): void;
|
|
85
105
|
detach(target: TTarget | number | string): void;
|
|
86
106
|
syncByIds(ids: (number | string)[]): Promise<void>;
|
|
107
|
+
/** @internal Type-level marker for the related pivot entity */
|
|
108
|
+
readonly __pivotType?: TPivot;
|
|
87
109
|
}
|
|
88
|
-
|
|
89
|
-
export type EntityInstance<
|
|
90
|
-
TTable extends TableDef,
|
|
91
|
-
TRow = InferRow<TTable>
|
|
92
|
-
> = TRow & {
|
|
93
|
-
[K in keyof RelationMap<TTable>]:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
: TTable['relations'][K] extends BelongsToManyRelation<infer TTarget>
|
|
99
|
-
? ManyToManyCollection<EntityInstance<TTarget>>
|
|
100
|
-
: TTable['relations'][K] extends BelongsToRelation<infer TTarget>
|
|
101
|
-
? BelongsToReference<EntityInstance<TTarget>>
|
|
102
|
-
: never;
|
|
103
|
-
} & {
|
|
104
|
-
$load<K extends keyof RelationMap<TTable>>(relation: K): Promise<RelationMap<TTable>[K]>;
|
|
105
|
-
};
|
|
106
|
-
|
|
110
|
+
|
|
111
|
+
export type EntityInstance<
|
|
112
|
+
TTable extends TableDef,
|
|
113
|
+
TRow = InferRow<TTable>
|
|
114
|
+
> = TRow & {
|
|
115
|
+
[K in keyof RelationMap<TTable>]: RelationWrapper<TTable['relations'][K]>;
|
|
116
|
+
} & {
|
|
117
|
+
$load<K extends keyof RelationMap<TTable>>(relation: K): Promise<RelationMap<TTable>[K]>;
|
|
118
|
+
};
|
|
119
|
+
|
|
107
120
|
export type Primitive = string | number | boolean | Date | bigint | Buffer | null | undefined;
|
|
108
121
|
|
|
122
|
+
type IsAny<T> = 0 extends (1 & T) ? true : false;
|
|
123
|
+
|
|
109
124
|
export type SelectableKeys<T> = {
|
|
110
|
-
[K in keyof T]-?:
|
|
125
|
+
[K in keyof T]-?: IsAny<T[K]> extends true
|
|
126
|
+
? never
|
|
127
|
+
: NonNullable<T[K]> extends Primitive
|
|
128
|
+
? K
|
|
129
|
+
: never
|
|
111
130
|
}[keyof T];
|