nestjs-query-mikro-orm 0.1.0 → 0.1.2

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/dist/index.d.cts CHANGED
@@ -342,6 +342,7 @@ declare abstract class RelationQueryService<Entity extends object> {
342
342
  * @param query - A query to filter, page or sort relations.
343
343
  */
344
344
  private batchFindRelations;
345
+ private isRelationClassIdentity;
345
346
  private getRelationMeta;
346
347
  private getRelationEntity;
347
348
  private getRelations;
package/dist/index.d.ts CHANGED
@@ -342,6 +342,7 @@ declare abstract class RelationQueryService<Entity extends object> {
342
342
  * @param query - A query to filter, page or sort relations.
343
343
  */
344
344
  private batchFindRelations;
345
+ private isRelationClassIdentity;
345
346
  private getRelationMeta;
346
347
  private getRelationEntity;
347
348
  private getRelations;
package/dist/index.mjs CHANGED
@@ -1,9 +1,7 @@
1
1
  import { MikroOrmModule, getRepositoryToken } from '@mikro-orm/nestjs';
2
- import { getFilterFields, AssemblerFactory, AssemblerSerializer, AssemblerDeserializer, getQueryServiceToken } from '@ptc-org/nestjs-query-core';
2
+ import { getFilterFields, AssemblerFactory, getQueryServiceToken } from '@ptc-org/nestjs-query-core';
3
3
  import { raw, wrap } from '@mikro-orm/core';
4
- import { getAssemblerSerializer } from '@ptc-org/nestjs-query-core/src/assemblers/assembler.serializer';
5
4
  import { BadRequestException, NotFoundException, MethodNotAllowedException } from '@nestjs/common';
6
- import { instanceToPlain } from 'class-transformer';
7
5
  import merge from 'lodash.merge';
8
6
 
9
7
  var __defProp = Object.defineProperty;
@@ -834,7 +832,14 @@ var RelationQueryBuilder = class {
834
832
  const entityKeys = Object.keys(entityAsRecord);
835
833
  const matchingKey = entityKeys.find((key) => {
836
834
  const keyLower = key.toLowerCase();
837
- return keyLower.endsWith("id") && relationNameLower.includes(keyLower.replace(/id$/, ""));
835
+ if (keyLower === "id" || !keyLower.endsWith("id")) {
836
+ return false;
837
+ }
838
+ const base = keyLower.replace(/id$/, "");
839
+ if (!base) {
840
+ return false;
841
+ }
842
+ return relationNameLower.includes(base);
838
843
  });
839
844
  if (matchingKey) {
840
845
  fkValue = entityAsRecord[matchingKey];
@@ -1168,6 +1173,10 @@ var RelationQueryService = class {
1168
1173
  if (Array.isArray(dto)) {
1169
1174
  return this.batchQueryRelations(RelationClass, relationName, dto, query);
1170
1175
  }
1176
+ if (this.isRelationClassIdentity(RelationClass, relationName)) {
1177
+ const relationQueryBuilder2 = this.getRelationQueryBuilder(relationName);
1178
+ return await relationQueryBuilder2.selectAndExecute(dto, query);
1179
+ }
1171
1180
  const assembler = AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1172
1181
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1173
1182
  return assembler.convertToDTOs(await relationQueryBuilder.selectAndExecute(dto, assembler.convertQuery(query)));
@@ -1201,6 +1210,16 @@ var RelationQueryService = class {
1201
1210
  if (Array.isArray(dto)) {
1202
1211
  return this.batchFindRelations(RelationClass, relationName, dto, opts);
1203
1212
  }
1213
+ if (this.isRelationClassIdentity(RelationClass, relationName)) {
1214
+ const relationQueryBuilder2 = this.getRelationQueryBuilder(relationName);
1215
+ const relations2 = await relationQueryBuilder2.selectAndExecute(dto, {
1216
+ filter: opts?.filter,
1217
+ paging: {
1218
+ limit: 1
1219
+ }
1220
+ });
1221
+ return relations2[0];
1222
+ }
1204
1223
  const assembler = AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1205
1224
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1206
1225
  const relations = await relationQueryBuilder.selectAndExecute(dto, {
@@ -1221,10 +1240,20 @@ var RelationQueryService = class {
1221
1240
  */
1222
1241
  async addRelations(relationName, id, relationIds, opts) {
1223
1242
  const entity = await this.getById(id, opts);
1243
+ const meta = this.getRelationMeta(relationName);
1224
1244
  const relations = await this.getRelations(relationName, relationIds, opts?.relationFilter);
1225
1245
  if (!this.foundAllRelations(relationIds, relations)) {
1226
1246
  throw new Error(`Unable to find all ${relationName} to add to ${this.EntityClass.name}`);
1227
1247
  }
1248
+ if (meta.kind === "1:m" && meta.mappedBy) {
1249
+ for (const relation of relations) {
1250
+ wrap(relation).assign({
1251
+ [meta.mappedBy]: entity
1252
+ });
1253
+ }
1254
+ await this.repo.getEntityManager().flush();
1255
+ return entity;
1256
+ }
1228
1257
  const collection = entity[relationName];
1229
1258
  if (collection && typeof collection.add === "function") {
1230
1259
  for (const relation of relations) {
@@ -1245,12 +1274,33 @@ var RelationQueryService = class {
1245
1274
  */
1246
1275
  async setRelations(relationName, id, relationIds, opts) {
1247
1276
  const entity = await this.getById(id, opts);
1277
+ const meta = this.getRelationMeta(relationName);
1248
1278
  const relations = await this.getRelations(relationName, relationIds, opts?.relationFilter);
1249
1279
  if (relationIds.length) {
1250
1280
  if (!this.foundAllRelations(relationIds, relations)) {
1251
1281
  throw new Error(`Unable to find all ${relationName} to set on ${this.EntityClass.name}`);
1252
1282
  }
1253
1283
  }
1284
+ if (meta.kind === "1:m" && meta.mappedBy) {
1285
+ const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1286
+ const currentRelations = await relationQueryBuilder.selectAndExecute(entity, {});
1287
+ const nextSet = new Set(relations.map((r) => wrap(r).getPrimaryKey()));
1288
+ for (const currentRelation of currentRelations) {
1289
+ const currentPk = wrap(currentRelation).getPrimaryKey();
1290
+ if (!nextSet.has(currentPk)) {
1291
+ wrap(currentRelation).assign({
1292
+ [meta.mappedBy]: null
1293
+ });
1294
+ }
1295
+ }
1296
+ for (const relation of relations) {
1297
+ wrap(relation).assign({
1298
+ [meta.mappedBy]: entity
1299
+ });
1300
+ }
1301
+ await this.repo.getEntityManager().flush();
1302
+ return entity;
1303
+ }
1254
1304
  const collection = entity[relationName];
1255
1305
  if (collection && typeof collection.set === "function") {
1256
1306
  await collection.init();
@@ -1290,10 +1340,20 @@ var RelationQueryService = class {
1290
1340
  */
1291
1341
  async removeRelations(relationName, id, relationIds, opts) {
1292
1342
  const entity = await this.getById(id, opts);
1343
+ const meta = this.getRelationMeta(relationName);
1293
1344
  const relations = await this.getRelations(relationName, relationIds, opts?.relationFilter);
1294
1345
  if (!this.foundAllRelations(relationIds, relations)) {
1295
1346
  throw new Error(`Unable to find all ${relationName} to remove from ${this.EntityClass.name}`);
1296
1347
  }
1348
+ if (meta.kind === "1:m" && meta.mappedBy) {
1349
+ for (const relation of relations) {
1350
+ wrap(relation).assign({
1351
+ [meta.mappedBy]: null
1352
+ });
1353
+ }
1354
+ await this.repo.getEntityManager().flush();
1355
+ return entity;
1356
+ }
1297
1357
  const collection = entity[relationName];
1298
1358
  if (collection && typeof collection.remove === "function") {
1299
1359
  await collection.init();
@@ -1322,14 +1382,25 @@ var RelationQueryService = class {
1322
1382
  const meta = this.getRelationMeta(relationName);
1323
1383
  if (meta.kind === "1:1" || meta.kind === "m:1") {
1324
1384
  const fkFieldName = `${relationName}Id`;
1325
- const assignData = {
1326
- [relationName]: null
1327
- };
1328
- if (fkFieldName in entity) {
1385
+ const assignData = {};
1386
+ const ownDescriptor = Object.getOwnPropertyDescriptor(entity, fkFieldName);
1387
+ const protoDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(entity), fkFieldName);
1388
+ const descriptor = ownDescriptor ?? protoDescriptor;
1389
+ const canAssignFk = fkFieldName in entity && (!descriptor || Boolean(descriptor.set) || descriptor.writable === true);
1390
+ if (canAssignFk) {
1329
1391
  assignData[fkFieldName] = null;
1392
+ } else {
1393
+ assignData[relationName] = null;
1330
1394
  }
1331
1395
  wrap(entity).assign(assignData);
1332
1396
  } else {
1397
+ if (meta.kind === "1:m" && meta.mappedBy) {
1398
+ wrap(relation).assign({
1399
+ [meta.mappedBy]: null
1400
+ });
1401
+ await this.repo.getEntityManager().flush();
1402
+ return entity;
1403
+ }
1333
1404
  const collection = entity[relationName];
1334
1405
  if (collection && typeof collection.remove === "function") {
1335
1406
  await collection.init();
@@ -1350,13 +1421,14 @@ var RelationQueryService = class {
1350
1421
  * @param query - A query to filter, page or sort relations.
1351
1422
  */
1352
1423
  async batchQueryRelations(RelationClass, relationName, entities, query) {
1353
- const assembler = AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1424
+ const bypassAssembler = this.isRelationClassIdentity(RelationClass, relationName);
1425
+ const assembler = bypassAssembler ? void 0 : AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1354
1426
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1355
- const convertedQuery = assembler.convertQuery(query);
1427
+ const convertedQuery = assembler ? assembler.convertQuery(query) : query;
1356
1428
  const results = /* @__PURE__ */ new Map();
1357
1429
  await Promise.all(entities.map(async (entity) => {
1358
1430
  const relations = await relationQueryBuilder.selectAndExecute(entity, convertedQuery);
1359
- const relationDtos = await assembler.convertToDTOs(relations);
1431
+ const relationDtos = bypassAssembler ? relations : await assembler.convertToDTOs(relations);
1360
1432
  if (relationDtos.length > 0) {
1361
1433
  results.set(entity, relationDtos);
1362
1434
  }
@@ -1426,6 +1498,10 @@ var RelationQueryService = class {
1426
1498
  });
1427
1499
  return results;
1428
1500
  }
1501
+ isRelationClassIdentity(RelationClass, relationName) {
1502
+ const relationEntity = this.getRelationEntity(relationName);
1503
+ return RelationClass === relationEntity || RelationClass.name === relationEntity.name;
1504
+ }
1429
1505
  getRelationMeta(relationName) {
1430
1506
  const em = this.repo.getEntityManager();
1431
1507
  const metadata = em.getMetadata().get(this.repo.getEntityName());
@@ -1436,12 +1512,14 @@ var RelationQueryService = class {
1436
1512
  return {
1437
1513
  kind: relationMeta.kind,
1438
1514
  type: relationMeta.type,
1439
- entity: relationMeta.entity
1515
+ entity: relationMeta.entity,
1516
+ mappedBy: relationMeta.mappedBy
1440
1517
  };
1441
1518
  }
1442
1519
  getRelationEntity(relationName) {
1443
1520
  const relationMeta = this.getRelationMeta(relationName);
1444
- return relationMeta.entity();
1521
+ const entity = relationMeta.entity();
1522
+ return entity && "class" in entity ? entity.class : entity;
1445
1523
  }
1446
1524
  async getRelations(relationName, ids, filter) {
1447
1525
  const em = this.repo.getEntityManager();
@@ -1485,28 +1563,6 @@ var MikroOrmQueryService = class extends RelationQueryService {
1485
1563
  super(), this.repo = repo;
1486
1564
  this.filterQueryBuilder = opts?.filterQueryBuilder ?? new FilterQueryBuilder(this.repo);
1487
1565
  this.useSoftDelete = opts?.useSoftDelete ?? false;
1488
- const serializer = getAssemblerSerializer(this.EntityClass);
1489
- if (!serializer) {
1490
- AssemblerSerializer((e) => {
1491
- const json = instanceToPlain(e, {
1492
- enableImplicitConversion: true,
1493
- excludeExtraneousValues: true,
1494
- exposeDefaultValues: true
1495
- });
1496
- const jsonWithRemovedEmptyObjects = Object.fromEntries(Object.entries(json).filter(([, value]) => !(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0)));
1497
- const wrapped = wrap(e, true);
1498
- const ormJson = "toObject" in wrapped ? wrapped.toObject() : {};
1499
- const data = {
1500
- ...ormJson,
1501
- ...jsonWithRemovedEmptyObjects
1502
- };
1503
- return data;
1504
- })(this.EntityClass);
1505
- AssemblerDeserializer((d) => {
1506
- const entity = this.repo.getEntityManager().create(this.EntityClass, instanceToPlain(d));
1507
- return entity;
1508
- })(this.EntityClass);
1509
- }
1510
1566
  }
1511
1567
  get EntityClass() {
1512
1568
  const em = this.repo.getEntityManager();