@koalarx/nest 3.1.13 → 3.1.15
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/core/database/repository.base.d.ts +1 -0
- package/core/database/repository.base.js +68 -15
- package/core/utils/generate-prisma-include-schema.js +16 -10
- package/package.json +1 -1
- package/test/utils/create-e2e-database.d.ts +6 -1
- package/test/utils/create-e2e-database.js +4 -13
- package/test/utils/e2e-database-client.d.ts +7 -0
- package/test/utils/e2e-database-client.js +12 -0
- package/tsconfig.lib.tsbuildinfo +1 -1
- package/test/utils/drop-e2e-database.d.ts +0 -2
- package/test/utils/drop-e2e-database.js +0 -33
|
@@ -28,6 +28,7 @@ export declare abstract class RepositoryBase<TEntity extends EntityBase<TEntity>
|
|
|
28
28
|
private findManySchema;
|
|
29
29
|
private createEntity;
|
|
30
30
|
private orphanRemoval;
|
|
31
|
+
private getIdOnEntity;
|
|
31
32
|
private loadRelationForEntity;
|
|
32
33
|
private enrichEntityWithRelations;
|
|
33
34
|
private persistRelations;
|
|
@@ -17,23 +17,35 @@ class RepositoryBase {
|
|
|
17
17
|
this._modelName = modelName;
|
|
18
18
|
this._includeFindMany = (0, generate_prisma_include_schema_1.generateIncludeSchema)({
|
|
19
19
|
forList: true,
|
|
20
|
-
deepLimit:
|
|
20
|
+
deepLimit: 2,
|
|
21
21
|
entity: this._modelName,
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
getIdPropName(entity) {
|
|
25
|
-
|
|
25
|
+
const idConfig = Reflect.getMetadata('entity:id', entity ? entity.constructor.prototype : this._modelName.prototype);
|
|
26
|
+
if (idConfig) {
|
|
27
|
+
if (idConfig.single) {
|
|
28
|
+
return idConfig.single;
|
|
29
|
+
}
|
|
30
|
+
else if (idConfig.composite) {
|
|
31
|
+
return idConfig.composite;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return 'id';
|
|
26
35
|
}
|
|
27
36
|
getWhereByIdSchema(entity, value) {
|
|
28
37
|
const propIdName = this.getIdPropName(entity);
|
|
29
38
|
if (Array.isArray(propIdName)) {
|
|
30
39
|
const whereSchema = {};
|
|
31
40
|
propIdName.forEach((propName) => {
|
|
32
|
-
whereSchema[propName] =
|
|
41
|
+
whereSchema[propName] =
|
|
42
|
+
typeof value === 'object' ? value[propName] : value;
|
|
33
43
|
});
|
|
34
44
|
return whereSchema;
|
|
35
45
|
}
|
|
36
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
[propIdName]: typeof value === 'object' ? value[propIdName] : value,
|
|
48
|
+
};
|
|
37
49
|
}
|
|
38
50
|
getConnectPrismaSchemaForRelation(entity, data) {
|
|
39
51
|
return {
|
|
@@ -74,14 +86,14 @@ class RepositoryBase {
|
|
|
74
86
|
}
|
|
75
87
|
if (instance instanceof entity_base_1.EntityBase) {
|
|
76
88
|
selectSchema[prop.name] = {
|
|
77
|
-
select: this.
|
|
89
|
+
select: this.getWhereByIdSchema(instance, true),
|
|
78
90
|
};
|
|
79
91
|
}
|
|
80
92
|
else if (instance instanceof list_1.List) {
|
|
81
93
|
const list = new entity()[prop.name];
|
|
82
94
|
const entityInstance = list.entityType;
|
|
83
95
|
selectSchema[prop.name] = {
|
|
84
|
-
select: this.
|
|
96
|
+
select: this.getWhereByIdSchema(new entityInstance(), true),
|
|
85
97
|
};
|
|
86
98
|
}
|
|
87
99
|
else {
|
|
@@ -171,6 +183,22 @@ class RepositoryBase {
|
|
|
171
183
|
});
|
|
172
184
|
}
|
|
173
185
|
}
|
|
186
|
+
else if (entity[key] instanceof entity_base_1.EntityBase) {
|
|
187
|
+
const entityInstance = entity[key];
|
|
188
|
+
const modelName = entity[key].constructor.name;
|
|
189
|
+
if (entity[key]._action === entity_base_1.EntityActionType.update) {
|
|
190
|
+
relationUpdates.push({
|
|
191
|
+
modelName: (0, KlString_1.toCamelCase)(modelName),
|
|
192
|
+
entityInstance,
|
|
193
|
+
schema: {
|
|
194
|
+
where: { id: entityInstance._id },
|
|
195
|
+
data: this.entityToPrisma(entityInstance),
|
|
196
|
+
select: this.getSelectRootPrismaSchema(entityInstance),
|
|
197
|
+
},
|
|
198
|
+
relations: this.listRelationEntities(entityInstance),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
174
202
|
});
|
|
175
203
|
return { relationCreates, relationUpdates, relationDeletes };
|
|
176
204
|
}
|
|
@@ -243,15 +271,28 @@ class RepositoryBase {
|
|
|
243
271
|
.forEach((key) => (where[key] = entity[key]));
|
|
244
272
|
return client[(0, KlString_1.toCamelCase)(entity.constructor.name)].delete({ where });
|
|
245
273
|
}
|
|
246
|
-
|
|
274
|
+
getIdOnEntity(entity, data) {
|
|
275
|
+
const propIdName = this.getIdPropName(entity);
|
|
276
|
+
if (Array.isArray(propIdName)) {
|
|
277
|
+
const idValues = [];
|
|
278
|
+
propIdName.forEach((propName) => {
|
|
279
|
+
idValues.push(data[propName]);
|
|
280
|
+
});
|
|
281
|
+
return idValues.join('-');
|
|
282
|
+
}
|
|
283
|
+
return data[propIdName];
|
|
284
|
+
}
|
|
285
|
+
async loadRelationForEntity(where, entity, cache) {
|
|
247
286
|
return this._context[(0, KlString_1.toCamelCase)((0, KlString_1.toCamelCase)(entity.name))]
|
|
248
|
-
.
|
|
287
|
+
.findFirst({
|
|
249
288
|
select: this.getSelectWithRelationsId(entity),
|
|
250
289
|
where,
|
|
251
290
|
})
|
|
252
|
-
.then((data) => this.enrichEntityWithRelations(entity, data));
|
|
291
|
+
.then((data) => this.enrichEntityWithRelations(entity, data, cache));
|
|
253
292
|
}
|
|
254
|
-
async enrichEntityWithRelations(entity, data) {
|
|
293
|
+
async enrichEntityWithRelations(entity, data, cache = new Map()) {
|
|
294
|
+
if (!data)
|
|
295
|
+
return data;
|
|
255
296
|
const relationQueries = [];
|
|
256
297
|
const relationKeys = [];
|
|
257
298
|
const allProps = auto_mapping_list_1.AutoMappingList.getAllProps(entity);
|
|
@@ -264,15 +305,27 @@ class RepositoryBase {
|
|
|
264
305
|
relationKeys.push(propName);
|
|
265
306
|
const items = [];
|
|
266
307
|
data[propName].forEach((item) => {
|
|
267
|
-
|
|
308
|
+
const cacheKey = `${entity.constructor.name}-${propName}-${this.getIdOnEntity(new entityInstance(), item)}`;
|
|
309
|
+
if (cache.has(cacheKey)) {
|
|
310
|
+
items.push(Promise.resolve(cache.get(cacheKey)));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
cache.set(cacheKey, item);
|
|
314
|
+
items.push(this.loadRelationForEntity(item, entityInstance, cache));
|
|
268
315
|
});
|
|
269
316
|
relationQueries.push(Promise.all(items));
|
|
270
317
|
return;
|
|
271
318
|
}
|
|
272
319
|
const relationEntity = auto_mapping_list_1.AutoMappingList.getSourceByName(propDef?.type ?? '');
|
|
273
320
|
if (relationEntity && data[propName]) {
|
|
321
|
+
const cacheKey = `${entity.constructor.name}-${propName}-${this.getIdOnEntity(new relationEntity(), data[propName])}`;
|
|
322
|
+
if (cache.has(cacheKey)) {
|
|
323
|
+
data[propName] = cache.get(cacheKey);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
cache.set(cacheKey, data[propName]);
|
|
274
327
|
relationKeys.push(propName);
|
|
275
|
-
relationQueries.push(this.loadRelationForEntity(this.getWhereByIdSchema(relationEntity, data[propName]), relationEntity));
|
|
328
|
+
relationQueries.push(this.loadRelationForEntity(this.getWhereByIdSchema(relationEntity, data[propName]), relationEntity, cache));
|
|
276
329
|
}
|
|
277
330
|
});
|
|
278
331
|
if (relationQueries.length > 0) {
|
|
@@ -341,7 +394,7 @@ class RepositoryBase {
|
|
|
341
394
|
});
|
|
342
395
|
if (!data)
|
|
343
396
|
return null;
|
|
344
|
-
const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, data);
|
|
397
|
+
const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, { ...data });
|
|
345
398
|
return this.createEntity(enrichedEntity);
|
|
346
399
|
}
|
|
347
400
|
async findFirst(where) {
|
|
@@ -351,7 +404,7 @@ class RepositoryBase {
|
|
|
351
404
|
});
|
|
352
405
|
if (!data)
|
|
353
406
|
return null;
|
|
354
|
-
const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, data);
|
|
407
|
+
const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, { ...data });
|
|
355
408
|
return this.createEntity(enrichedEntity);
|
|
356
409
|
}
|
|
357
410
|
async findUnique(where) {
|
|
@@ -361,7 +414,7 @@ class RepositoryBase {
|
|
|
361
414
|
});
|
|
362
415
|
if (!data)
|
|
363
416
|
return null;
|
|
364
|
-
const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, data);
|
|
417
|
+
const enrichedEntity = await this.enrichEntityWithRelations(this._modelName.prototype.constructor, { ...data });
|
|
365
418
|
return this.createEntity(enrichedEntity);
|
|
366
419
|
}
|
|
367
420
|
async findMany(where, pagination) {
|
|
@@ -2,33 +2,39 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateIncludeSchema = generateIncludeSchema;
|
|
4
4
|
const entity_base_1 = require("../database/entity.base");
|
|
5
|
-
const list_1 = require("./list");
|
|
6
5
|
const auto_mapping_list_1 = require("../mapping/auto-mapping-list");
|
|
6
|
+
const list_1 = require("./list");
|
|
7
7
|
function generateIncludeSchema({ forList, entity, deepIncludeCount = 0, deepLimit, }) {
|
|
8
8
|
if (deepIncludeCount >= deepLimit) {
|
|
9
9
|
return true;
|
|
10
10
|
}
|
|
11
11
|
const includeSchema = {};
|
|
12
|
+
const props = auto_mapping_list_1.AutoMappingList.getAllProps(entity);
|
|
12
13
|
const entityInstance = new entity();
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
props.forEach((prop) => {
|
|
15
|
+
let instance;
|
|
16
|
+
try {
|
|
17
|
+
instance = new (prop.type())();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
instance = null;
|
|
21
|
+
}
|
|
16
22
|
let includes;
|
|
17
|
-
if (
|
|
23
|
+
if (instance instanceof list_1.List) {
|
|
18
24
|
if (forList) {
|
|
19
|
-
includeSchema[
|
|
25
|
+
includeSchema[prop.name] = true;
|
|
20
26
|
}
|
|
21
27
|
else {
|
|
22
28
|
includes = generateIncludeSchema({
|
|
23
29
|
forList,
|
|
24
|
-
entity:
|
|
30
|
+
entity: instance.entityType,
|
|
25
31
|
deepLimit,
|
|
26
32
|
deepIncludeCount: deepIncludeCount > 0 ? deepIncludeCount + 1 : 1,
|
|
27
33
|
});
|
|
28
34
|
}
|
|
29
35
|
}
|
|
30
36
|
else {
|
|
31
|
-
const propDefinitions = auto_mapping_list_1.AutoMappingList.getPropDefinitions(entityInstance.constructor,
|
|
37
|
+
const propDefinitions = auto_mapping_list_1.AutoMappingList.getPropDefinitions(entityInstance.constructor, prop.name);
|
|
32
38
|
if (propDefinitions) {
|
|
33
39
|
const source = auto_mapping_list_1.AutoMappingList.getSourceByName(propDefinitions.type);
|
|
34
40
|
if (source?.prototype instanceof entity_base_1.EntityBase) {
|
|
@@ -43,10 +49,10 @@ function generateIncludeSchema({ forList, entity, deepIncludeCount = 0, deepLimi
|
|
|
43
49
|
}
|
|
44
50
|
if (includes) {
|
|
45
51
|
if (includes === true || Object.keys(includes).length > 0) {
|
|
46
|
-
includeSchema[
|
|
52
|
+
includeSchema[prop.name] = includes;
|
|
47
53
|
}
|
|
48
54
|
else {
|
|
49
|
-
includeSchema[
|
|
55
|
+
includeSchema[prop.name] = true;
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
});
|
package/package.json
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
1
2
|
import 'dotenv/config';
|
|
2
|
-
|
|
3
|
+
import { E2EDatabaseClient } from './e2e-database-client';
|
|
4
|
+
export declare function createE2EDatabase<T extends E2EDatabaseClient>(runtime: "node" | "bun" | undefined, clientInstance: Type<T>): Promise<{
|
|
5
|
+
client: T;
|
|
6
|
+
schemaId: `${string}-${string}-${string}-${string}-${string}`;
|
|
7
|
+
}>;
|
|
@@ -4,7 +4,6 @@ exports.createE2EDatabase = createE2EDatabase;
|
|
|
4
4
|
require("dotenv/config");
|
|
5
5
|
const node_child_process_1 = require("node:child_process");
|
|
6
6
|
const node_crypto_1 = require("node:crypto");
|
|
7
|
-
const pg_1 = require("pg");
|
|
8
7
|
function generateUniqueDatabaseURL() {
|
|
9
8
|
const schemaId = (0, node_crypto_1.randomUUID)();
|
|
10
9
|
if (!process.env.DATABASE_URL) {
|
|
@@ -17,31 +16,23 @@ function generateUniqueDatabaseURL() {
|
|
|
17
16
|
schemaId,
|
|
18
17
|
};
|
|
19
18
|
}
|
|
20
|
-
async function createE2EDatabase(runtime = 'node') {
|
|
19
|
+
async function createE2EDatabase(runtime = 'node', clientInstance) {
|
|
21
20
|
const { url, schemaId } = generateUniqueDatabaseURL();
|
|
22
21
|
process.env.DATABASE_URL = url;
|
|
23
|
-
process.env.DIRECT_URL = url;
|
|
24
22
|
process.env.PRISMA_SCHEMA_DISABLE_ADVISORY_LOCK = 'true';
|
|
25
23
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const pool = new pg_1.Pool({ connectionString: baseUrl.toString() });
|
|
29
|
-
try {
|
|
30
|
-
await pool.query(`CREATE DATABASE "${schemaId}"`);
|
|
31
|
-
}
|
|
32
|
-
finally {
|
|
33
|
-
await pool.end();
|
|
34
|
-
}
|
|
24
|
+
const client = new clientInstance(url, schemaId);
|
|
25
|
+
await client.createDatabase(schemaId);
|
|
35
26
|
const env = { ...process.env, DATABASE_URL: url, DIRECT_URL: url };
|
|
36
27
|
(0, node_child_process_1.execSync)(`${runtime}x prisma migrate deploy`, {
|
|
37
28
|
cwd: process.cwd(),
|
|
38
29
|
env,
|
|
39
30
|
stdio: 'inherit',
|
|
40
31
|
});
|
|
32
|
+
return { client, schemaId };
|
|
41
33
|
}
|
|
42
34
|
catch (error) {
|
|
43
35
|
console.error('Erro ao criar banco de dados e2e:', error);
|
|
44
36
|
throw error;
|
|
45
37
|
}
|
|
46
|
-
return schemaId;
|
|
47
38
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare abstract class E2EDatabaseClient {
|
|
2
|
+
protected readonly url: string;
|
|
3
|
+
protected readonly schemaName: string;
|
|
4
|
+
constructor(url: string, schemaName: string);
|
|
5
|
+
abstract createDatabase(schemaName: string): Promise<void>;
|
|
6
|
+
abstract dropDatabase(): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.E2EDatabaseClient = void 0;
|
|
4
|
+
class E2EDatabaseClient {
|
|
5
|
+
url;
|
|
6
|
+
schemaName;
|
|
7
|
+
constructor(url, schemaName) {
|
|
8
|
+
this.url = url;
|
|
9
|
+
this.schemaName = schemaName;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.E2EDatabaseClient = E2EDatabaseClient;
|