metal-orm 1.0.35 → 1.0.37
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 +3 -0
- package/dist/index.cjs +31 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -5
- package/dist/index.d.ts +10 -5
- package/dist/index.js +31 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/decorators/bootstrap.ts +3 -3
- package/src/decorators/column.ts +3 -1
- package/src/orm/entity-metadata.ts +16 -9
- package/src/orm/entity.ts +7 -4
- package/src/orm/orm-session.ts +36 -11
- package/src/schema/types.ts +1 -1
package/package.json
CHANGED
|
@@ -119,16 +119,16 @@ export const bootstrapEntities = (): TableDef[] => {
|
|
|
119
119
|
return metas.map(meta => meta.table!) as TableDef[];
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
-
export const getTableDefFromEntity = (ctor: EntityConstructor):
|
|
122
|
+
export const getTableDefFromEntity = <TTable extends TableDef = TableDef>(ctor: EntityConstructor): TTable | undefined => {
|
|
123
123
|
const meta = getEntityMetadata(ctor);
|
|
124
124
|
if (!meta) return undefined;
|
|
125
125
|
if (!meta.table) {
|
|
126
126
|
bootstrapEntities();
|
|
127
127
|
}
|
|
128
|
-
return meta.table;
|
|
128
|
+
return meta.table as TTable;
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
-
export const selectFromEntity = <TTable extends TableDef>(
|
|
131
|
+
export const selectFromEntity = <TTable extends TableDef = TableDef>(
|
|
132
132
|
ctor: EntityConstructor
|
|
133
133
|
): SelectQueryBuilder<any, TTable> => {
|
|
134
134
|
const table = getTableDefFromEntity(ctor);
|
package/src/decorators/column.ts
CHANGED
|
@@ -18,9 +18,10 @@ export interface ColumnOptions {
|
|
|
18
18
|
args?: ColumnDef['args'];
|
|
19
19
|
notNull?: boolean;
|
|
20
20
|
primary?: boolean;
|
|
21
|
+
tsType?: ColumnDef['tsType'];
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export type ColumnInput = ColumnOptions | ColumnDef
|
|
24
|
+
export type ColumnInput = ColumnOptions | ColumnDef<any, any>;
|
|
24
25
|
|
|
25
26
|
const normalizeColumnInput = (input: ColumnInput): ColumnDefLike => {
|
|
26
27
|
const asOptions = input as ColumnOptions;
|
|
@@ -30,6 +31,7 @@ const normalizeColumnInput = (input: ColumnInput): ColumnDefLike => {
|
|
|
30
31
|
args: asOptions.args ?? asDefinition.args,
|
|
31
32
|
notNull: asOptions.notNull ?? asDefinition.notNull,
|
|
32
33
|
primary: asOptions.primary ?? asDefinition.primary,
|
|
34
|
+
tsType: asDefinition.tsType ?? asOptions.tsType,
|
|
33
35
|
unique: asDefinition.unique,
|
|
34
36
|
default: asDefinition.default,
|
|
35
37
|
autoIncrement: asDefinition.autoIncrement,
|
|
@@ -6,7 +6,14 @@ export type EntityConstructor = new (...args: any[]) => any;
|
|
|
6
6
|
export type EntityOrTableTarget = EntityConstructor | TableDef;
|
|
7
7
|
export type EntityOrTableTargetResolver = EntityOrTableTarget | (() => EntityOrTableTarget);
|
|
8
8
|
|
|
9
|
-
export type ColumnDefLike = Omit<
|
|
9
|
+
export type ColumnDefLike<T extends ColumnDef = ColumnDef> = Omit<T, 'name' | 'table'>;
|
|
10
|
+
|
|
11
|
+
type MaterializeColumns<TColumns extends Record<string, ColumnDefLike>> = {
|
|
12
|
+
[K in keyof TColumns]: ColumnDef<TColumns[K]['type'], TColumns[K]['tsType']> & Omit<
|
|
13
|
+
TColumns[K],
|
|
14
|
+
'name' | 'table' | 'type' | 'tsType'
|
|
15
|
+
> & { name: string; table: string };
|
|
16
|
+
};
|
|
10
17
|
|
|
11
18
|
interface BaseRelationMetadata {
|
|
12
19
|
propertyKey: string;
|
|
@@ -49,13 +56,13 @@ export type RelationMetadata =
|
|
|
49
56
|
| BelongsToRelationMetadata
|
|
50
57
|
| BelongsToManyRelationMetadata;
|
|
51
58
|
|
|
52
|
-
export interface EntityMetadata {
|
|
59
|
+
export interface EntityMetadata<TColumns extends Record<string, ColumnDefLike> = Record<string, ColumnDefLike>> {
|
|
53
60
|
target: EntityConstructor;
|
|
54
61
|
tableName: string;
|
|
55
|
-
columns:
|
|
62
|
+
columns: TColumns;
|
|
56
63
|
relations: Record<string, RelationMetadata>;
|
|
57
64
|
hooks?: TableHooks;
|
|
58
|
-
table?: TableDef
|
|
65
|
+
table?: TableDef<MaterializeColumns<TColumns>>;
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
const metadataMap = new Map<EntityConstructor, EntityMetadata>();
|
|
@@ -96,7 +103,7 @@ export const addColumnMetadata = (
|
|
|
96
103
|
column: ColumnDefLike
|
|
97
104
|
): void => {
|
|
98
105
|
const meta = ensureEntityMetadata(target);
|
|
99
|
-
meta.columns[propertyKey] = { ...column };
|
|
106
|
+
(meta.columns as Record<string, ColumnDefLike>)[propertyKey] = { ...column };
|
|
100
107
|
};
|
|
101
108
|
|
|
102
109
|
export const addRelationMetadata = (
|
|
@@ -122,19 +129,19 @@ export const setEntityTableName = (
|
|
|
122
129
|
}
|
|
123
130
|
};
|
|
124
131
|
|
|
125
|
-
export const buildTableDef = (meta: EntityMetadata): TableDef => {
|
|
132
|
+
export const buildTableDef = <TColumns extends Record<string, ColumnDefLike>>(meta: EntityMetadata<TColumns>): TableDef<MaterializeColumns<TColumns>> => {
|
|
126
133
|
if (meta.table) {
|
|
127
134
|
return meta.table;
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
const columns = Object.entries(meta.columns).reduce<
|
|
131
|
-
acc[key] = {
|
|
137
|
+
const columns = Object.entries(meta.columns).reduce<MaterializeColumns<TColumns>>((acc, [key, def]) => {
|
|
138
|
+
(acc as any)[key] = {
|
|
132
139
|
...def,
|
|
133
140
|
name: key,
|
|
134
141
|
table: meta.tableName
|
|
135
142
|
};
|
|
136
143
|
return acc;
|
|
137
|
-
}, {});
|
|
144
|
+
}, {} as MaterializeColumns<TColumns>);
|
|
138
145
|
|
|
139
146
|
const table = defineTable(meta.tableName, columns, {}, meta.hooks);
|
|
140
147
|
meta.table = table;
|
package/src/orm/entity.ts
CHANGED
|
@@ -104,17 +104,20 @@ export const createEntityProxy = <
|
|
|
104
104
|
return proxy;
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
export const createEntityFromRow = <
|
|
107
|
+
export const createEntityFromRow = <
|
|
108
|
+
TTable extends TableDef,
|
|
109
|
+
TResult extends EntityInstance<TTable> = EntityInstance<TTable>
|
|
110
|
+
>(
|
|
108
111
|
ctx: EntityContext,
|
|
109
112
|
table: TTable,
|
|
110
113
|
row: Record<string, any>,
|
|
111
114
|
lazyRelations: (keyof RelationMap<TTable>)[] = []
|
|
112
|
-
):
|
|
115
|
+
): TResult => {
|
|
113
116
|
const pkName = findPrimaryKey(table);
|
|
114
117
|
const pkValue = row[pkName];
|
|
115
118
|
if (pkValue !== undefined && pkValue !== null) {
|
|
116
119
|
const tracked = ctx.getEntity(table, pkValue);
|
|
117
|
-
if (tracked) return tracked;
|
|
120
|
+
if (tracked) return tracked as TResult;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
const entity = createEntityProxy(ctx, table, row, lazyRelations);
|
|
@@ -124,7 +127,7 @@ export const createEntityFromRow = <TTable extends TableDef>(
|
|
|
124
127
|
ctx.trackNew(table, entity);
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
return entity;
|
|
130
|
+
return entity as TResult;
|
|
128
131
|
};
|
|
129
132
|
|
|
130
133
|
const toKey = (value: unknown): string => (value === null || value === undefined ? '' : String(value));
|
package/src/orm/orm-session.ts
CHANGED
|
@@ -185,24 +185,49 @@ export class OrmSession<E extends DomainEvent = OrmDomainEvent> implements Entit
|
|
|
185
185
|
await this.unitOfWork.flush();
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
async
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
private async flushWithHooks(): Promise<void> {
|
|
189
|
+
for (const interceptor of this.interceptors) {
|
|
190
|
+
await interceptor.beforeFlush?.(this);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
await this.unitOfWork.flush();
|
|
194
|
+
await this.relationChanges.process();
|
|
195
|
+
await this.unitOfWork.flush();
|
|
193
196
|
|
|
194
|
-
|
|
195
|
-
await
|
|
196
|
-
|
|
197
|
+
for (const interceptor of this.interceptors) {
|
|
198
|
+
await interceptor.afterFlush?.(this);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
197
201
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
202
|
+
async commit(): Promise<void> {
|
|
203
|
+
await runInTransaction(this.executor, async () => {
|
|
204
|
+
await this.flushWithHooks();
|
|
201
205
|
});
|
|
202
206
|
|
|
203
207
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
204
208
|
}
|
|
205
209
|
|
|
210
|
+
async transaction<T>(fn: (session: OrmSession<E>) => Promise<T>): Promise<T> {
|
|
211
|
+
// If the executor can't do transactions, just run and commit once.
|
|
212
|
+
if (!this.executor.beginTransaction) {
|
|
213
|
+
const result = await fn(this);
|
|
214
|
+
await this.commit();
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await this.executor.beginTransaction();
|
|
219
|
+
try {
|
|
220
|
+
const result = await fn(this);
|
|
221
|
+
await this.flushWithHooks();
|
|
222
|
+
await this.executor.commitTransaction?.();
|
|
223
|
+
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
224
|
+
return result;
|
|
225
|
+
} catch (err) {
|
|
226
|
+
await this.rollback();
|
|
227
|
+
throw err;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
206
231
|
async rollback(): Promise<void> {
|
|
207
232
|
await this.executor.rollbackTransaction?.();
|
|
208
233
|
this.unitOfWork.reset();
|
package/src/schema/types.ts
CHANGED
|
@@ -22,7 +22,7 @@ export type RelationTargetTable<TRel extends RelationDef> =
|
|
|
22
22
|
* Maps a ColumnDef to its TypeScript type representation
|
|
23
23
|
*/
|
|
24
24
|
export type ColumnToTs<T extends ColumnDef> =
|
|
25
|
-
T['tsType']
|
|
25
|
+
[unknown] extends [T['tsType']]
|
|
26
26
|
? T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number :
|
|
27
27
|
T['type'] extends 'BIGINT' | 'bigint' ? number | bigint :
|
|
28
28
|
T['type'] extends 'DECIMAL' | 'decimal' | 'FLOAT' | 'float' | 'DOUBLE' | 'double' ? number :
|