@tstdl/base 0.92.85 → 0.92.87
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 +4 -4
- package/ai/ai.service.js +27 -14
- package/ai/types.d.ts +5 -4
- package/api/server/gateway.js +1 -1
- package/authentication/authentication.api.d.ts +9 -9
- package/authentication/models/schemas.d.ts +2 -2
- package/authentication/server/authentication-ancillary.service.d.ts +6 -4
- package/authentication/server/authentication-ancillary.service.js +5 -5
- package/cancellation/token.d.ts +1 -1
- package/context/context.d.ts +1 -9
- package/context/context.js +8 -5
- package/document-management/api/document-management.api.d.ts +142 -110
- package/document-management/models/document-category.model.d.ts +1 -0
- package/document-management/models/document-category.model.js +2 -0
- package/document-management/models/document-collection-document.model.js +7 -3
- package/document-management/models/document-property-value.model.d.ts +13 -14
- package/document-management/models/document-property-value.model.js +60 -27
- package/document-management/models/document-property.model.d.ts +2 -0
- package/document-management/models/document-property.model.js +4 -1
- package/document-management/models/document-request-assignment-task-collection.model.d.ts +7 -0
- package/document-management/models/document-request-assignment-task-collection.model.js +32 -0
- package/document-management/models/document-request-assignment-task.model.d.ts +14 -0
- package/document-management/models/document-request-assignment-task.model.js +72 -0
- package/document-management/models/document-request-collection.model.d.ts +1 -0
- package/document-management/models/document-request-collection.model.js +7 -3
- package/document-management/models/document-request-file.model.d.ts +7 -2
- package/document-management/models/document-request-file.model.js +29 -4
- package/document-management/models/document-request.model.d.ts +1 -0
- package/document-management/models/document-requests-template.js +2 -0
- package/document-management/models/document-type-property.model.js +7 -3
- package/document-management/models/document-type.model.d.ts +1 -0
- package/document-management/models/document-type.model.js +7 -3
- package/document-management/models/document.model.d.ts +5 -2
- package/document-management/models/document.model.js +21 -6
- package/document-management/models/index.d.ts +2 -0
- package/document-management/models/index.js +2 -0
- package/document-management/models/service-models/document.service-model.d.ts +84 -65
- package/document-management/models/service-models/document.service-model.js +11 -6
- package/document-management/models/service-models/document.view-model.d.ts +1 -1
- package/document-management/models/service-models/document.view-model.js +2 -2
- package/document-management/server/drizzle/{0000_sloppy_fenris.sql → 0000_cool_victor_mancha.sql} +99 -43
- package/document-management/server/drizzle/meta/0000_snapshot.json +518 -130
- 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 +3 -2
- package/document-management/server/module.js +4 -2
- package/document-management/server/schemas.d.ts +36 -0
- package/document-management/server/schemas.js +37 -0
- package/document-management/server/services/document-management-ancillary.service.d.ts +4 -0
- package/document-management/server/services/document-management-ancillary.service.js +13 -0
- package/document-management/server/services/document-management.service.d.ts +71 -22
- package/document-management/server/services/document-management.service.js +528 -81
- package/document-management/server/services/index.d.ts +1 -0
- package/document-management/server/services/index.js +1 -0
- package/eslint.config.js +1 -0
- package/examples/document-management/main.d.ts +5 -0
- package/examples/document-management/main.js +20 -2
- package/examples/orm/schemas.d.ts +1 -1
- package/file/index.d.ts +1 -0
- package/file/index.js +1 -0
- package/file/temporary-file.d.ts +17 -0
- package/file/temporary-file.js +49 -0
- package/http/server/http-server-response.d.ts +2 -0
- package/http/server/http-server-response.js +13 -0
- package/injector/index.d.ts +1 -0
- package/injector/index.js +1 -0
- package/injector/injector.js +19 -7
- package/injector/interfaces.d.ts +1 -1
- package/injector/interfaces.js +1 -1
- package/injector/resolution.d.ts +15 -0
- package/injector/resolution.js +6 -0
- package/logger/console/logger.d.ts +1 -1
- package/logger/logger.d.ts +1 -1
- package/mail/drizzle.config.js +1 -1
- package/mail/models/schemas.d.ts +1 -1
- package/object-storage/object-storage.d.ts +5 -7
- package/object-storage/s3/s3.object-storage.d.ts +0 -1
- package/object-storage/s3/s3.object-storage.js +0 -3
- package/orm/{server/data-types → data-types}/numeric-date.js +2 -3
- package/orm/decorators.d.ts +17 -8
- package/orm/decorators.js +13 -7
- package/orm/entity.d.ts +5 -7
- package/orm/entity.js +11 -7
- package/orm/index.d.ts +2 -0
- package/orm/index.js +2 -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/drizzle/schema-converter.js +48 -19
- 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 +80 -43
- package/orm/server/repository.js +219 -112
- package/orm/server/sqls.d.ts +15 -0
- package/orm/server/sqls.js +19 -0
- package/orm/server/types.d.ts +3 -3
- package/orm/types.d.ts +4 -4
- package/orm/utils.d.ts +3 -0
- package/orm/utils.js +6 -0
- package/package.json +23 -19
- package/pdf/pdf.service.d.ts +0 -1
- package/pdf/pdf.service.js +1 -95
- package/pdf/utils.d.ts +3 -1
- package/pdf/utils.js +129 -4
- package/promise/lazy-promise.d.ts +3 -3
- 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 +147 -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 +32 -6
- package/queue/queue.js +43 -0
- package/schema/schemas/object.d.ts +1 -1
- package/utils/date-time.d.ts +4 -2
- package/utils/date-time.js +10 -3
- package/utils/format-error.js +0 -1
- package/utils/object/lazy-property.js +0 -1
- package/utils/timing.d.ts +4 -3
- package/utils/timing.js +3 -1
- package/utils/try-ignore.d.ts +9 -2
- package/utils/try-ignore.js +30 -6
- package/document-management/models/schemas.d.ts +0 -33
- package/document-management/models/schemas.js +0 -34
- /package/orm/{server/data-types → data-types}/bytea.d.ts +0 -0
- /package/orm/{server/data-types → data-types}/bytea.js +0 -0
- /package/orm/{server/data-types → data-types}/index.d.ts +0 -0
- /package/orm/{server/data-types → data-types}/index.js +0 -0
- /package/orm/{server/data-types → data-types}/numeric-date.d.ts +0 -0
- /package/orm/{server/data-types → data-types}/timestamp.d.ts +0 -0
- /package/orm/{server/data-types → data-types}/timestamp.js +0 -0
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, fromEntries, objectEntries } from '../../utils/object/object.js';
|
|
26
|
+
import { assertDefinedPass, isArray, isDefined, isString, 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,16 @@ 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
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
251
|
+
const targetColumns = toArray(target).map((path) => this.$getColumn(path));
|
|
252
|
+
const columns = await this.mapManyToInsertColumns(entities, transformContext);
|
|
253
|
+
const mappedUpdate = isDefined(update)
|
|
254
|
+
? await this.mapUpdate(update, transformContext)
|
|
255
|
+
: {
|
|
256
|
+
...fromEntries(this.#columnDefinitions.map((column) => [column.name, sql `excluded.${sql.identifier(this.$getColumn(column).name)}`])),
|
|
257
|
+
...this.getMetadataUpdate(update)
|
|
258
|
+
};
|
|
249
259
|
const rows = await this.session
|
|
250
|
-
.insert(this
|
|
260
|
+
.insert(this.#table)
|
|
251
261
|
.values(columns)
|
|
252
262
|
.onConflictDoUpdate({
|
|
253
263
|
target: targetColumns,
|
|
@@ -259,7 +269,7 @@ let EntityRepository = class EntityRepository {
|
|
|
259
269
|
async update(id, update) {
|
|
260
270
|
const entity = await this.tryUpdate(id, update);
|
|
261
271
|
if (isUndefined(entity)) {
|
|
262
|
-
throw new NotFoundError(`${this.
|
|
272
|
+
throw new NotFoundError(`${this.typeName} ${id} not found.`);
|
|
263
273
|
}
|
|
264
274
|
return entity;
|
|
265
275
|
}
|
|
@@ -267,9 +277,9 @@ let EntityRepository = class EntityRepository {
|
|
|
267
277
|
const transformContext = await this.getTransformContext();
|
|
268
278
|
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
269
279
|
const [row] = await this.session
|
|
270
|
-
.update(this
|
|
280
|
+
.update(this.#table)
|
|
271
281
|
.set(mappedUpdate)
|
|
272
|
-
.where(eq(this
|
|
282
|
+
.where(eq(this.#table.id, id))
|
|
273
283
|
.returning();
|
|
274
284
|
if (isUndefined(row)) {
|
|
275
285
|
return undefined;
|
|
@@ -279,18 +289,18 @@ let EntityRepository = class EntityRepository {
|
|
|
279
289
|
async updateByQuery(query, update) {
|
|
280
290
|
const entity = await this.tryUpdateByQuery(query, update);
|
|
281
291
|
if (isUndefined(entity)) {
|
|
282
|
-
throw new NotFoundError(`${this.
|
|
292
|
+
throw new NotFoundError(`${this.typeName} not found.`);
|
|
283
293
|
}
|
|
284
294
|
return entity;
|
|
285
295
|
}
|
|
286
296
|
async tryUpdateByQuery(query, update) {
|
|
287
297
|
const transformContext = await this.getTransformContext();
|
|
288
298
|
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
289
|
-
const idQuery = this.
|
|
299
|
+
const idQuery = this.getIdLimitSelect(query);
|
|
290
300
|
const [row] = await this.session
|
|
291
|
-
.update(this
|
|
301
|
+
.update(this.#table)
|
|
292
302
|
.set(mappedUpdate)
|
|
293
|
-
.where(inArray(this
|
|
303
|
+
.where(inArray(this.#table.id, idQuery.for('update')))
|
|
294
304
|
.returning();
|
|
295
305
|
if (isUndefined(row)) {
|
|
296
306
|
return undefined;
|
|
@@ -298,14 +308,14 @@ let EntityRepository = class EntityRepository {
|
|
|
298
308
|
return this.mapToEntity(row, transformContext);
|
|
299
309
|
}
|
|
300
310
|
async updateMany(ids, update) {
|
|
301
|
-
return this.updateManyByQuery(inArray(this
|
|
311
|
+
return this.updateManyByQuery(inArray(this.#table.id, ids), update);
|
|
302
312
|
}
|
|
303
313
|
async updateManyByQuery(query, update) {
|
|
304
314
|
const transformContext = await this.getTransformContext();
|
|
305
|
-
const sqlQuery = this
|
|
315
|
+
const sqlQuery = this.$convertQuery(query);
|
|
306
316
|
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
307
317
|
const rows = await this.session
|
|
308
|
-
.update(this
|
|
318
|
+
.update(this.#table)
|
|
309
319
|
.set(mappedUpdate)
|
|
310
320
|
.where(sqlQuery)
|
|
311
321
|
.returning();
|
|
@@ -314,18 +324,21 @@ let EntityRepository = class EntityRepository {
|
|
|
314
324
|
async delete(id, metadataUpdate) {
|
|
315
325
|
const entity = await this.tryDelete(id, metadataUpdate);
|
|
316
326
|
if (isUndefined(entity)) {
|
|
317
|
-
throw new NotFoundError(`${this.
|
|
327
|
+
throw new NotFoundError(`${this.typeName} ${id} not found.`);
|
|
318
328
|
}
|
|
319
329
|
return entity;
|
|
320
330
|
}
|
|
321
331
|
async tryDelete(id, metadataUpdate) {
|
|
332
|
+
if (!this.hasMetadata) {
|
|
333
|
+
return this.tryHardDelete(id);
|
|
334
|
+
}
|
|
322
335
|
const [row] = await this.session
|
|
323
|
-
.update(this
|
|
336
|
+
.update(this.#tableWithMetadata)
|
|
324
337
|
.set({
|
|
325
338
|
deleteTimestamp: TRANSACTION_TIMESTAMP,
|
|
326
339
|
attributes: this.getAttributesUpdate(metadataUpdate?.attributes)
|
|
327
340
|
})
|
|
328
|
-
.where(eq(this
|
|
341
|
+
.where(eq(this.#table.id, id))
|
|
329
342
|
.returning();
|
|
330
343
|
if (isUndefined(row)) {
|
|
331
344
|
return undefined;
|
|
@@ -336,19 +349,22 @@ let EntityRepository = class EntityRepository {
|
|
|
336
349
|
async deleteByQuery(query, metadataUpdate) {
|
|
337
350
|
const entity = await this.tryDeleteByQuery(query, metadataUpdate);
|
|
338
351
|
if (isUndefined(entity)) {
|
|
339
|
-
throw new NotFoundError(`${this.
|
|
352
|
+
throw new NotFoundError(`${this.typeName} not found.`);
|
|
340
353
|
}
|
|
341
354
|
return entity;
|
|
342
355
|
}
|
|
343
356
|
async tryDeleteByQuery(query, metadataUpdate) {
|
|
344
|
-
|
|
357
|
+
if (!this.hasMetadata) {
|
|
358
|
+
return this.tryHardDeleteByQuery(query);
|
|
359
|
+
}
|
|
360
|
+
const idQuery = this.getIdLimitSelect(query);
|
|
345
361
|
const [row] = await this.session
|
|
346
|
-
.update(this
|
|
362
|
+
.update(this.#tableWithMetadata)
|
|
347
363
|
.set({
|
|
348
364
|
deleteTimestamp: TRANSACTION_TIMESTAMP,
|
|
349
365
|
attributes: this.getAttributesUpdate(metadataUpdate?.attributes)
|
|
350
366
|
})
|
|
351
|
-
.where(inArray(this
|
|
367
|
+
.where(inArray(this.#table.id, idQuery.for('update')))
|
|
352
368
|
.returning();
|
|
353
369
|
if (isUndefined(row)) {
|
|
354
370
|
return undefined;
|
|
@@ -357,12 +373,15 @@ let EntityRepository = class EntityRepository {
|
|
|
357
373
|
return this.mapToEntity(row, transformContext);
|
|
358
374
|
}
|
|
359
375
|
async deleteMany(ids, metadataUpdate) {
|
|
360
|
-
return this.deleteManyByQuery(inArray(this
|
|
376
|
+
return this.deleteManyByQuery(inArray(this.#table.id, ids), metadataUpdate);
|
|
361
377
|
}
|
|
362
378
|
async deleteManyByQuery(query, metadataUpdate) {
|
|
363
|
-
|
|
379
|
+
if (!this.hasMetadata) {
|
|
380
|
+
return this.hardDeleteManyByQuery(query);
|
|
381
|
+
}
|
|
382
|
+
const sqlQuery = this.$convertQuery(query);
|
|
364
383
|
const rows = await this.session
|
|
365
|
-
.update(this
|
|
384
|
+
.update(this.#tableWithMetadata)
|
|
366
385
|
.set({
|
|
367
386
|
deleteTimestamp: TRANSACTION_TIMESTAMP,
|
|
368
387
|
attributes: this.getAttributesUpdate(metadataUpdate?.attributes)
|
|
@@ -375,47 +394,118 @@ let EntityRepository = class EntityRepository {
|
|
|
375
394
|
async hardDelete(id) {
|
|
376
395
|
const result = await this.tryHardDelete(id);
|
|
377
396
|
if (!result) {
|
|
378
|
-
throw new NotFoundError(`${this.
|
|
397
|
+
throw new NotFoundError(`${this.typeName} ${id} not found.`);
|
|
379
398
|
}
|
|
399
|
+
return result;
|
|
380
400
|
}
|
|
381
401
|
async tryHardDelete(id) {
|
|
382
|
-
const
|
|
383
|
-
.delete(this
|
|
384
|
-
.where(eq(this
|
|
385
|
-
|
|
402
|
+
const [row] = await this.session
|
|
403
|
+
.delete(this.#table)
|
|
404
|
+
.where(eq(this.#table.id, id))
|
|
405
|
+
.returning();
|
|
406
|
+
if (isUndefined(row)) {
|
|
407
|
+
return undefined;
|
|
408
|
+
}
|
|
409
|
+
const transformContext = await this.getTransformContext();
|
|
410
|
+
return this.mapToEntity(row, transformContext);
|
|
386
411
|
}
|
|
387
412
|
async hardDeleteByQuery(query) {
|
|
388
413
|
const result = await this.tryHardDeleteByQuery(query);
|
|
389
414
|
if (!result) {
|
|
390
|
-
throw new NotFoundError(`${this.
|
|
415
|
+
throw new NotFoundError(`${this.typeName} not found.`);
|
|
391
416
|
}
|
|
417
|
+
return result;
|
|
392
418
|
}
|
|
393
419
|
async tryHardDeleteByQuery(query) {
|
|
394
|
-
const idQuery = this.
|
|
395
|
-
const
|
|
396
|
-
.delete(this
|
|
397
|
-
.where(inArray(this
|
|
398
|
-
|
|
420
|
+
const idQuery = this.getIdLimitSelect(query);
|
|
421
|
+
const [row] = await this.session
|
|
422
|
+
.delete(this.#table)
|
|
423
|
+
.where(inArray(this.#table.id, idQuery.for('update')))
|
|
424
|
+
.returning();
|
|
425
|
+
if (isUndefined(row)) {
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
const transformContext = await this.getTransformContext();
|
|
429
|
+
return this.mapToEntity(row, transformContext);
|
|
399
430
|
}
|
|
400
431
|
async hardDeleteMany(ids) {
|
|
401
|
-
return this.hardDeleteManyByQuery(inArray(this
|
|
432
|
+
return this.hardDeleteManyByQuery(inArray(this.#table.id, ids));
|
|
402
433
|
}
|
|
403
434
|
async hardDeleteManyByQuery(query) {
|
|
404
|
-
const sqlQuery = this
|
|
405
|
-
const
|
|
406
|
-
.delete(this
|
|
407
|
-
.where(sqlQuery)
|
|
408
|
-
|
|
435
|
+
const sqlQuery = this.$convertQuery(query);
|
|
436
|
+
const rows = await this.session
|
|
437
|
+
.delete(this.#table)
|
|
438
|
+
.where(sqlQuery)
|
|
439
|
+
.returning();
|
|
440
|
+
const transformContext = await this.getTransformContext();
|
|
441
|
+
return this.mapManyToEntity(rows, transformContext);
|
|
409
442
|
}
|
|
410
|
-
|
|
411
|
-
|
|
443
|
+
$getColumn(pathOrColumn) {
|
|
444
|
+
if (isString(pathOrColumn)) {
|
|
445
|
+
const columnName = assertDefinedPass(this.#columnDefinitionsMap.get(pathOrColumn), `Could not map ${pathOrColumn} to column.`).name;
|
|
446
|
+
return this.#table[columnName];
|
|
447
|
+
}
|
|
448
|
+
return this.#table[pathOrColumn.name];
|
|
449
|
+
}
|
|
450
|
+
$convertOrderBy(orderBy) {
|
|
451
|
+
if (isArray(orderBy)) {
|
|
452
|
+
return orderBy.map((item) => {
|
|
453
|
+
const itemIsArray = isArray(item);
|
|
454
|
+
const target = itemIsArray ? item[0] : item;
|
|
455
|
+
const column = isSQLWrapper(target) ? target : this.$getColumn(target);
|
|
456
|
+
const direction = itemIsArray ? item[1] : 'asc';
|
|
457
|
+
return direction == 'asc' ? asc(column) : desc(column);
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
return objectEntries(orderBy)
|
|
461
|
+
.map(([path, direction]) => {
|
|
462
|
+
const column = this.$getColumn(path);
|
|
463
|
+
return direction == 'asc' ? asc(column) : desc(column);
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
$convertQuery(query) {
|
|
467
|
+
return convertQuery(query, this.#table, this.#columnDefinitionsMap);
|
|
468
|
+
}
|
|
469
|
+
async $mapManyToEntity(columns) {
|
|
470
|
+
const transformContext = await this.getTransformContext();
|
|
471
|
+
return this.mapManyToEntity(columns, transformContext);
|
|
472
|
+
}
|
|
473
|
+
async $mapToEntity(columns) {
|
|
474
|
+
const transformContext = await this.getTransformContext();
|
|
475
|
+
return this.mapToEntity(columns, transformContext);
|
|
476
|
+
}
|
|
477
|
+
async $mapManyToColumns(objects) {
|
|
478
|
+
const transformContext = await this.getTransformContext();
|
|
479
|
+
return this.mapManyToColumns(objects, transformContext);
|
|
480
|
+
}
|
|
481
|
+
async $mapToColumns(obj) {
|
|
482
|
+
const transformContext = await this.getTransformContext();
|
|
483
|
+
return this.mapToColumns(obj, transformContext);
|
|
484
|
+
}
|
|
485
|
+
async $mapManyToInsertColumns(objects) {
|
|
486
|
+
const transformContext = await this.getTransformContext();
|
|
487
|
+
return this.mapManyToInsertColumns(objects, transformContext);
|
|
488
|
+
}
|
|
489
|
+
async $mapToInsertColumns(obj) {
|
|
490
|
+
const transformContext = await this.getTransformContext();
|
|
491
|
+
return this.mapToInsertColumns(obj, transformContext);
|
|
492
|
+
}
|
|
493
|
+
async $mapUpdate(update) {
|
|
494
|
+
const transformContext = await this.getTransformContext();
|
|
495
|
+
return this.mapUpdate(update, transformContext);
|
|
496
|
+
}
|
|
497
|
+
$getIdLimitQuery(query) {
|
|
498
|
+
return this.getIdLimitSelect(query);
|
|
499
|
+
}
|
|
500
|
+
$getAttributesUpdate(attributes) {
|
|
501
|
+
return this.getAttributesUpdate(attributes);
|
|
412
502
|
}
|
|
413
503
|
async mapManyToEntity(columns, transformContext) {
|
|
414
504
|
return toArrayAsync(mapAsync(columns, async (column) => this.mapToEntity(column, transformContext)));
|
|
415
505
|
}
|
|
416
506
|
async mapToEntity(columns, transformContext) {
|
|
417
507
|
const entries = [];
|
|
418
|
-
for (const def of this
|
|
508
|
+
for (const def of this.#columnDefinitions) {
|
|
419
509
|
const rawValue = columns[def.name];
|
|
420
510
|
const transformed = await def.fromDatabase(rawValue, transformContext);
|
|
421
511
|
entries.push([def.objectPath, transformed]); // eslint-disable-line @typescript-eslint/no-unsafe-argument
|
|
@@ -428,7 +518,7 @@ let EntityRepository = class EntityRepository {
|
|
|
428
518
|
}
|
|
429
519
|
async mapToColumns(obj, transformContext) {
|
|
430
520
|
const columns = {};
|
|
431
|
-
for (const def of this
|
|
521
|
+
for (const def of this.#columnDefinitions) {
|
|
432
522
|
const rawValue = def.dereferenceObjectPath(obj);
|
|
433
523
|
columns[def.name] = await def.toDatabase(rawValue, transformContext);
|
|
434
524
|
}
|
|
@@ -441,14 +531,18 @@ let EntityRepository = class EntityRepository {
|
|
|
441
531
|
const mapped = await this.mapToColumns(obj, transformContext);
|
|
442
532
|
return {
|
|
443
533
|
...mapped,
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
534
|
+
...(this.hasMetadata
|
|
535
|
+
? {
|
|
536
|
+
revision: 1,
|
|
537
|
+
revisionTimestamp: TRANSACTION_TIMESTAMP,
|
|
538
|
+
createTimestamp: TRANSACTION_TIMESTAMP
|
|
539
|
+
}
|
|
540
|
+
: undefined)
|
|
447
541
|
};
|
|
448
542
|
}
|
|
449
543
|
async mapUpdate(update, transformContext) {
|
|
450
544
|
const mappedUpdate = {};
|
|
451
|
-
for (const column of this
|
|
545
|
+
for (const column of this.#columnDefinitions) {
|
|
452
546
|
const value = column.dereferenceObjectPath(update);
|
|
453
547
|
if (isUndefined(value)) {
|
|
454
548
|
continue;
|
|
@@ -457,15 +551,22 @@ let EntityRepository = class EntityRepository {
|
|
|
457
551
|
}
|
|
458
552
|
return {
|
|
459
553
|
...mappedUpdate,
|
|
460
|
-
|
|
461
|
-
revision: sql `${this.table.revision} + 1`,
|
|
462
|
-
revisionTimestamp: TRANSACTION_TIMESTAMP
|
|
554
|
+
...this.getMetadataUpdate(update)
|
|
463
555
|
};
|
|
464
556
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
557
|
+
getMetadataUpdate(update) {
|
|
558
|
+
return this.hasMetadata
|
|
559
|
+
? {
|
|
560
|
+
attributes: this.getAttributesUpdate(update?.metadata?.attributes),
|
|
561
|
+
revision: sql `${this.#tableWithMetadata.revision} + 1`,
|
|
562
|
+
revisionTimestamp: TRANSACTION_TIMESTAMP
|
|
563
|
+
}
|
|
564
|
+
: undefined;
|
|
565
|
+
}
|
|
566
|
+
getIdLimitSelect(query) {
|
|
567
|
+
const sqlQuery = this.$convertQuery(query);
|
|
568
|
+
return this.session.select({ id: this.#table.id })
|
|
569
|
+
.from(this.#table)
|
|
469
570
|
.where(sqlQuery)
|
|
470
571
|
.limit(1);
|
|
471
572
|
}
|
|
@@ -473,11 +574,17 @@ let EntityRepository = class EntityRepository {
|
|
|
473
574
|
if (isUndefined(attributes)) {
|
|
474
575
|
return undefined;
|
|
475
576
|
}
|
|
476
|
-
|
|
577
|
+
if (attributes instanceof SQL) {
|
|
578
|
+
return attributes;
|
|
579
|
+
}
|
|
580
|
+
return sql `${this.#tableWithMetadata.attributes} || ${JSON.stringify(attributes)}::jsonb`;
|
|
477
581
|
}
|
|
478
582
|
async getTransformContext() {
|
|
479
583
|
if (isUndefined(this.#transformContext)) {
|
|
480
|
-
|
|
584
|
+
if (isUndefined(this.#encryptionSecret)) {
|
|
585
|
+
this.#transformContext = {};
|
|
586
|
+
return this.#transformContext;
|
|
587
|
+
}
|
|
481
588
|
this.#transformContext = importSymmetricKey('AES-GCM', 256, this.#encryptionSecret, false).then((encryptionKey) => ({ encryptionKey }));
|
|
482
589
|
const transformContext = await this.#transformContext;
|
|
483
590
|
this.#transformContext = transformContext;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Column, type SQL } from 'drizzle-orm';
|
|
2
|
+
import type { GetSelectTableSelection, SelectResultField, TableLike } from 'drizzle-orm/query-builders/select.types';
|
|
3
|
+
import type { Uuid } from '../types.js';
|
|
4
|
+
export declare const TRANSACTION_TIMESTAMP: SQL<Date>;
|
|
5
|
+
export declare const RANDOM_UUID: SQL<Uuid>;
|
|
6
|
+
type IntervalUnit = 'millennium' | 'millenniums' | 'millennia' | 'century' | 'centuries' | 'decade' | 'decades' | 'year' | 'years' | 'day' | 'days' | 'hour' | 'hours' | 'minute' | 'minutes' | 'second' | 'seconds' | 'millisecond' | 'milliseconds' | 'microsecond' | 'microseconds';
|
|
7
|
+
export declare function interval(value: number, unit: IntervalUnit): SQL;
|
|
8
|
+
export declare function arrayAgg<T extends Column>(column: T): SQL<SelectResultField<T>[]>;
|
|
9
|
+
export declare function jsonAgg<T extends TableLike>(tableOrColumn: T): SQL<SelectResultField<GetSelectTableSelection<T>>[]>;
|
|
10
|
+
export declare namespace jsonAgg {
|
|
11
|
+
var withNull: <T extends TableLike>(tableOrColumn: T) => SQL<(SelectResultField<GetSelectTableSelection<T>> | null)[]>;
|
|
12
|
+
}
|
|
13
|
+
export declare function coalesce<T extends (Column | SQL)[]>(...columns: T): SQL<SelectResultField<T>[number]>;
|
|
14
|
+
export declare function toJsonb<T extends (Column | SQL)>(column: T): SQL<SelectResultField<T>>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
export const TRANSACTION_TIMESTAMP = sql `transaction_timestamp()`;
|
|
3
|
+
export const RANDOM_UUID = sql `gen_random_uuid()`;
|
|
4
|
+
export function interval(value, unit) {
|
|
5
|
+
return sql `(${value} ||' ${sql.raw(unit)}')::interval`;
|
|
6
|
+
}
|
|
7
|
+
export function arrayAgg(column) {
|
|
8
|
+
return sql `array_agg(${column})`;
|
|
9
|
+
}
|
|
10
|
+
export function jsonAgg(tableOrColumn) {
|
|
11
|
+
return sql `json_agg(${tableOrColumn})`;
|
|
12
|
+
}
|
|
13
|
+
jsonAgg.withNull = jsonAgg;
|
|
14
|
+
export function coalesce(...columns) {
|
|
15
|
+
return sql `coalesce(${sql.join(columns, sql.raw(', '))})`;
|
|
16
|
+
}
|
|
17
|
+
export function toJsonb(column) {
|
|
18
|
+
return sql `to_jsonb(${column})`;
|
|
19
|
+
}
|