@tstdl/base 0.92.85 → 0.92.86
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/ai/ai.service.d.ts +1 -1
- package/ai/ai.service.js +3 -3
- package/ai/types.d.ts +1 -1
- package/authentication/authentication.api.d.ts +9 -9
- package/authentication/models/schemas.d.ts +2 -2
- package/cancellation/token.d.ts +1 -1
- package/document-management/api/document-management.api.d.ts +94 -94
- package/document-management/models/document-category.model.d.ts +1 -0
- package/document-management/models/document-index.model.d.ts +7 -0
- package/document-management/models/document-index.model.js +32 -0
- package/document-management/models/document-request-file.model.d.ts +1 -1
- package/document-management/models/document-request-file.model.js +2 -2
- package/document-management/models/document-type.model.d.ts +1 -0
- package/document-management/models/document.model.d.ts +1 -1
- package/document-management/models/document.model.js +2 -2
- package/document-management/models/service-models/document.service-model.d.ts +51 -51
- package/document-management/models/service-models/document.service-model.js +2 -2
- package/document-management/server/drizzle/{0000_sloppy_fenris.sql → 0000_useful_overlord.sql} +2 -2
- package/document-management/server/drizzle/meta/0000_snapshot.json +5 -5
- package/document-management/server/drizzle/meta/_journal.json +2 -2
- package/document-management/server/drizzle.config.js +1 -1
- package/document-management/server/module.d.ts +1 -1
- package/document-management/server/module.js +1 -1
- package/document-management/server/schemas.d.ts +33 -0
- package/document-management/{models → server}/schemas.js +14 -14
- package/document-management/server/services/document-management.service.d.ts +17 -3
- package/document-management/server/services/document-management.service.js +65 -17
- package/examples/orm/schemas.d.ts +1 -1
- package/mail/drizzle.config.js +1 -1
- package/mail/models/schemas.d.ts +1 -1
- package/orm/decorators.d.ts +4 -4
- package/orm/entity.d.ts +5 -7
- package/orm/entity.js +9 -1
- package/orm/index.d.ts +1 -0
- package/orm/index.js +1 -0
- package/orm/query.d.ts +1 -3
- package/orm/query.js +0 -1
- package/orm/repository.types.d.ts +32 -0
- package/orm/repository.types.js +1 -0
- package/orm/server/database-schema.d.ts +4 -4
- package/orm/server/drizzle/schema-converter.d.ts +1 -1
- package/orm/server/index.d.ts +1 -0
- package/orm/server/index.js +1 -0
- package/orm/server/query-converter.d.ts +1 -2
- package/orm/server/query-converter.js +66 -61
- package/orm/server/repository.d.ts +78 -42
- package/orm/server/repository.js +202 -106
- package/orm/server/sqls.d.ts +7 -0
- package/orm/server/sqls.js +6 -0
- package/orm/server/types.d.ts +3 -3
- package/orm/types.d.ts +1 -1
- package/package.json +11 -9
- package/queue/enqueue-batch.d.ts +1 -0
- package/queue/enqueue-batch.js +1 -1
- package/queue/mongo/queue.d.ts +9 -4
- package/queue/mongo/queue.js +5 -6
- package/queue/postgres/drizzle/0000_zippy_moondragon.sql +11 -0
- package/queue/postgres/drizzle/meta/0000_snapshot.json +90 -0
- package/queue/postgres/drizzle/meta/_journal.json +13 -0
- package/queue/postgres/drizzle.config.d.ts +2 -0
- package/queue/postgres/drizzle.config.js +11 -0
- package/queue/postgres/index.d.ts +4 -0
- package/queue/postgres/index.js +4 -0
- package/queue/postgres/job.model.d.ts +13 -0
- package/queue/postgres/job.model.js +55 -0
- package/queue/postgres/module.d.ts +9 -0
- package/queue/postgres/module.js +29 -0
- package/queue/postgres/queue.d.ts +28 -0
- package/queue/postgres/queue.js +149 -0
- package/queue/postgres/queue.provider.d.ts +7 -0
- package/queue/postgres/queue.provider.js +21 -0
- package/queue/postgres/schemas.d.ts +3 -0
- package/queue/postgres/schemas.js +4 -0
- package/queue/provider.d.ts +2 -1
- package/queue/queue.d.ts +18 -6
- package/schema/schemas/object.d.ts +1 -1
- package/utils/timing.d.ts +4 -3
- package/utils/timing.js +3 -1
- package/document-management/models/schemas.d.ts +0 -33
package/orm/server/repository.js
CHANGED
|
@@ -8,7 +8,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
8
8
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
|
-
import { count, eq, inArray, sql } from 'drizzle-orm';
|
|
11
|
+
import { asc, count, desc, eq, inArray, isSQLWrapper, SQL, sql } from 'drizzle-orm';
|
|
12
12
|
import { PgTransaction as DrizzlePgTransaction } from 'drizzle-orm/pg-core';
|
|
13
13
|
import { createContextProvider } from '../../context/context.js';
|
|
14
14
|
import { NotFoundError } from '../../errors/not-found.error.js';
|
|
@@ -21,11 +21,14 @@ import { toArray } from '../../utils/array/array.js';
|
|
|
21
21
|
import { mapAsync } from '../../utils/async-iterable-helpers/map.js';
|
|
22
22
|
import { toArrayAsync } from '../../utils/async-iterable-helpers/to-array.js';
|
|
23
23
|
import { importSymmetricKey } from '../../utils/cryptography.js';
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
24
|
+
import { typeExtends } from '../../utils/index.js';
|
|
25
|
+
import { fromDeepObjectEntries, objectEntries } from '../../utils/object/object.js';
|
|
26
|
+
import { assertDefinedPass, isArray, isDefined, isUndefined } from '../../utils/type-guards.js';
|
|
27
|
+
import { Entity } from '../entity.js';
|
|
26
28
|
import { Database } from './database.js';
|
|
27
29
|
import { getColumnDefinitions, getDrizzleTableFromType } from './drizzle/schema-converter.js';
|
|
28
30
|
import { convertQuery } from './query-converter.js';
|
|
31
|
+
import { TRANSACTION_TIMESTAMP } from './sqls.js';
|
|
29
32
|
import { ENCRYPTION_SECRET } from './tokens.js';
|
|
30
33
|
import { DrizzleTransaction } from './transaction.js';
|
|
31
34
|
export const repositoryType = Symbol('repositoryType');
|
|
@@ -33,30 +36,28 @@ export class EntityRepositoryConfig {
|
|
|
33
36
|
schema;
|
|
34
37
|
}
|
|
35
38
|
const entityTypeToken = Symbol('EntityType');
|
|
36
|
-
const TRANSACTION_TIMESTAMP = sql `transaction_timestamp()`;
|
|
37
39
|
const { getCurrentEntityRepositoryContext, runInEntityRepositoryContext, isInEntityRepositoryContext } = createContextProvider('EntityRepository');
|
|
38
40
|
let EntityRepository = class EntityRepository {
|
|
39
41
|
#injector = inject(Injector);
|
|
40
42
|
#repositoryConstructor;
|
|
41
43
|
#withTransactionCache = new WeakMap();
|
|
42
44
|
#encryptionSecret = isInEntityRepositoryContext() ? getCurrentEntityRepositoryContext()?.encryptionSecret : inject(ENCRYPTION_SECRET, undefined, { optional: true });
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
#context = getCurrentEntityRepositoryContext() ?? {};
|
|
46
|
+
#transformContext = this.#context.transformContext;
|
|
47
|
+
type = this.#context.type ?? injectArgument(this, { optional: true }) ?? assertDefinedPass(this.constructor[entityTypeToken], 'Missing entity type.');
|
|
48
|
+
typeName = this.type.entityName ?? this.type.name;
|
|
49
|
+
#table = this.#context.table ?? getDrizzleTableFromType(this.type, inject(EntityRepositoryConfig).schema);
|
|
50
|
+
#tableWithMetadata = this.#table;
|
|
51
|
+
#columnDefinitions = this.#context.columnDefinitions ?? getColumnDefinitions(this.#table);
|
|
52
|
+
#columnDefinitionsMap = this.#context.columnDefinitionsMap ?? new Map(this.#columnDefinitions.map((column) => [column.objectPath.path, column]));
|
|
53
|
+
session = this.#context.session ?? inject(Database);
|
|
54
|
+
isInTransaction = this.session instanceof DrizzlePgTransaction;
|
|
55
|
+
hasMetadata = typeExtends(this.type, Entity);
|
|
56
|
+
get table() {
|
|
57
|
+
return this.#table;
|
|
58
|
+
}
|
|
50
59
|
constructor() {
|
|
51
60
|
this.#repositoryConstructor = new.target;
|
|
52
|
-
const { type, table, columnDefinitions, columnDefinitionsMap, session, transformContext } = getCurrentEntityRepositoryContext() ?? {};
|
|
53
|
-
this.type = type ?? injectArgument(this, { optional: true }) ?? assertDefinedPass(new.target[entityTypeToken], 'Missing entity type.');
|
|
54
|
-
this.table = table ?? getDrizzleTableFromType(this.type, inject(EntityRepositoryConfig).schema);
|
|
55
|
-
this.columnDefinitions = columnDefinitions ?? getColumnDefinitions(this.table);
|
|
56
|
-
this.columnDefinitionsMap = columnDefinitionsMap ?? new Map(this.columnDefinitions.map((column) => [column.objectPath.path, column]));
|
|
57
|
-
this.session = session ?? inject(Database);
|
|
58
|
-
this.isInTransaction = this.session instanceof DrizzlePgTransaction;
|
|
59
|
-
this.#transformContext = transformContext;
|
|
60
61
|
}
|
|
61
62
|
withOptionalTransaction(transaction) {
|
|
62
63
|
if (isUndefined(transaction)) {
|
|
@@ -70,9 +71,9 @@ let EntityRepository = class EntityRepository {
|
|
|
70
71
|
}
|
|
71
72
|
const context = {
|
|
72
73
|
type: this.type,
|
|
73
|
-
table: this
|
|
74
|
-
columnDefinitions: this
|
|
75
|
-
columnDefinitionsMap: this
|
|
74
|
+
table: this.#table,
|
|
75
|
+
columnDefinitions: this.#columnDefinitions,
|
|
76
|
+
columnDefinitionsMap: this.#columnDefinitionsMap,
|
|
76
77
|
session: transaction.transaction,
|
|
77
78
|
encryptionSecret: this.#encryptionSecret,
|
|
78
79
|
transformContext: this.#transformContext
|
|
@@ -99,26 +100,30 @@ let EntityRepository = class EntityRepository {
|
|
|
99
100
|
async load(id) {
|
|
100
101
|
const entity = await this.tryLoad(id);
|
|
101
102
|
if (isUndefined(entity)) {
|
|
102
|
-
throw new NotFoundError(`${this.
|
|
103
|
+
throw new NotFoundError(`${this.typeName} ${id} not found.`);
|
|
103
104
|
}
|
|
104
105
|
return entity;
|
|
105
106
|
}
|
|
106
107
|
async tryLoad(id) {
|
|
107
|
-
return this.tryLoadByQuery(eq(this
|
|
108
|
+
return this.tryLoadByQuery(eq(this.#table.id, id));
|
|
108
109
|
}
|
|
109
110
|
async loadByQuery(query, options) {
|
|
110
111
|
const entity = await this.tryLoadByQuery(query, options);
|
|
111
112
|
if (isUndefined(entity)) {
|
|
112
|
-
throw new NotFoundError(`${this.
|
|
113
|
+
throw new NotFoundError(`${this.typeName} not found.`);
|
|
113
114
|
}
|
|
114
115
|
return entity;
|
|
115
116
|
}
|
|
116
117
|
async tryLoadByQuery(query, options) {
|
|
117
|
-
const sqlQuery = this
|
|
118
|
-
|
|
119
|
-
.from(this
|
|
118
|
+
const sqlQuery = this.$convertQuery(query);
|
|
119
|
+
let dbQuery = this.session.select()
|
|
120
|
+
.from(this.#table)
|
|
120
121
|
.where(sqlQuery)
|
|
121
|
-
.offset(options?.offset)
|
|
122
|
+
.offset(options?.offset)
|
|
123
|
+
.$dynamic();
|
|
124
|
+
if (isDefined(options?.order)) {
|
|
125
|
+
dbQuery = dbQuery.orderBy(...this.$convertOrderBy(options.order));
|
|
126
|
+
}
|
|
122
127
|
const [row] = await dbQuery;
|
|
123
128
|
if (isUndefined(row)) {
|
|
124
129
|
return undefined;
|
|
@@ -127,19 +132,25 @@ let EntityRepository = class EntityRepository {
|
|
|
127
132
|
return this.mapToEntity(row, transformContext);
|
|
128
133
|
}
|
|
129
134
|
async loadMany(ids, options) {
|
|
130
|
-
return this.loadManyByQuery(inArray(this
|
|
135
|
+
return this.loadManyByQuery(inArray(this.#table.id, ids), options);
|
|
131
136
|
}
|
|
132
137
|
async *loadManyCursor(ids, options) {
|
|
133
138
|
const entities = await this.loadMany(ids, options);
|
|
134
139
|
yield* entities;
|
|
135
140
|
}
|
|
136
141
|
async loadManyByQuery(query, options) {
|
|
137
|
-
const sqlQuery = this
|
|
138
|
-
|
|
139
|
-
.from(this
|
|
142
|
+
const sqlQuery = this.$convertQuery(query);
|
|
143
|
+
let dbQuery = this.session.select()
|
|
144
|
+
.from(this.#table)
|
|
140
145
|
.where(sqlQuery)
|
|
146
|
+
.orderBy()
|
|
141
147
|
.offset(options?.offset)
|
|
142
|
-
.limit(options?.limit)
|
|
148
|
+
.limit(options?.limit)
|
|
149
|
+
.$dynamic();
|
|
150
|
+
if (isDefined(options?.order)) {
|
|
151
|
+
dbQuery = dbQuery.orderBy(...this.$convertOrderBy(options.order));
|
|
152
|
+
}
|
|
153
|
+
const rows = await dbQuery;
|
|
143
154
|
const transformContext = await this.getTransformContext();
|
|
144
155
|
return this.mapManyToEntity(rows, transformContext);
|
|
145
156
|
}
|
|
@@ -157,34 +168,34 @@ let EntityRepository = class EntityRepository {
|
|
|
157
168
|
async count() {
|
|
158
169
|
const dbQuery = this.session
|
|
159
170
|
.select({ count: count() })
|
|
160
|
-
.from(this
|
|
171
|
+
.from(this.#table);
|
|
161
172
|
const [result] = await dbQuery;
|
|
162
173
|
return assertDefinedPass(result).count;
|
|
163
174
|
}
|
|
164
175
|
async countByQuery(query) {
|
|
165
|
-
const sqlQuery = this
|
|
176
|
+
const sqlQuery = this.$convertQuery(query);
|
|
166
177
|
const dbQuery = this.session
|
|
167
178
|
.select({ count: count() })
|
|
168
|
-
.from(this
|
|
179
|
+
.from(this.#table)
|
|
169
180
|
.where(sqlQuery);
|
|
170
181
|
const [result] = await dbQuery;
|
|
171
182
|
return assertDefinedPass(result).count;
|
|
172
183
|
}
|
|
173
184
|
async has(id) {
|
|
174
|
-
return this.hasByQuery(eq(this
|
|
185
|
+
return this.hasByQuery(eq(this.#table.id, id));
|
|
175
186
|
}
|
|
176
187
|
async hasByQuery(query) {
|
|
177
|
-
const sqlQuery = this
|
|
188
|
+
const sqlQuery = this.$convertQuery(query);
|
|
178
189
|
const dbQuery = this.session
|
|
179
|
-
.select({ exists: sql `SELECT EXISTS(SELECT 1 FROM ${this
|
|
180
|
-
.from(this
|
|
190
|
+
.select({ exists: sql `SELECT EXISTS(SELECT 1 FROM ${this.#table} WHERE ${sqlQuery})` })
|
|
191
|
+
.from(this.#table);
|
|
181
192
|
const [result] = await dbQuery;
|
|
182
193
|
return assertDefinedPass(result).exists;
|
|
183
194
|
}
|
|
184
195
|
async hasAll(ids) {
|
|
185
196
|
const result = await this.session
|
|
186
|
-
.select({ contains: sql `array_agg(${this
|
|
187
|
-
.from(this
|
|
197
|
+
.select({ contains: sql `array_agg(${this.#table.id}) @> ${ids}`.as('contains') })
|
|
198
|
+
.from(this.#table);
|
|
188
199
|
return assertDefinedPass(result[0]).contains;
|
|
189
200
|
}
|
|
190
201
|
/**
|
|
@@ -196,7 +207,7 @@ let EntityRepository = class EntityRepository {
|
|
|
196
207
|
const transformContext = await this.getTransformContext();
|
|
197
208
|
const columns = await this.mapToInsertColumns(entity, transformContext);
|
|
198
209
|
const [row] = await this.session
|
|
199
|
-
.insert(this
|
|
210
|
+
.insert(this.#table)
|
|
200
211
|
.values(columns)
|
|
201
212
|
.onConflictDoNothing()
|
|
202
213
|
.returning();
|
|
@@ -209,7 +220,7 @@ let EntityRepository = class EntityRepository {
|
|
|
209
220
|
const transformContext = await this.getTransformContext();
|
|
210
221
|
const columns = await this.mapToInsertColumns(entity, transformContext);
|
|
211
222
|
const [row] = await this.session
|
|
212
|
-
.insert(this
|
|
223
|
+
.insert(this.#table)
|
|
213
224
|
.values(columns)
|
|
214
225
|
.returning();
|
|
215
226
|
return this.mapToEntity(row, transformContext);
|
|
@@ -217,19 +228,16 @@ let EntityRepository = class EntityRepository {
|
|
|
217
228
|
async insertMany(entities) {
|
|
218
229
|
const transformContext = await this.getTransformContext();
|
|
219
230
|
const columns = await this.mapManyToInsertColumns(entities, transformContext);
|
|
220
|
-
const rows = await this.session.insert(this
|
|
231
|
+
const rows = await this.session.insert(this.#table).values(columns).returning();
|
|
221
232
|
return this.mapManyToEntity(rows, transformContext);
|
|
222
233
|
}
|
|
223
234
|
async upsert(target, entity, update) {
|
|
224
235
|
const transformContext = await this.getTransformContext();
|
|
225
|
-
const targetColumns = toArray(target).map((path) =>
|
|
226
|
-
const columnName = assertDefinedPass(this.columnDefinitionsMap.get(path), `Could not map ${path} to column.`).name;
|
|
227
|
-
return this.table[columnName];
|
|
228
|
-
});
|
|
236
|
+
const targetColumns = toArray(target).map((path) => this.$getColumn(path));
|
|
229
237
|
const columns = await this.mapToInsertColumns(entity, transformContext);
|
|
230
238
|
const mappedUpdate = await this.mapUpdate(update ?? entity, transformContext);
|
|
231
239
|
const [row] = await this.session
|
|
232
|
-
.insert(this
|
|
240
|
+
.insert(this.#table)
|
|
233
241
|
.values(columns)
|
|
234
242
|
.onConflictDoUpdate({
|
|
235
243
|
target: targetColumns,
|
|
@@ -240,14 +248,11 @@ let EntityRepository = class EntityRepository {
|
|
|
240
248
|
}
|
|
241
249
|
async upsertMany(target, entities, update) {
|
|
242
250
|
const transformContext = await this.getTransformContext();
|
|
243
|
-
const targetColumns = toArray(target).map((path) =>
|
|
244
|
-
const columnName = assertDefinedPass(this.columnDefinitionsMap.get(path), `Could not map ${path} to column.`).name;
|
|
245
|
-
return this.table[columnName];
|
|
246
|
-
});
|
|
251
|
+
const targetColumns = toArray(target).map((path) => this.$getColumn(path));
|
|
247
252
|
const columns = await this.mapManyToColumns(entities, transformContext);
|
|
248
253
|
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
249
254
|
const rows = await this.session
|
|
250
|
-
.insert(this
|
|
255
|
+
.insert(this.#table)
|
|
251
256
|
.values(columns)
|
|
252
257
|
.onConflictDoUpdate({
|
|
253
258
|
target: targetColumns,
|
|
@@ -259,7 +264,7 @@ let EntityRepository = class EntityRepository {
|
|
|
259
264
|
async update(id, update) {
|
|
260
265
|
const entity = await this.tryUpdate(id, update);
|
|
261
266
|
if (isUndefined(entity)) {
|
|
262
|
-
throw new NotFoundError(`${this.
|
|
267
|
+
throw new NotFoundError(`${this.typeName} ${id} not found.`);
|
|
263
268
|
}
|
|
264
269
|
return entity;
|
|
265
270
|
}
|
|
@@ -267,9 +272,9 @@ let EntityRepository = class EntityRepository {
|
|
|
267
272
|
const transformContext = await this.getTransformContext();
|
|
268
273
|
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
269
274
|
const [row] = await this.session
|
|
270
|
-
.update(this
|
|
275
|
+
.update(this.#table)
|
|
271
276
|
.set(mappedUpdate)
|
|
272
|
-
.where(eq(this
|
|
277
|
+
.where(eq(this.#table.id, id))
|
|
273
278
|
.returning();
|
|
274
279
|
if (isUndefined(row)) {
|
|
275
280
|
return undefined;
|
|
@@ -279,7 +284,7 @@ let EntityRepository = class EntityRepository {
|
|
|
279
284
|
async updateByQuery(query, update) {
|
|
280
285
|
const entity = await this.tryUpdateByQuery(query, update);
|
|
281
286
|
if (isUndefined(entity)) {
|
|
282
|
-
throw new NotFoundError(`${this.
|
|
287
|
+
throw new NotFoundError(`${this.typeName} not found.`);
|
|
283
288
|
}
|
|
284
289
|
return entity;
|
|
285
290
|
}
|
|
@@ -288,9 +293,9 @@ let EntityRepository = class EntityRepository {
|
|
|
288
293
|
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
289
294
|
const idQuery = this.getIdLimitQuery(query);
|
|
290
295
|
const [row] = await this.session
|
|
291
|
-
.update(this
|
|
296
|
+
.update(this.#table)
|
|
292
297
|
.set(mappedUpdate)
|
|
293
|
-
.where(inArray(this
|
|
298
|
+
.where(inArray(this.#table.id, idQuery))
|
|
294
299
|
.returning();
|
|
295
300
|
if (isUndefined(row)) {
|
|
296
301
|
return undefined;
|
|
@@ -298,14 +303,14 @@ let EntityRepository = class EntityRepository {
|
|
|
298
303
|
return this.mapToEntity(row, transformContext);
|
|
299
304
|
}
|
|
300
305
|
async updateMany(ids, update) {
|
|
301
|
-
return this.updateManyByQuery(inArray(this
|
|
306
|
+
return this.updateManyByQuery(inArray(this.#table.id, ids), update);
|
|
302
307
|
}
|
|
303
308
|
async updateManyByQuery(query, update) {
|
|
304
309
|
const transformContext = await this.getTransformContext();
|
|
305
|
-
const sqlQuery = this
|
|
310
|
+
const sqlQuery = this.$convertQuery(query);
|
|
306
311
|
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
307
312
|
const rows = await this.session
|
|
308
|
-
.update(this
|
|
313
|
+
.update(this.#table)
|
|
309
314
|
.set(mappedUpdate)
|
|
310
315
|
.where(sqlQuery)
|
|
311
316
|
.returning();
|
|
@@ -314,18 +319,21 @@ let EntityRepository = class EntityRepository {
|
|
|
314
319
|
async delete(id, metadataUpdate) {
|
|
315
320
|
const entity = await this.tryDelete(id, metadataUpdate);
|
|
316
321
|
if (isUndefined(entity)) {
|
|
317
|
-
throw new NotFoundError(`${this.
|
|
322
|
+
throw new NotFoundError(`${this.typeName} ${id} not found.`);
|
|
318
323
|
}
|
|
319
324
|
return entity;
|
|
320
325
|
}
|
|
321
326
|
async tryDelete(id, metadataUpdate) {
|
|
327
|
+
if (!this.hasMetadata) {
|
|
328
|
+
return this.tryHardDelete(id);
|
|
329
|
+
}
|
|
322
330
|
const [row] = await this.session
|
|
323
|
-
.update(this
|
|
331
|
+
.update(this.#tableWithMetadata)
|
|
324
332
|
.set({
|
|
325
333
|
deleteTimestamp: TRANSACTION_TIMESTAMP,
|
|
326
334
|
attributes: this.getAttributesUpdate(metadataUpdate?.attributes)
|
|
327
335
|
})
|
|
328
|
-
.where(eq(this
|
|
336
|
+
.where(eq(this.#table.id, id))
|
|
329
337
|
.returning();
|
|
330
338
|
if (isUndefined(row)) {
|
|
331
339
|
return undefined;
|
|
@@ -336,19 +344,22 @@ let EntityRepository = class EntityRepository {
|
|
|
336
344
|
async deleteByQuery(query, metadataUpdate) {
|
|
337
345
|
const entity = await this.tryDeleteByQuery(query, metadataUpdate);
|
|
338
346
|
if (isUndefined(entity)) {
|
|
339
|
-
throw new NotFoundError(`${this.
|
|
347
|
+
throw new NotFoundError(`${this.typeName} not found.`);
|
|
340
348
|
}
|
|
341
349
|
return entity;
|
|
342
350
|
}
|
|
343
351
|
async tryDeleteByQuery(query, metadataUpdate) {
|
|
352
|
+
if (!this.hasMetadata) {
|
|
353
|
+
return this.tryHardDeleteByQuery(query);
|
|
354
|
+
}
|
|
344
355
|
const idQuery = this.getIdLimitQuery(query);
|
|
345
356
|
const [row] = await this.session
|
|
346
|
-
.update(this
|
|
357
|
+
.update(this.#tableWithMetadata)
|
|
347
358
|
.set({
|
|
348
359
|
deleteTimestamp: TRANSACTION_TIMESTAMP,
|
|
349
360
|
attributes: this.getAttributesUpdate(metadataUpdate?.attributes)
|
|
350
361
|
})
|
|
351
|
-
.where(inArray(this
|
|
362
|
+
.where(inArray(this.#table.id, idQuery))
|
|
352
363
|
.returning();
|
|
353
364
|
if (isUndefined(row)) {
|
|
354
365
|
return undefined;
|
|
@@ -357,12 +368,15 @@ let EntityRepository = class EntityRepository {
|
|
|
357
368
|
return this.mapToEntity(row, transformContext);
|
|
358
369
|
}
|
|
359
370
|
async deleteMany(ids, metadataUpdate) {
|
|
360
|
-
return this.deleteManyByQuery(inArray(this
|
|
371
|
+
return this.deleteManyByQuery(inArray(this.#table.id, ids), metadataUpdate);
|
|
361
372
|
}
|
|
362
373
|
async deleteManyByQuery(query, metadataUpdate) {
|
|
363
|
-
|
|
374
|
+
if (!this.hasMetadata) {
|
|
375
|
+
return this.hardDeleteManyByQuery(query);
|
|
376
|
+
}
|
|
377
|
+
const sqlQuery = this.$convertQuery(query);
|
|
364
378
|
const rows = await this.session
|
|
365
|
-
.update(this
|
|
379
|
+
.update(this.#tableWithMetadata)
|
|
366
380
|
.set({
|
|
367
381
|
deleteTimestamp: TRANSACTION_TIMESTAMP,
|
|
368
382
|
attributes: this.getAttributesUpdate(metadataUpdate?.attributes)
|
|
@@ -375,47 +389,115 @@ let EntityRepository = class EntityRepository {
|
|
|
375
389
|
async hardDelete(id) {
|
|
376
390
|
const result = await this.tryHardDelete(id);
|
|
377
391
|
if (!result) {
|
|
378
|
-
throw new NotFoundError(`${this.
|
|
392
|
+
throw new NotFoundError(`${this.typeName} ${id} not found.`);
|
|
379
393
|
}
|
|
394
|
+
return result;
|
|
380
395
|
}
|
|
381
396
|
async tryHardDelete(id) {
|
|
382
|
-
const
|
|
383
|
-
.delete(this
|
|
384
|
-
.where(eq(this
|
|
385
|
-
|
|
397
|
+
const [row] = await this.session
|
|
398
|
+
.delete(this.#table)
|
|
399
|
+
.where(eq(this.#table.id, id))
|
|
400
|
+
.returning();
|
|
401
|
+
if (isUndefined(row)) {
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
404
|
+
const transformContext = await this.getTransformContext();
|
|
405
|
+
return this.mapToEntity(row, transformContext);
|
|
386
406
|
}
|
|
387
407
|
async hardDeleteByQuery(query) {
|
|
388
408
|
const result = await this.tryHardDeleteByQuery(query);
|
|
389
409
|
if (!result) {
|
|
390
|
-
throw new NotFoundError(`${this.
|
|
410
|
+
throw new NotFoundError(`${this.typeName} not found.`);
|
|
391
411
|
}
|
|
412
|
+
return result;
|
|
392
413
|
}
|
|
393
414
|
async tryHardDeleteByQuery(query) {
|
|
394
415
|
const idQuery = this.getIdLimitQuery(query);
|
|
395
|
-
const
|
|
396
|
-
.delete(this
|
|
397
|
-
.where(inArray(this
|
|
398
|
-
|
|
416
|
+
const [row] = await this.session
|
|
417
|
+
.delete(this.#table)
|
|
418
|
+
.where(inArray(this.#table.id, idQuery))
|
|
419
|
+
.returning();
|
|
420
|
+
if (isUndefined(row)) {
|
|
421
|
+
return undefined;
|
|
422
|
+
}
|
|
423
|
+
const transformContext = await this.getTransformContext();
|
|
424
|
+
return this.mapToEntity(row, transformContext);
|
|
399
425
|
}
|
|
400
426
|
async hardDeleteMany(ids) {
|
|
401
|
-
return this.hardDeleteManyByQuery(inArray(this
|
|
427
|
+
return this.hardDeleteManyByQuery(inArray(this.#table.id, ids));
|
|
402
428
|
}
|
|
403
429
|
async hardDeleteManyByQuery(query) {
|
|
404
|
-
const sqlQuery = this
|
|
405
|
-
const
|
|
406
|
-
.delete(this
|
|
407
|
-
.where(sqlQuery)
|
|
408
|
-
|
|
430
|
+
const sqlQuery = this.$convertQuery(query);
|
|
431
|
+
const rows = await this.session
|
|
432
|
+
.delete(this.#table)
|
|
433
|
+
.where(sqlQuery)
|
|
434
|
+
.returning();
|
|
435
|
+
const transformContext = await this.getTransformContext();
|
|
436
|
+
return this.mapManyToEntity(rows, transformContext);
|
|
437
|
+
}
|
|
438
|
+
$getColumn(path) {
|
|
439
|
+
const columnName = assertDefinedPass(this.#columnDefinitionsMap.get(path), `Could not map ${path} to column.`).name;
|
|
440
|
+
return this.#table[columnName];
|
|
441
|
+
}
|
|
442
|
+
$convertOrderBy(orderBy) {
|
|
443
|
+
if (isArray(orderBy)) {
|
|
444
|
+
return orderBy.map((item) => {
|
|
445
|
+
const itemIsArray = isArray(item);
|
|
446
|
+
const target = itemIsArray ? item[0] : item;
|
|
447
|
+
const column = isSQLWrapper(target) ? target : this.$getColumn(target);
|
|
448
|
+
const direction = itemIsArray ? item[1] : 'asc';
|
|
449
|
+
return direction == 'asc' ? asc(column) : desc(column);
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
return objectEntries(orderBy)
|
|
453
|
+
.map(([path, direction]) => {
|
|
454
|
+
const column = this.$getColumn(path);
|
|
455
|
+
return direction == 'asc' ? asc(column) : desc(column);
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
$convertQuery(query) {
|
|
459
|
+
return convertQuery(query, this.#table, this.#columnDefinitionsMap);
|
|
460
|
+
}
|
|
461
|
+
async $mapManyToEntity(columns) {
|
|
462
|
+
const transformContext = await this.getTransformContext();
|
|
463
|
+
return this.mapManyToEntity(columns, transformContext);
|
|
464
|
+
}
|
|
465
|
+
async $mapToEntity(columns) {
|
|
466
|
+
const transformContext = await this.getTransformContext();
|
|
467
|
+
return this.mapToEntity(columns, transformContext);
|
|
409
468
|
}
|
|
410
|
-
|
|
411
|
-
|
|
469
|
+
async $mapManyToColumns(objects) {
|
|
470
|
+
const transformContext = await this.getTransformContext();
|
|
471
|
+
return this.mapManyToColumns(objects, transformContext);
|
|
472
|
+
}
|
|
473
|
+
async $mapToColumns(obj) {
|
|
474
|
+
const transformContext = await this.getTransformContext();
|
|
475
|
+
return this.mapToColumns(obj, transformContext);
|
|
476
|
+
}
|
|
477
|
+
async $mapManyToInsertColumns(objects) {
|
|
478
|
+
const transformContext = await this.getTransformContext();
|
|
479
|
+
return this.mapManyToInsertColumns(objects, transformContext);
|
|
480
|
+
}
|
|
481
|
+
async $mapToInsertColumns(obj) {
|
|
482
|
+
const transformContext = await this.getTransformContext();
|
|
483
|
+
return this.mapToInsertColumns(obj, transformContext);
|
|
484
|
+
}
|
|
485
|
+
async $mapUpdate(update) {
|
|
486
|
+
const transformContext = await this.getTransformContext();
|
|
487
|
+
return this.mapUpdate(update, transformContext);
|
|
488
|
+
}
|
|
489
|
+
$getIdLimitQuery(query) {
|
|
490
|
+
return this.getIdLimitQuery(query);
|
|
491
|
+
}
|
|
492
|
+
$getAttributesUpdate(attributes) {
|
|
493
|
+
return this.getAttributesUpdate(attributes);
|
|
412
494
|
}
|
|
413
495
|
async mapManyToEntity(columns, transformContext) {
|
|
414
496
|
return toArrayAsync(mapAsync(columns, async (column) => this.mapToEntity(column, transformContext)));
|
|
415
497
|
}
|
|
416
498
|
async mapToEntity(columns, transformContext) {
|
|
417
499
|
const entries = [];
|
|
418
|
-
for (const def of this
|
|
500
|
+
for (const def of this.#columnDefinitions) {
|
|
419
501
|
const rawValue = columns[def.name];
|
|
420
502
|
const transformed = await def.fromDatabase(rawValue, transformContext);
|
|
421
503
|
entries.push([def.objectPath, transformed]); // eslint-disable-line @typescript-eslint/no-unsafe-argument
|
|
@@ -428,7 +510,7 @@ let EntityRepository = class EntityRepository {
|
|
|
428
510
|
}
|
|
429
511
|
async mapToColumns(obj, transformContext) {
|
|
430
512
|
const columns = {};
|
|
431
|
-
for (const def of this
|
|
513
|
+
for (const def of this.#columnDefinitions) {
|
|
432
514
|
const rawValue = def.dereferenceObjectPath(obj);
|
|
433
515
|
columns[def.name] = await def.toDatabase(rawValue, transformContext);
|
|
434
516
|
}
|
|
@@ -441,14 +523,18 @@ let EntityRepository = class EntityRepository {
|
|
|
441
523
|
const mapped = await this.mapToColumns(obj, transformContext);
|
|
442
524
|
return {
|
|
443
525
|
...mapped,
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
526
|
+
...(this.hasMetadata
|
|
527
|
+
? {
|
|
528
|
+
revision: 1,
|
|
529
|
+
revisionTimestamp: TRANSACTION_TIMESTAMP,
|
|
530
|
+
createTimestamp: TRANSACTION_TIMESTAMP
|
|
531
|
+
}
|
|
532
|
+
: undefined)
|
|
447
533
|
};
|
|
448
534
|
}
|
|
449
535
|
async mapUpdate(update, transformContext) {
|
|
450
536
|
const mappedUpdate = {};
|
|
451
|
-
for (const column of this
|
|
537
|
+
for (const column of this.#columnDefinitions) {
|
|
452
538
|
const value = column.dereferenceObjectPath(update);
|
|
453
539
|
if (isUndefined(value)) {
|
|
454
540
|
continue;
|
|
@@ -457,15 +543,19 @@ let EntityRepository = class EntityRepository {
|
|
|
457
543
|
}
|
|
458
544
|
return {
|
|
459
545
|
...mappedUpdate,
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
546
|
+
...(this.hasMetadata
|
|
547
|
+
? {
|
|
548
|
+
attributes: this.getAttributesUpdate(update?.metadata?.attributes),
|
|
549
|
+
revision: sql `${this.#tableWithMetadata.revision} + 1`,
|
|
550
|
+
revisionTimestamp: TRANSACTION_TIMESTAMP
|
|
551
|
+
}
|
|
552
|
+
: undefined)
|
|
463
553
|
};
|
|
464
554
|
}
|
|
465
555
|
getIdLimitQuery(query) {
|
|
466
|
-
const sqlQuery = this
|
|
467
|
-
return this.session.select({ id: this
|
|
468
|
-
.from(this
|
|
556
|
+
const sqlQuery = this.$convertQuery(query);
|
|
557
|
+
return this.session.select({ id: this.#table.id })
|
|
558
|
+
.from(this.#table)
|
|
469
559
|
.where(sqlQuery)
|
|
470
560
|
.limit(1);
|
|
471
561
|
}
|
|
@@ -473,11 +563,17 @@ let EntityRepository = class EntityRepository {
|
|
|
473
563
|
if (isUndefined(attributes)) {
|
|
474
564
|
return undefined;
|
|
475
565
|
}
|
|
476
|
-
|
|
566
|
+
if (attributes instanceof SQL) {
|
|
567
|
+
return attributes;
|
|
568
|
+
}
|
|
569
|
+
return sql `${this.#tableWithMetadata.attributes} || ${JSON.stringify(attributes)}::jsonb`;
|
|
477
570
|
}
|
|
478
571
|
async getTransformContext() {
|
|
479
572
|
if (isUndefined(this.#transformContext)) {
|
|
480
|
-
|
|
573
|
+
if (isUndefined(this.#encryptionSecret)) {
|
|
574
|
+
this.#transformContext = {};
|
|
575
|
+
return this.#transformContext;
|
|
576
|
+
}
|
|
481
577
|
this.#transformContext = importSymmetricKey('AES-GCM', 256, this.#encryptionSecret, false).then((encryptionKey) => ({ encryptionKey }));
|
|
482
578
|
const transformContext = await this.#transformContext;
|
|
483
579
|
this.#transformContext = transformContext;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type SQL } from 'drizzle-orm';
|
|
2
|
+
import type { Uuid } from '../types.js';
|
|
3
|
+
export declare const TRANSACTION_TIMESTAMP: SQL<Date>;
|
|
4
|
+
export declare const RANDOM_UUID: SQL<Uuid>;
|
|
5
|
+
type IntervalUnit = 'millennium' | 'millenniums' | 'millennia' | 'century' | 'centuries' | 'decade' | 'decades' | 'year' | 'years' | 'day' | 'days' | 'hour' | 'hours' | 'minute' | 'minutes' | 'second' | 'seconds' | 'millisecond' | 'milliseconds' | 'microsecond' | 'microseconds';
|
|
6
|
+
export declare function interval(value: number, unit: IntervalUnit): SQL;
|
|
7
|
+
export {};
|
package/orm/server/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { PgColumnBuilder, PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
|
3
3
|
import type { CamelCase, ConditionalPick, SnakeCase } from 'type-fest';
|
|
4
4
|
import type { JsonPath } from '../../json-path/json-path.js';
|
|
5
5
|
import type { Record } from '../../schema/index.js';
|
|
6
|
-
import type {
|
|
6
|
+
import type { UnionToIntersection } from '../../types.js';
|
|
7
7
|
import type { Tagged } from '../../types/index.js';
|
|
8
8
|
import type { OrmColumnReflectionData } from '../decorators.js';
|
|
9
9
|
import type { EntityType } from '../entity.js';
|
|
@@ -23,11 +23,11 @@ export type ColumnDefinition = {
|
|
|
23
23
|
export type TransformContext = {
|
|
24
24
|
encryptionKey?: CryptoKey;
|
|
25
25
|
};
|
|
26
|
-
type Column<Name extends string, T> = null extends T ? ColumnBuilder<T, Name> : NotNull<ColumnBuilder<T, Name>>;
|
|
26
|
+
type Column<Name extends string, T> = null extends T ? ColumnBuilder<Exclude<T, null>, Name> : NotNull<ColumnBuilder<T, Name>>;
|
|
27
27
|
export type ColumnPrefix<T> = T extends Tagged<unknown, EmbeddedConfigTag, {
|
|
28
28
|
prefix: infer Prefix;
|
|
29
29
|
}> ? Prefix extends string ? Prefix : '' : '';
|
|
30
|
-
export type PgTableFromType<
|
|
30
|
+
export type PgTableFromType<T extends EntityType = EntityType, S extends string = string, TableName extends string = T extends Required<EntityType> ? SnakeCase<T['entityName']> : string> = PgTableWithColumns<{
|
|
31
31
|
name: TableName;
|
|
32
32
|
schema: S;
|
|
33
33
|
columns: BuildColumns<TableName, {
|
package/orm/types.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export type Embedded<T = AbstractConstructor, P extends string = ''> = Tagged<T,
|
|
|
16
16
|
prefix: P;
|
|
17
17
|
}>;
|
|
18
18
|
export type Array<T extends Tagged<ObjectLiteral, ColumnTypeTag, PgColumnBuilder<any>>> = Tagged<UnwrapTagged<T>[], ColumnTypeTag, ReturnType<GetTagMetadata<T, ColumnTypeTag>['array']>>;
|
|
19
|
-
export type Json<T
|
|
19
|
+
export type Json<T> = Tagged<T, ColumnTypeTag, $Type<ReturnType<typeof jsonb>, T>>;
|
|
20
20
|
export type Enum<T extends EnumerationObject> = Tagged<EnumerationValue<T>, ColumnTypeTag, EnumColumn<T>>;
|
|
21
21
|
export type Text = Tagged<string, ColumnTypeTag, ReturnType<typeof text<string, [string, ...string[]]>>>;
|
|
22
22
|
export type Uuid = Tagged<string, ColumnTypeTag, ReturnType<typeof uuid>>;
|