@tstdl/base 0.92.54 → 0.92.56
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/authentication/models/index.d.ts +1 -0
- package/authentication/models/index.js +1 -0
- package/authentication/models/schemas.d.ts +2 -2
- package/document-management/models/schemas.d.ts +17 -17
- package/document-management/server/drizzle/{0000_wakeful_firebrand.sql → 0000_sloppy_fenris.sql} +1 -1
- package/document-management/server/drizzle/meta/0000_snapshot.json +5 -5
- package/document-management/server/drizzle/meta/_journal.json +2 -2
- package/examples/orm/schemas.d.ts +1 -1
- package/mail/drizzle/0000_empty_jubilee.sql +13 -0
- package/mail/drizzle/meta/0000_snapshot.json +100 -0
- package/mail/drizzle/meta/_journal.json +13 -0
- package/mail/drizzle.config.d.ts +2 -0
- package/mail/drizzle.config.js +11 -0
- package/mail/index.d.ts +0 -1
- package/mail/index.js +0 -1
- package/mail/mail.service.d.ts +1 -1
- package/mail/mail.service.js +21 -21
- package/mail/models/index.d.ts +1 -0
- package/mail/models/index.js +1 -0
- package/mail/models/mail-log.model.d.ts +6 -7
- package/mail/models/mail-log.model.js +38 -1
- package/mail/models/schemas.d.ts +3 -0
- package/mail/models/schemas.js +4 -0
- package/mail/module.d.ts +9 -8
- package/mail/module.js +25 -11
- package/orm/decorators.d.ts +2 -0
- package/orm/decorators.js +3 -0
- package/orm/server/database-schema.d.ts +1 -1
- package/orm/server/drizzle/schema-converter.d.ts +3 -36
- package/orm/server/drizzle/schema-converter.js +18 -1
- package/orm/server/encryption.d.ts +2 -0
- package/orm/server/encryption.js +30 -0
- package/orm/server/module.d.ts +3 -1
- package/orm/server/module.js +4 -0
- package/orm/server/query-converter.d.ts +1 -1
- package/orm/server/query-converter.js +0 -1
- package/orm/server/repository.d.ts +9 -5
- package/orm/server/repository.js +72 -30
- package/orm/server/tokens.d.ts +1 -0
- package/orm/server/tokens.js +2 -0
- package/orm/server/types.d.ts +43 -0
- package/orm/server/types.js +1 -0
- package/orm/types.d.ts +2 -1
- package/package.json +6 -4
- package/mail/repositories/index.d.ts +0 -2
- package/mail/repositories/index.js +0 -2
- package/mail/repositories/mail-log.repository.d.ts +0 -4
- package/mail/repositories/mail-log.repository.js +0 -3
- package/mail/repositories/mongo/index.d.ts +0 -1
- package/mail/repositories/mongo/index.js +0 -1
- package/mail/repositories/mongo/mongo-mail-log.repository.d.ts +0 -16
- package/mail/repositories/mongo/mongo-mail-log.repository.js +0 -33
|
@@ -6,6 +6,7 @@ import { JsonPath } from '../../../json-path/json-path.js';
|
|
|
6
6
|
import { reflectionRegistry } from '../../../reflection/registry.js';
|
|
7
7
|
import { ArraySchema, BooleanSchema, DefaultSchema, EnumerationSchema, getObjectSchema, NullableSchema, NumberSchema, ObjectSchema, OptionalSchema, StringSchema, Uint8ArraySchema } from '../../../schema/index.js';
|
|
8
8
|
import { compareByValueSelectionToOrder, orderRest } from '../../../utils/comparison.js';
|
|
9
|
+
import { decodeText, encodeUtf8 } from '../../../utils/encoding.js';
|
|
9
10
|
import { enumValues } from '../../../utils/enum.js';
|
|
10
11
|
import { memoize, memoizeSingle } from '../../../utils/function/memoize.js';
|
|
11
12
|
import { compileDereferencer } from '../../../utils/object/dereference.js';
|
|
@@ -16,6 +17,7 @@ import { NumericDateSchema } from '../../schemas/numeric-date.js';
|
|
|
16
17
|
import { TimestampSchema } from '../../schemas/timestamp.js';
|
|
17
18
|
import { UuidSchema } from '../../schemas/uuid.js';
|
|
18
19
|
import { bytea } from '../data-types/bytea.js';
|
|
20
|
+
import { decryptBytes, encryptBytes } from '../encryption.js';
|
|
19
21
|
const getDbSchema = memoizeSingle(pgSchema);
|
|
20
22
|
export const getDrizzleTableFromType = memoize(_getDrizzleTableFromType);
|
|
21
23
|
const columnDefinitionsSymbol = Symbol('columnDefinitions');
|
|
@@ -86,13 +88,28 @@ function getPostgresColumnEntries(type, tableName, dbSchema, path = new JsonPath
|
|
|
86
88
|
return getPostgresColumnEntries(columnReflectionData?.embedded?.type ?? propertyMetadata.type, tableName, dbSchema, path.add(property), nestedPrefix);
|
|
87
89
|
}
|
|
88
90
|
const objectPath = path.add(property);
|
|
91
|
+
const encrypted = columnReflectionData?.encrypted == true;
|
|
92
|
+
const toDatabase = encrypted
|
|
93
|
+
? async (value, context) => {
|
|
94
|
+
const bytes = encodeUtf8(value);
|
|
95
|
+
return encryptBytes(bytes, context.encryptionKey);
|
|
96
|
+
}
|
|
97
|
+
: (value) => value;
|
|
98
|
+
const fromDatabase = encrypted
|
|
99
|
+
? async (value, context) => {
|
|
100
|
+
const decrypted = await decryptBytes(value, context.encryptionKey);
|
|
101
|
+
return decodeText(decrypted);
|
|
102
|
+
}
|
|
103
|
+
: (value) => value;
|
|
89
104
|
return [
|
|
90
105
|
{
|
|
91
106
|
name: toCamelCase([prefix, columnName].join('')),
|
|
92
107
|
objectPath,
|
|
93
108
|
type: getPostgresColumn(columnName, dbSchema, schema, columnReflectionData ?? {}, { type, property }),
|
|
94
109
|
reflectionData: columnReflectionData,
|
|
95
|
-
dereferenceObjectPath: compileDereferencer(objectPath, { optional: true })
|
|
110
|
+
dereferenceObjectPath: compileDereferencer(objectPath, { optional: true }),
|
|
111
|
+
toDatabase,
|
|
112
|
+
fromDatabase
|
|
96
113
|
}
|
|
97
114
|
];
|
|
98
115
|
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DetailsError } from '../../errors/index.js';
|
|
2
|
+
import { decrypt, encrypt } from '../../utils/cryptography.js';
|
|
3
|
+
import { getRandomBytes } from '../../utils/random.js';
|
|
4
|
+
import { assert } from '../../utils/type-guards.js';
|
|
5
|
+
const encryptionVersion = 1;
|
|
6
|
+
const encryptionVersionBytes = 2;
|
|
7
|
+
const ivBytes = 12;
|
|
8
|
+
export async function encryptBytes(bytes, key) {
|
|
9
|
+
const iv = getRandomBytes(ivBytes);
|
|
10
|
+
const encrypted = await encrypt({ name: 'AES-GCM', iv }, key, bytes).toBuffer();
|
|
11
|
+
const result = new Uint8Array(encryptionVersionBytes + ivBytes + encrypted.byteLength);
|
|
12
|
+
const resultView = new DataView(result.buffer);
|
|
13
|
+
resultView.setUint16(0, encryptionVersion);
|
|
14
|
+
result.set(iv, encryptionVersionBytes);
|
|
15
|
+
result.set(new Uint8Array(encrypted), encryptionVersionBytes + ivBytes);
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
export async function decryptBytes(bytes, key) {
|
|
19
|
+
const bytesView = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
|
|
20
|
+
const version = bytesView.getUint16(0);
|
|
21
|
+
const iv = bytes.slice(encryptionVersionBytes, encryptionVersionBytes + ivBytes);
|
|
22
|
+
assert(version == encryptionVersion, 'Invalid encryption version.');
|
|
23
|
+
try {
|
|
24
|
+
const decrypted = await decrypt({ name: 'AES-GCM', iv }, key, bytes.slice(encryptionVersionBytes + ivBytes)).toBuffer();
|
|
25
|
+
return new Uint8Array(decrypted);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw new DetailsError('Decrypt error', error);
|
|
29
|
+
}
|
|
30
|
+
}
|
package/orm/server/module.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ export type OrmModuleOptions = {
|
|
|
7
7
|
connection?: string | PoolConfig;
|
|
8
8
|
repositoryConfig?: EntityRepositoryConfig;
|
|
9
9
|
};
|
|
10
|
-
export declare function configureOrm(options: OrmModuleOptions
|
|
10
|
+
export declare function configureOrm(options: OrmModuleOptions & {
|
|
11
|
+
encryptionSecret?: Uint8Array;
|
|
12
|
+
}): void;
|
package/orm/server/module.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Injector } from '../../injector/injector.js';
|
|
2
2
|
import { isDefined } from '../../utils/type-guards.js';
|
|
3
3
|
import { EntityRepositoryConfig } from './repository.js';
|
|
4
|
+
import { ENCRYPTION_SECRET } from './tokens.js';
|
|
4
5
|
export class DatabaseConfig {
|
|
5
6
|
connection;
|
|
6
7
|
}
|
|
@@ -11,4 +12,7 @@ export function configureOrm(options) {
|
|
|
11
12
|
if (isDefined(options.repositoryConfig)) {
|
|
12
13
|
Injector.register(EntityRepositoryConfig, { useValue: options.repositoryConfig });
|
|
13
14
|
}
|
|
15
|
+
if (isDefined(options.encryptionSecret)) {
|
|
16
|
+
Injector.register(ENCRYPTION_SECRET, { useValue: options.encryptionSecret });
|
|
17
|
+
}
|
|
14
18
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SQL } from 'drizzle-orm';
|
|
2
|
-
import type { ColumnDefinition, PgTableFromType } from './drizzle/schema-converter.js';
|
|
3
2
|
import type { EntityType } from '../entity.js';
|
|
4
3
|
import type { Query } from '../query.js';
|
|
4
|
+
import type { ColumnDefinition, PgTableFromType } from './types.js';
|
|
5
5
|
export declare function convertQuery(query: Query, table: PgTableFromType<string, EntityType>, columnDefinitionsMap: Map<string, ColumnDefinition>): SQL;
|
|
@@ -14,7 +14,6 @@ export function convertQuery(query, table, columnDefinitionsMap) {
|
|
|
14
14
|
if (queryEntries.length == 0) {
|
|
15
15
|
return sqlTrue;
|
|
16
16
|
}
|
|
17
|
-
// eslint-disable-next-line no-unreachable-loop
|
|
18
17
|
for (const [property, value] of queryEntries) {
|
|
19
18
|
const isPrimitiveValue = isPrimitive(value);
|
|
20
19
|
if (property == '$and') {
|
|
@@ -7,8 +7,8 @@ import type { UntaggedDeep } from '../../types/index.js';
|
|
|
7
7
|
import type { Entity, EntityMetadata, EntityMetadataAttributes, EntityType, NewEntity } from '../entity.js';
|
|
8
8
|
import type { Query } from '../query.js';
|
|
9
9
|
import { Database } from './database.js';
|
|
10
|
-
import { type ColumnDefinition, type PgTableFromType } from './drizzle/schema-converter.js';
|
|
11
10
|
import { type Transaction, type TransactionConfig } from './transaction.js';
|
|
11
|
+
import type { ColumnDefinition, PgTableFromType, TransformContext } from './types.js';
|
|
12
12
|
type PgTransaction = DrizzlePgTransaction<PgQueryResultHKT, Record, Record>;
|
|
13
13
|
export declare const repositoryType: unique symbol;
|
|
14
14
|
export type OrderOptions<T extends Entity> = {
|
|
@@ -83,10 +83,13 @@ export declare class EntityRepository<T extends Entity = Entity> implements Reso
|
|
|
83
83
|
hardDeleteMany(ids: string[]): Promise<number>;
|
|
84
84
|
hardDeleteManyByQuery(query: Query<T>): Promise<number>;
|
|
85
85
|
protected convertQuery(query: Query<T>): SQL;
|
|
86
|
-
protected
|
|
87
|
-
protected
|
|
88
|
-
protected
|
|
89
|
-
protected
|
|
86
|
+
protected mapManyToEntity(columns: this['table']['$inferSelect'][], transformContext: TransformContext): Promise<T[]>;
|
|
87
|
+
protected mapToEntity(columns: this['table']['$inferSelect'], transformContext: TransformContext): Promise<T>;
|
|
88
|
+
protected mapManyToColumns(objects: (DeepPartial<T> | NewEntity<T>)[], transformContext: TransformContext): Promise<PgInsertValue<PgTableFromType<string, EntityType>>[]>;
|
|
89
|
+
protected mapToColumns(obj: DeepPartial<T> | NewEntity<T>, transformContext: TransformContext): Promise<PgInsertValue<PgTableFromType<string, EntityType>>>;
|
|
90
|
+
protected mapManyToInsertColumns(objects: (DeepPartial<T> | NewEntity<T>)[], transformContext: TransformContext): Promise<PgInsertValue<PgTableFromType<string, EntityType>>[]>;
|
|
91
|
+
protected mapToInsertColumns(obj: DeepPartial<T> | NewEntity<T>, transformContext: TransformContext): Promise<PgInsertValue<PgTableFromType<string, EntityType>>>;
|
|
92
|
+
protected mapUpdate(update: EntityUpdate<T>, transformContext: TransformContext): Promise<PgUpdateSetSource<PgTableFromType<string, EntityType>>>;
|
|
90
93
|
protected getIdLimitQuery(query: Query<T>): import("drizzle-orm/pg-core").WithSubqueryWithSelection<{
|
|
91
94
|
id: PgColumn<{
|
|
92
95
|
name: string;
|
|
@@ -107,6 +110,7 @@ export declare class EntityRepository<T extends Entity = Entity> implements Reso
|
|
|
107
110
|
}, {}, {}>;
|
|
108
111
|
}, "id">;
|
|
109
112
|
protected getAttributesUpdate(attributes: EntityMetadataAttributes | undefined): SQL<unknown> | undefined;
|
|
113
|
+
protected getTransformContext(): Promise<TransformContext>;
|
|
110
114
|
}
|
|
111
115
|
export declare function injectRepository<T extends Entity>(type: EntityType<T>): EntityRepository<T>;
|
|
112
116
|
export declare function getRepository<T extends Entity>(type: EntityType<T>, config?: EntityRepositoryConfig): Type<EntityRepository<T>>;
|
package/orm/server/repository.js
CHANGED
|
@@ -17,11 +17,15 @@ import { resolveArgumentType } from '../../injector/interfaces.js';
|
|
|
17
17
|
import { injectionToken } from '../../injector/token.js';
|
|
18
18
|
import { Schema } from '../../schema/schema.js';
|
|
19
19
|
import { toArray } from '../../utils/array/array.js';
|
|
20
|
+
import { mapAsync } from '../../utils/async-iterable-helpers/map.js';
|
|
21
|
+
import { toArrayAsync } from '../../utils/async-iterable-helpers/to-array.js';
|
|
22
|
+
import { importSymmetricKey } from '../../utils/cryptography.js';
|
|
20
23
|
import { fromDeepObjectEntries } from '../../utils/object/object.js';
|
|
21
|
-
import { assertDefinedPass, assertNotNullPass, isNotNull, isUndefined } from '../../utils/type-guards.js';
|
|
24
|
+
import { assertDefined, assertDefinedPass, assertNotNullPass, isNotNull, isUndefined } from '../../utils/type-guards.js';
|
|
22
25
|
import { Database } from './database.js';
|
|
23
26
|
import { getColumnDefinitions, getDrizzleTableFromType } from './drizzle/schema-converter.js';
|
|
24
27
|
import { convertQuery } from './query-converter.js';
|
|
28
|
+
import { ENCRYPTION_SECRET } from './tokens.js';
|
|
25
29
|
import { DrizzleTransaction } from './transaction.js';
|
|
26
30
|
export const repositoryType = Symbol('repositoryType');
|
|
27
31
|
export class EntityRepositoryConfig {
|
|
@@ -32,6 +36,8 @@ const TRANSACTION_TIMESTAMP = sql `transaction_timestamp()`;
|
|
|
32
36
|
let EntityRepository = class EntityRepository {
|
|
33
37
|
#repositoryConstructor;
|
|
34
38
|
#withTransactionCache = new WeakMap();
|
|
39
|
+
#encryptionSecret = inject(ENCRYPTION_SECRET, undefined, { optional: true });
|
|
40
|
+
#transformContext;
|
|
35
41
|
type;
|
|
36
42
|
table;
|
|
37
43
|
columnDefinitions;
|
|
@@ -103,7 +109,8 @@ let EntityRepository = class EntityRepository {
|
|
|
103
109
|
if (isUndefined(row)) {
|
|
104
110
|
return undefined;
|
|
105
111
|
}
|
|
106
|
-
|
|
112
|
+
const transformContext = await this.getTransformContext();
|
|
113
|
+
return this.mapToEntity(row, transformContext);
|
|
107
114
|
}
|
|
108
115
|
async loadMany(ids, options) {
|
|
109
116
|
return this.loadManyByQuery(inArray(this.table.id, ids), options);
|
|
@@ -119,7 +126,8 @@ let EntityRepository = class EntityRepository {
|
|
|
119
126
|
.where(sqlQuery)
|
|
120
127
|
.offset(options?.offset)
|
|
121
128
|
.limit(options?.limit);
|
|
122
|
-
|
|
129
|
+
const transformContext = await this.getTransformContext();
|
|
130
|
+
return this.mapManyToEntity(rows, transformContext);
|
|
123
131
|
}
|
|
124
132
|
async *loadManyByQueryCursor(query, options) {
|
|
125
133
|
const entities = await this.loadManyByQuery(query, options);
|
|
@@ -166,25 +174,28 @@ let EntityRepository = class EntityRepository {
|
|
|
166
174
|
return assertDefinedPass(result[0]).contains;
|
|
167
175
|
}
|
|
168
176
|
async insert(entity) {
|
|
169
|
-
const
|
|
177
|
+
const transformContext = await this.getTransformContext();
|
|
178
|
+
const columns = await this.mapToInsertColumns(entity, transformContext);
|
|
170
179
|
const [row] = await this.session
|
|
171
180
|
.insert(this.table)
|
|
172
181
|
.values(columns)
|
|
173
182
|
.returning();
|
|
174
|
-
return this.mapToEntity(row);
|
|
183
|
+
return this.mapToEntity(row, transformContext);
|
|
175
184
|
}
|
|
176
185
|
async insertMany(entities) {
|
|
177
|
-
const
|
|
186
|
+
const transformContext = await this.getTransformContext();
|
|
187
|
+
const columns = await this.mapManyToInsertColumns(entities, transformContext);
|
|
178
188
|
const rows = await this.session.insert(this.table).values(columns).returning();
|
|
179
|
-
return
|
|
189
|
+
return this.mapManyToEntity(rows, transformContext);
|
|
180
190
|
}
|
|
181
191
|
async upsert(target, entity, update) {
|
|
192
|
+
const transformContext = await this.getTransformContext();
|
|
182
193
|
const targetColumns = toArray(target).map((path) => {
|
|
183
194
|
const columnName = assertDefinedPass(this.columnDefinitionsMap.get(path), `Could not map ${path} to column.`).name;
|
|
184
195
|
return this.table[columnName];
|
|
185
196
|
});
|
|
186
|
-
const columns = this.mapToInsertColumns(entity);
|
|
187
|
-
const mappedUpdate = this.mapUpdate(update ?? entity);
|
|
197
|
+
const columns = await this.mapToInsertColumns(entity, transformContext);
|
|
198
|
+
const mappedUpdate = await this.mapUpdate(update ?? entity, transformContext);
|
|
188
199
|
const [row] = await this.session
|
|
189
200
|
.insert(this.table)
|
|
190
201
|
.values(columns)
|
|
@@ -193,15 +204,16 @@ let EntityRepository = class EntityRepository {
|
|
|
193
204
|
set: mappedUpdate
|
|
194
205
|
})
|
|
195
206
|
.returning();
|
|
196
|
-
return this.mapToEntity(row);
|
|
207
|
+
return this.mapToEntity(row, transformContext);
|
|
197
208
|
}
|
|
198
209
|
async upsertMany(target, entities, update) {
|
|
210
|
+
const transformContext = await this.getTransformContext();
|
|
199
211
|
const targetColumns = toArray(target).map((path) => {
|
|
200
212
|
const columnName = assertDefinedPass(this.columnDefinitionsMap.get(path), `Could not map ${path} to column.`).name;
|
|
201
213
|
return this.table[columnName];
|
|
202
214
|
});
|
|
203
|
-
const columns =
|
|
204
|
-
const mappedUpdate = this.mapUpdate(update);
|
|
215
|
+
const columns = await this.mapManyToColumns(entities, transformContext);
|
|
216
|
+
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
205
217
|
const rows = await this.session
|
|
206
218
|
.insert(this.table)
|
|
207
219
|
.values(columns)
|
|
@@ -210,7 +222,7 @@ let EntityRepository = class EntityRepository {
|
|
|
210
222
|
set: mappedUpdate
|
|
211
223
|
})
|
|
212
224
|
.returning();
|
|
213
|
-
return
|
|
225
|
+
return this.mapManyToEntity(rows, transformContext);
|
|
214
226
|
}
|
|
215
227
|
async update(id, update) {
|
|
216
228
|
const entity = await this.tryUpdate(id, update);
|
|
@@ -220,7 +232,8 @@ let EntityRepository = class EntityRepository {
|
|
|
220
232
|
return entity;
|
|
221
233
|
}
|
|
222
234
|
async tryUpdate(id, update) {
|
|
223
|
-
const
|
|
235
|
+
const transformContext = await this.getTransformContext();
|
|
236
|
+
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
224
237
|
const [row] = await this.session
|
|
225
238
|
.update(this.table)
|
|
226
239
|
.set(mappedUpdate)
|
|
@@ -229,7 +242,7 @@ let EntityRepository = class EntityRepository {
|
|
|
229
242
|
if (isUndefined(row)) {
|
|
230
243
|
return undefined;
|
|
231
244
|
}
|
|
232
|
-
return this.mapToEntity(row);
|
|
245
|
+
return this.mapToEntity(row, transformContext);
|
|
233
246
|
}
|
|
234
247
|
async updateByQuery(query, update) {
|
|
235
248
|
const entity = await this.tryUpdateByQuery(query, update);
|
|
@@ -239,7 +252,8 @@ let EntityRepository = class EntityRepository {
|
|
|
239
252
|
return entity;
|
|
240
253
|
}
|
|
241
254
|
async tryUpdateByQuery(query, update) {
|
|
242
|
-
const
|
|
255
|
+
const transformContext = await this.getTransformContext();
|
|
256
|
+
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
243
257
|
const idQuery = this.getIdLimitQuery(query);
|
|
244
258
|
const [row] = await this.session
|
|
245
259
|
.with(idQuery)
|
|
@@ -250,20 +264,21 @@ let EntityRepository = class EntityRepository {
|
|
|
250
264
|
if (isUndefined(row)) {
|
|
251
265
|
return undefined;
|
|
252
266
|
}
|
|
253
|
-
return this.mapToEntity(row);
|
|
267
|
+
return this.mapToEntity(row, transformContext);
|
|
254
268
|
}
|
|
255
269
|
async updateMany(ids, update) {
|
|
256
270
|
return this.updateManyByQuery(inArray(this.table.id, ids), update);
|
|
257
271
|
}
|
|
258
272
|
async updateManyByQuery(query, update) {
|
|
273
|
+
const transformContext = await this.getTransformContext();
|
|
259
274
|
const sqlQuery = this.convertQuery(query);
|
|
260
|
-
const mappedUpdate = this.mapUpdate(update);
|
|
275
|
+
const mappedUpdate = await this.mapUpdate(update, transformContext);
|
|
261
276
|
const rows = await this.session
|
|
262
277
|
.update(this.table)
|
|
263
278
|
.set(mappedUpdate)
|
|
264
279
|
.where(sqlQuery)
|
|
265
280
|
.returning();
|
|
266
|
-
return
|
|
281
|
+
return this.mapManyToEntity(rows, transformContext);
|
|
267
282
|
}
|
|
268
283
|
async delete(id, metadataUpdate) {
|
|
269
284
|
const entity = await this.tryDelete(id, metadataUpdate);
|
|
@@ -284,7 +299,8 @@ let EntityRepository = class EntityRepository {
|
|
|
284
299
|
if (isUndefined(row)) {
|
|
285
300
|
return undefined;
|
|
286
301
|
}
|
|
287
|
-
|
|
302
|
+
const transformContext = await this.getTransformContext();
|
|
303
|
+
return this.mapToEntity(row, transformContext);
|
|
288
304
|
}
|
|
289
305
|
async deleteByQuery(query, metadataUpdate) {
|
|
290
306
|
const entity = await this.tryDeleteByQuery(query, metadataUpdate);
|
|
@@ -306,7 +322,8 @@ let EntityRepository = class EntityRepository {
|
|
|
306
322
|
if (isUndefined(row)) {
|
|
307
323
|
return undefined;
|
|
308
324
|
}
|
|
309
|
-
|
|
325
|
+
const transformContext = await this.getTransformContext();
|
|
326
|
+
return this.mapToEntity(row, transformContext);
|
|
310
327
|
}
|
|
311
328
|
async deleteMany(ids, metadataUpdate) {
|
|
312
329
|
return this.deleteManyByQuery(inArray(this.table.id, ids), metadataUpdate);
|
|
@@ -321,7 +338,8 @@ let EntityRepository = class EntityRepository {
|
|
|
321
338
|
})
|
|
322
339
|
.where(sqlQuery)
|
|
323
340
|
.returning();
|
|
324
|
-
|
|
341
|
+
const transformContext = await this.getTransformContext();
|
|
342
|
+
return this.mapManyToEntity(rows, transformContext);
|
|
325
343
|
}
|
|
326
344
|
async hardDelete(id) {
|
|
327
345
|
const result = await this.tryHardDelete(id);
|
|
@@ -355,20 +373,35 @@ let EntityRepository = class EntityRepository {
|
|
|
355
373
|
convertQuery(query) {
|
|
356
374
|
return convertQuery(query, this.table, this.columnDefinitionsMap);
|
|
357
375
|
}
|
|
358
|
-
|
|
359
|
-
|
|
376
|
+
async mapManyToEntity(columns, transformContext) {
|
|
377
|
+
return toArrayAsync(mapAsync(columns, async (column) => this.mapToEntity(column, transformContext)));
|
|
378
|
+
}
|
|
379
|
+
async mapToEntity(columns, transformContext) {
|
|
380
|
+
const entries = [];
|
|
381
|
+
for (const def of this.columnDefinitions) {
|
|
382
|
+
const rawValue = columns[def.name];
|
|
383
|
+
const transformed = await def.fromDatabase(rawValue, transformContext);
|
|
384
|
+
entries.push([def.objectPath, transformed]); // eslint-disable-line @typescript-eslint/no-unsafe-argument
|
|
385
|
+
}
|
|
360
386
|
const obj = fromDeepObjectEntries(entries);
|
|
361
387
|
return Schema.parse(this.type, obj);
|
|
362
388
|
}
|
|
363
|
-
|
|
389
|
+
async mapManyToColumns(objects, transformContext) {
|
|
390
|
+
return toArrayAsync(mapAsync(objects, async (obj) => this.mapToColumns(obj, transformContext)));
|
|
391
|
+
}
|
|
392
|
+
async mapToColumns(obj, transformContext) {
|
|
364
393
|
const columns = {};
|
|
365
394
|
for (const def of this.columnDefinitions) {
|
|
366
|
-
|
|
395
|
+
const rawValue = def.dereferenceObjectPath(obj);
|
|
396
|
+
columns[def.name] = await def.toDatabase(rawValue, transformContext);
|
|
367
397
|
}
|
|
368
398
|
return columns;
|
|
369
399
|
}
|
|
370
|
-
|
|
371
|
-
|
|
400
|
+
async mapManyToInsertColumns(objects, transformContext) {
|
|
401
|
+
return toArrayAsync(mapAsync(objects, async (obj) => this.mapToInsertColumns(obj, transformContext)));
|
|
402
|
+
}
|
|
403
|
+
async mapToInsertColumns(obj, transformContext) {
|
|
404
|
+
const mapped = await this.mapToColumns(obj, transformContext);
|
|
372
405
|
return {
|
|
373
406
|
...mapped,
|
|
374
407
|
revision: 1,
|
|
@@ -376,14 +409,14 @@ let EntityRepository = class EntityRepository {
|
|
|
376
409
|
createTimestamp: TRANSACTION_TIMESTAMP
|
|
377
410
|
};
|
|
378
411
|
}
|
|
379
|
-
mapUpdate(update) {
|
|
412
|
+
async mapUpdate(update, transformContext) {
|
|
380
413
|
const mappedUpdate = {};
|
|
381
414
|
for (const column of this.columnDefinitions) {
|
|
382
415
|
const value = column.dereferenceObjectPath(update);
|
|
383
416
|
if (isUndefined(value)) {
|
|
384
417
|
continue;
|
|
385
418
|
}
|
|
386
|
-
mappedUpdate[column.name] = value;
|
|
419
|
+
mappedUpdate[column.name] = await column.toDatabase(value, transformContext);
|
|
387
420
|
}
|
|
388
421
|
return {
|
|
389
422
|
...mappedUpdate,
|
|
@@ -405,6 +438,15 @@ let EntityRepository = class EntityRepository {
|
|
|
405
438
|
}
|
|
406
439
|
return sql `${this.table.attributes} || '${JSON.stringify(attributes)}'::jsonb`;
|
|
407
440
|
}
|
|
441
|
+
async getTransformContext() {
|
|
442
|
+
if (isUndefined(this.#transformContext)) {
|
|
443
|
+
assertDefined(this.#encryptionSecret, 'Missing database encryption secret');
|
|
444
|
+
this.#transformContext = importSymmetricKey('AES-GCM', 256, this.#encryptionSecret, false).then((encryptionKey) => ({ encryptionKey }));
|
|
445
|
+
const transformContext = await this.#transformContext;
|
|
446
|
+
this.#transformContext = transformContext;
|
|
447
|
+
}
|
|
448
|
+
return this.#transformContext;
|
|
449
|
+
}
|
|
408
450
|
};
|
|
409
451
|
EntityRepository = __decorate([
|
|
410
452
|
Singleton({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ENCRYPTION_SECRET: import("../../injector/token.js").InjectionToken<Uint8Array<ArrayBufferLike>, never>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { BuildColumns, NotNull } from 'drizzle-orm';
|
|
2
|
+
import type { PgColumnBuilder, PgTableWithColumns } from 'drizzle-orm/pg-core';
|
|
3
|
+
import type { CamelCase, ConditionalPick, SnakeCase } from 'type-fest';
|
|
4
|
+
import type { JsonPath } from '../../json-path/json-path.js';
|
|
5
|
+
import type { Record } from '../../schema/index.js';
|
|
6
|
+
import type { AbstractConstructor, UnionToIntersection } from '../../types.js';
|
|
7
|
+
import type { Tagged } from '../../types/index.js';
|
|
8
|
+
import type { OrmColumnReflectionData } from '../decorators.js';
|
|
9
|
+
import type { EntityType } from '../entity.js';
|
|
10
|
+
import type { ColumnBuilder, EmbeddedConfigTag } from '../types.js';
|
|
11
|
+
export type ColumnDefinition = {
|
|
12
|
+
name: string;
|
|
13
|
+
objectPath: JsonPath;
|
|
14
|
+
type: PgColumnBuilder<any, any, any, any>;
|
|
15
|
+
reflectionData: OrmColumnReflectionData | undefined;
|
|
16
|
+
dereferenceObjectPath: (obj: Record) => any;
|
|
17
|
+
toDatabase: (value: unknown, context: TransformContext) => any;
|
|
18
|
+
fromDatabase: (value: unknown, context: TransformContext) => any;
|
|
19
|
+
};
|
|
20
|
+
export type TransformContext = {
|
|
21
|
+
encryptionKey?: CryptoKey;
|
|
22
|
+
};
|
|
23
|
+
type Column<Name extends string, T> = null extends T ? ColumnBuilder<T, Name> : NotNull<ColumnBuilder<T, Name>>;
|
|
24
|
+
export type ColumnPrefix<T> = T extends Tagged<unknown, EmbeddedConfigTag, {
|
|
25
|
+
prefix: infer Prefix;
|
|
26
|
+
}> ? Prefix extends string ? Prefix : '' : '';
|
|
27
|
+
export type PgTableFromType<S extends string, T extends AbstractConstructor, TableName extends string = T extends Required<EntityType> ? SnakeCase<T['entityName']> : string> = PgTableWithColumns<{
|
|
28
|
+
name: TableName;
|
|
29
|
+
schema: S;
|
|
30
|
+
columns: BuildColumns<TableName, {
|
|
31
|
+
[P in Exclude<keyof InstanceType<T>, keyof EmbeddedProperties<InstanceType<T>>>]: Column<CamelCase<Extract<P, string>>, InstanceType<T>[P]>;
|
|
32
|
+
} & UnionToIntersection<{
|
|
33
|
+
[P in keyof EmbeddedProperties<InstanceType<T>>]: EmbeddedColumns<InstanceType<T>[P], ColumnPrefix<InstanceType<T>[P]>>;
|
|
34
|
+
}[keyof EmbeddedProperties<InstanceType<T>>]>, 'pg'>;
|
|
35
|
+
dialect: 'pg';
|
|
36
|
+
}>;
|
|
37
|
+
export type EmbeddedProperties<T> = ConditionalPick<T, Tagged<unknown, EmbeddedConfigTag, {
|
|
38
|
+
prefix: any;
|
|
39
|
+
}>>;
|
|
40
|
+
export type EmbeddedColumns<T, Prefix extends string> = {
|
|
41
|
+
[P in keyof T as CamelCase<`${Prefix}${Extract<P, string>}`>]: Column<CamelCase<`${Prefix}${Extract<P, string>}`>, T[P]>;
|
|
42
|
+
};
|
|
43
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/orm/types.d.ts
CHANGED
|
@@ -25,5 +25,6 @@ export type DoublePrecision = Tagged<number, ColumnTypeTag, ReturnType<typeof do
|
|
|
25
25
|
export type Boolean = Tagged<number, ColumnTypeTag, ReturnType<typeof boolean>>;
|
|
26
26
|
export type NumericDate = Tagged<number, ColumnTypeTag, ReturnType<typeof date>>;
|
|
27
27
|
export type Timestamp = Tagged<number, ColumnTypeTag, ReturnType<typeof timestamp>>;
|
|
28
|
-
export type Bytea = Tagged<
|
|
28
|
+
export type Bytea = Tagged<Uint8Array, ColumnTypeTag, ReturnType<typeof bytea>>;
|
|
29
|
+
export type Encrypted<T> = Tagged<T, ColumnTypeTag, ReturnType<typeof bytea>>;
|
|
29
30
|
export { Array, Column, Embedded, Index, Integer, Json, NumericDate, PrimaryKey, References, Timestamp, Unique, Uuid };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tstdl/base",
|
|
3
|
-
"version": "0.92.
|
|
3
|
+
"version": "0.92.56",
|
|
4
4
|
"author": "Patrick Hein",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -17,12 +17,14 @@
|
|
|
17
17
|
"pub": "npm run build:production && rm -vf dist/test* && rm -vrf dist/tools/ && npm publish dist/",
|
|
18
18
|
"tsc:watch": "tsc --watch",
|
|
19
19
|
"tsc-alias:watch": "tsc-alias --watch",
|
|
20
|
-
"generate:orm": "npm run generate:drizzle:document-management && npm run generate:drizzle:authentication",
|
|
20
|
+
"generate:orm": "npm run generate:drizzle:document-management && npm run generate:drizzle:authentication && npm run generate:drizzle:mail",
|
|
21
21
|
"generate:drizzle:document-management": "drizzle-kit generate --config dist/document-management/server/drizzle.config.js",
|
|
22
22
|
"generate:drizzle:authentication": "drizzle-kit generate --config dist/authentication/server/drizzle.config.js",
|
|
23
|
-
"
|
|
23
|
+
"generate:drizzle:mail": "drizzle-kit generate --config dist/mail/drizzle.config.js",
|
|
24
|
+
"copy:orm": "npm run copy:document-management && npm run copy:authentication && npm run copy:mail",
|
|
24
25
|
"copy:document-management": "rm -rf ./dist/document-management/server/drizzle && cp -r ./source/document-management/server/drizzle ./dist/document-management/server/",
|
|
25
|
-
"copy:authentication": "rm -rf ./dist/authentication/server/drizzle && cp -r ./source/authentication/server/drizzle ./dist/authentication/server/"
|
|
26
|
+
"copy:authentication": "rm -rf ./dist/authentication/server/drizzle && cp -r ./source/authentication/server/drizzle ./dist/authentication/server/",
|
|
27
|
+
"copy:mail": "rm -rf ./dist/mail/drizzle && cp -r ./source/mail/drizzle ./dist/mail/"
|
|
26
28
|
},
|
|
27
29
|
"exports": {
|
|
28
30
|
"./tsconfig.json": "./tsconfig.json",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './mongo-mail-log.repository.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './mongo-mail-log.repository.js';
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { CollectionArgument } from '../../../database/mongo/index.js';
|
|
2
|
-
import { Collection, MongoEntityRepository } from '../../../database/mongo/index.js';
|
|
3
|
-
import { resolveArgumentType } from '../../../injector/index.js';
|
|
4
|
-
import type { Resolvable } from '../../../injector/interfaces.js';
|
|
5
|
-
import { Logger } from '../../../logger/index.js';
|
|
6
|
-
import type { MailLog } from '../../models/mail-log.model.js';
|
|
7
|
-
export type MongoMailLogRepositoryConfig = {
|
|
8
|
-
config?: MongoMailLogRepositoryArgument;
|
|
9
|
-
};
|
|
10
|
-
export type MongoMailLogRepositoryArgument = CollectionArgument<MailLog>;
|
|
11
|
-
export declare const mongoMailLogRepositoryConfig: MongoMailLogRepositoryConfig;
|
|
12
|
-
export declare class MongoMailLogRepository extends MongoEntityRepository<MailLog> implements Resolvable<MongoMailLogRepositoryArgument> {
|
|
13
|
-
readonly [resolveArgumentType]: MongoMailLogRepositoryArgument;
|
|
14
|
-
constructor(collection: Collection<MailLog>, logger: Logger);
|
|
15
|
-
}
|
|
16
|
-
export declare function configureMongoMailLogRepository(config?: Partial<MongoMailLogRepositoryConfig>): void;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
-
};
|
|
13
|
-
import { Collection, MongoEntityRepository, noopTransformer } from '../../../database/mongo/index.js';
|
|
14
|
-
import { ForwardArg, Singleton, resolveArgumentType } from '../../../injector/index.js';
|
|
15
|
-
import { Logger } from '../../../logger/index.js';
|
|
16
|
-
export const mongoMailLogRepositoryConfig = {};
|
|
17
|
-
const indexes = [];
|
|
18
|
-
let MongoMailLogRepository = class MongoMailLogRepository extends MongoEntityRepository {
|
|
19
|
-
constructor(collection, logger) {
|
|
20
|
-
super(collection, noopTransformer, { logger, indexes });
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
MongoMailLogRepository = __decorate([
|
|
24
|
-
Singleton({
|
|
25
|
-
defaultArgumentProvider: () => mongoMailLogRepositoryConfig.config
|
|
26
|
-
}),
|
|
27
|
-
__param(0, ForwardArg()),
|
|
28
|
-
__metadata("design:paramtypes", [Collection, Logger])
|
|
29
|
-
], MongoMailLogRepository);
|
|
30
|
-
export { MongoMailLogRepository };
|
|
31
|
-
export function configureMongoMailLogRepository(config = {}) {
|
|
32
|
-
mongoMailLogRepositoryConfig.config = config.config ?? mongoMailLogRepositoryConfig.config;
|
|
33
|
-
}
|