nestjs-query-mikro-orm 0.0.9 → 0.1.1

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
@@ -1,6 +1,6 @@
1
1
  import { EntityName, AnyEntity, FilterQuery, EntityMetadata, EntityRepository } from '@mikro-orm/core';
2
2
  import { DynamicModule, FactoryProvider } from '@nestjs/common';
3
- import { Filter, Query, SortField, FilterComparisonOperators, CommonFieldComparisonBetweenType, AggregateQuery, AggregateResponse, Class, GetByIdOptions, FindRelationOptions, ModifyRelationOptions, QueryService, DeepPartial, FindByIdOptions, UpdateOneOptions, UpdateManyResponse, DeleteOneOptions, DeleteManyResponse, Filterable } from '@nestjs-query/core';
3
+ import { Filter, Query, SortField, FilterComparisonOperators, CommonFieldComparisonBetweenType, AggregateQuery, AggregateResponse, Class, GetByIdOptions, FindRelationOptions, ModifyRelationOptions, QueryService, DeepPartial, FindByIdOptions, UpdateOneOptions, UpdateManyResponse, DeleteOneOptions, DeleteManyResponse, Filterable } from '@ptc-org/nestjs-query-core';
4
4
 
5
5
  declare class NestjsQueryMikroOrmModule {
6
6
  static forFeature(entities: EntityName<AnyEntity>[], contextName?: string): DynamicModule;
@@ -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;
@@ -375,7 +376,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
375
376
  constructor(repo: EntityRepository<Entity>, opts?: MikroOrmQueryServiceOpts<Entity>);
376
377
  get EntityClass(): Class<Entity>;
377
378
  /**
378
- * Query for multiple entities, using a Query from `@nestjs-query/core`.
379
+ * Query for multiple entities, using a Query from `@ptc-org/nestjs-query-core`.
379
380
  *
380
381
  * @example
381
382
  * ```ts
@@ -450,7 +451,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
450
451
  */
451
452
  updateOne(id: number | string, update: DeepPartial<Entity>, opts?: UpdateOneOptions<Entity>): Promise<Entity>;
452
453
  /**
453
- * Update multiple entities with a `@nestjs-query/core` Filter.
454
+ * Update multiple entities with a `@ptc-org/nestjs-query-core` Filter.
454
455
  *
455
456
  * @example
456
457
  * ```ts
@@ -477,7 +478,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
477
478
  */
478
479
  deleteOne(id: string | number, opts?: DeleteOneOptions<Entity>): Promise<Entity>;
479
480
  /**
480
- * Delete multiple records with a `@nestjs-query/core` `Filter`.
481
+ * Delete multiple records with a `@ptc-org/nestjs-query-core` `Filter`.
481
482
  *
482
483
  * @example
483
484
  *
@@ -504,7 +505,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
504
505
  */
505
506
  restoreOne(id: string | number, opts?: Filterable<Entity>): Promise<Entity>;
506
507
  /**
507
- * Restores multiple records with a `@nestjs-query/core` `Filter`.
508
+ * Restores multiple records with a `@ptc-org/nestjs-query-core` `Filter`.
508
509
  *
509
510
  * @example
510
511
  *
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { EntityName, AnyEntity, FilterQuery, EntityMetadata, EntityRepository } from '@mikro-orm/core';
2
2
  import { DynamicModule, FactoryProvider } from '@nestjs/common';
3
- import { Filter, Query, SortField, FilterComparisonOperators, CommonFieldComparisonBetweenType, AggregateQuery, AggregateResponse, Class, GetByIdOptions, FindRelationOptions, ModifyRelationOptions, QueryService, DeepPartial, FindByIdOptions, UpdateOneOptions, UpdateManyResponse, DeleteOneOptions, DeleteManyResponse, Filterable } from '@nestjs-query/core';
3
+ import { Filter, Query, SortField, FilterComparisonOperators, CommonFieldComparisonBetweenType, AggregateQuery, AggregateResponse, Class, GetByIdOptions, FindRelationOptions, ModifyRelationOptions, QueryService, DeepPartial, FindByIdOptions, UpdateOneOptions, UpdateManyResponse, DeleteOneOptions, DeleteManyResponse, Filterable } from '@ptc-org/nestjs-query-core';
4
4
 
5
5
  declare class NestjsQueryMikroOrmModule {
6
6
  static forFeature(entities: EntityName<AnyEntity>[], contextName?: string): DynamicModule;
@@ -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;
@@ -375,7 +376,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
375
376
  constructor(repo: EntityRepository<Entity>, opts?: MikroOrmQueryServiceOpts<Entity>);
376
377
  get EntityClass(): Class<Entity>;
377
378
  /**
378
- * Query for multiple entities, using a Query from `@nestjs-query/core`.
379
+ * Query for multiple entities, using a Query from `@ptc-org/nestjs-query-core`.
379
380
  *
380
381
  * @example
381
382
  * ```ts
@@ -450,7 +451,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
450
451
  */
451
452
  updateOne(id: number | string, update: DeepPartial<Entity>, opts?: UpdateOneOptions<Entity>): Promise<Entity>;
452
453
  /**
453
- * Update multiple entities with a `@nestjs-query/core` Filter.
454
+ * Update multiple entities with a `@ptc-org/nestjs-query-core` Filter.
454
455
  *
455
456
  * @example
456
457
  * ```ts
@@ -477,7 +478,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
477
478
  */
478
479
  deleteOne(id: string | number, opts?: DeleteOneOptions<Entity>): Promise<Entity>;
479
480
  /**
480
- * Delete multiple records with a `@nestjs-query/core` `Filter`.
481
+ * Delete multiple records with a `@ptc-org/nestjs-query-core` `Filter`.
481
482
  *
482
483
  * @example
483
484
  *
@@ -504,7 +505,7 @@ declare class MikroOrmQueryService<Entity extends object> extends RelationQueryS
504
505
  */
505
506
  restoreOne(id: string | number, opts?: Filterable<Entity>): Promise<Entity>;
506
507
  /**
507
- * Restores multiple records with a `@nestjs-query/core` `Filter`.
508
+ * Restores multiple records with a `@ptc-org/nestjs-query-core` `Filter`.
508
509
  *
509
510
  * @example
510
511
  *
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { MikroOrmModule, getRepositoryToken } from '@mikro-orm/nestjs';
2
- import { getFilterFields, AssemblerFactory, AssemblerSerializer, AssemblerDeserializer, getQueryServiceToken } from '@nestjs-query/core';
2
+ import { getFilterFields, AssemblerFactory, AssemblerSerializer, AssemblerDeserializer, getQueryServiceToken } from '@ptc-org/nestjs-query-core';
3
3
  import { raw, wrap } from '@mikro-orm/core';
4
- import { getAssemblerSerializer } from '@nestjs-query/core/dist/src/assemblers/assembler.serializer';
4
+ import { getAssemblerSerializer } from '@ptc-org/nestjs-query-core/src/assemblers/assembler.serializer';
5
5
  import { BadRequestException, NotFoundException, MethodNotAllowedException } from '@nestjs/common';
6
6
  import { instanceToPlain } from 'class-transformer';
7
7
  import merge from 'lodash.merge';
@@ -834,7 +834,14 @@ var RelationQueryBuilder = class {
834
834
  const entityKeys = Object.keys(entityAsRecord);
835
835
  const matchingKey = entityKeys.find((key) => {
836
836
  const keyLower = key.toLowerCase();
837
- return keyLower.endsWith("id") && relationNameLower.includes(keyLower.replace(/id$/, ""));
837
+ if (keyLower === "id" || !keyLower.endsWith("id")) {
838
+ return false;
839
+ }
840
+ const base = keyLower.replace(/id$/, "");
841
+ if (!base) {
842
+ return false;
843
+ }
844
+ return relationNameLower.includes(base);
838
845
  });
839
846
  if (matchingKey) {
840
847
  fkValue = entityAsRecord[matchingKey];
@@ -964,7 +971,8 @@ var AggregateBuilder = class _AggregateBuilder {
964
971
  });
965
972
  const funcSelects = [];
966
973
  aggs.forEach(([func, fields]) => {
967
- const aliases = (fields ?? []).map((f) => {
974
+ if (!fields || fields.length === 0) return;
975
+ const aliases = fields.map((f) => {
968
976
  const col = alias ? `\`${alias}\`.\`${String(f)}\`` : `\`${String(f)}\``;
969
977
  return [
970
978
  `${func}(${col})`,
@@ -1019,7 +1027,8 @@ var AggregateBuilder = class _AggregateBuilder {
1019
1027
  ]
1020
1028
  ];
1021
1029
  return aggs.reduce((cols, [func, fields]) => {
1022
- const aliases = (fields ?? []).map((f) => this.getAggregateAlias(func, f));
1030
+ if (!fields || fields.length === 0) return cols;
1031
+ const aliases = fields.map((f) => this.getAggregateAlias(func, f));
1023
1032
  return [
1024
1033
  ...cols,
1025
1034
  ...aliases
@@ -1095,14 +1104,34 @@ var AggregateBuilder = class _AggregateBuilder {
1095
1104
  */
1096
1105
  build(qb, aggregate, alias) {
1097
1106
  const metadata = qb.mainAlias?.metadata;
1098
- const selects = [
1099
- ...this.createGroupBySelect(aggregate.groupBy, alias, metadata),
1100
- ...this.createAggSelect("COUNT", aggregate.count, alias, metadata),
1101
- ...this.createAggSelect("SUM", aggregate.sum, alias, metadata),
1102
- ...this.createAggSelect("AVG", aggregate.avg, alias, metadata),
1103
- ...this.createAggSelect("MAX", aggregate.max, alias, metadata),
1104
- ...this.createAggSelect("MIN", aggregate.min, alias, metadata)
1107
+ const selects = [];
1108
+ selects.push(...this.createGroupBySelect(aggregate.groupBy, alias, metadata));
1109
+ const aggs = [
1110
+ [
1111
+ "COUNT",
1112
+ aggregate.count
1113
+ ],
1114
+ [
1115
+ "SUM",
1116
+ aggregate.sum
1117
+ ],
1118
+ [
1119
+ "AVG",
1120
+ aggregate.avg
1121
+ ],
1122
+ [
1123
+ "MAX",
1124
+ aggregate.max
1125
+ ],
1126
+ [
1127
+ "MIN",
1128
+ aggregate.min
1129
+ ]
1105
1130
  ];
1131
+ aggs.forEach(([func, fields]) => {
1132
+ if (!fields || fields.length === 0) return;
1133
+ selects.push(...this.createAggSelect(func, fields, alias, metadata));
1134
+ });
1106
1135
  if (!selects.length) {
1107
1136
  throw new BadRequestException("No aggregate fields found.");
1108
1137
  }
@@ -1146,9 +1175,13 @@ var RelationQueryService = class {
1146
1175
  if (Array.isArray(dto)) {
1147
1176
  return this.batchQueryRelations(RelationClass, relationName, dto, query);
1148
1177
  }
1178
+ if (this.isRelationClassIdentity(RelationClass, relationName)) {
1179
+ const relationQueryBuilder2 = this.getRelationQueryBuilder(relationName);
1180
+ return await relationQueryBuilder2.selectAndExecute(dto, query);
1181
+ }
1149
1182
  const assembler = AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1150
1183
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1151
- return assembler.convertAsyncToDTOs(relationQueryBuilder.selectAndExecute(dto, assembler.convertQuery(query)));
1184
+ return assembler.convertToDTOs(await relationQueryBuilder.selectAndExecute(dto, assembler.convertQuery(query)));
1152
1185
  }
1153
1186
  async aggregateRelations(RelationClass, relationName, dto, filter, aggregate) {
1154
1187
  if (Array.isArray(dto)) {
@@ -1179,6 +1212,16 @@ var RelationQueryService = class {
1179
1212
  if (Array.isArray(dto)) {
1180
1213
  return this.batchFindRelations(RelationClass, relationName, dto, opts);
1181
1214
  }
1215
+ if (this.isRelationClassIdentity(RelationClass, relationName)) {
1216
+ const relationQueryBuilder2 = this.getRelationQueryBuilder(relationName);
1217
+ const relations2 = await relationQueryBuilder2.selectAndExecute(dto, {
1218
+ filter: opts?.filter,
1219
+ paging: {
1220
+ limit: 1
1221
+ }
1222
+ });
1223
+ return relations2[0];
1224
+ }
1182
1225
  const assembler = AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1183
1226
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1184
1227
  const relations = await relationQueryBuilder.selectAndExecute(dto, {
@@ -1199,10 +1242,20 @@ var RelationQueryService = class {
1199
1242
  */
1200
1243
  async addRelations(relationName, id, relationIds, opts) {
1201
1244
  const entity = await this.getById(id, opts);
1245
+ const meta = this.getRelationMeta(relationName);
1202
1246
  const relations = await this.getRelations(relationName, relationIds, opts?.relationFilter);
1203
1247
  if (!this.foundAllRelations(relationIds, relations)) {
1204
1248
  throw new Error(`Unable to find all ${relationName} to add to ${this.EntityClass.name}`);
1205
1249
  }
1250
+ if (meta.kind === "1:m" && meta.mappedBy) {
1251
+ for (const relation of relations) {
1252
+ wrap(relation).assign({
1253
+ [meta.mappedBy]: entity
1254
+ });
1255
+ }
1256
+ await this.repo.getEntityManager().flush();
1257
+ return entity;
1258
+ }
1206
1259
  const collection = entity[relationName];
1207
1260
  if (collection && typeof collection.add === "function") {
1208
1261
  for (const relation of relations) {
@@ -1223,12 +1276,33 @@ var RelationQueryService = class {
1223
1276
  */
1224
1277
  async setRelations(relationName, id, relationIds, opts) {
1225
1278
  const entity = await this.getById(id, opts);
1279
+ const meta = this.getRelationMeta(relationName);
1226
1280
  const relations = await this.getRelations(relationName, relationIds, opts?.relationFilter);
1227
1281
  if (relationIds.length) {
1228
1282
  if (!this.foundAllRelations(relationIds, relations)) {
1229
1283
  throw new Error(`Unable to find all ${relationName} to set on ${this.EntityClass.name}`);
1230
1284
  }
1231
1285
  }
1286
+ if (meta.kind === "1:m" && meta.mappedBy) {
1287
+ const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1288
+ const currentRelations = await relationQueryBuilder.selectAndExecute(entity, {});
1289
+ const nextSet = new Set(relations.map((r) => wrap(r).getPrimaryKey()));
1290
+ for (const currentRelation of currentRelations) {
1291
+ const currentPk = wrap(currentRelation).getPrimaryKey();
1292
+ if (!nextSet.has(currentPk)) {
1293
+ wrap(currentRelation).assign({
1294
+ [meta.mappedBy]: null
1295
+ });
1296
+ }
1297
+ }
1298
+ for (const relation of relations) {
1299
+ wrap(relation).assign({
1300
+ [meta.mappedBy]: entity
1301
+ });
1302
+ }
1303
+ await this.repo.getEntityManager().flush();
1304
+ return entity;
1305
+ }
1232
1306
  const collection = entity[relationName];
1233
1307
  if (collection && typeof collection.set === "function") {
1234
1308
  await collection.init();
@@ -1268,10 +1342,20 @@ var RelationQueryService = class {
1268
1342
  */
1269
1343
  async removeRelations(relationName, id, relationIds, opts) {
1270
1344
  const entity = await this.getById(id, opts);
1345
+ const meta = this.getRelationMeta(relationName);
1271
1346
  const relations = await this.getRelations(relationName, relationIds, opts?.relationFilter);
1272
1347
  if (!this.foundAllRelations(relationIds, relations)) {
1273
1348
  throw new Error(`Unable to find all ${relationName} to remove from ${this.EntityClass.name}`);
1274
1349
  }
1350
+ if (meta.kind === "1:m" && meta.mappedBy) {
1351
+ for (const relation of relations) {
1352
+ wrap(relation).assign({
1353
+ [meta.mappedBy]: null
1354
+ });
1355
+ }
1356
+ await this.repo.getEntityManager().flush();
1357
+ return entity;
1358
+ }
1275
1359
  const collection = entity[relationName];
1276
1360
  if (collection && typeof collection.remove === "function") {
1277
1361
  await collection.init();
@@ -1300,14 +1384,25 @@ var RelationQueryService = class {
1300
1384
  const meta = this.getRelationMeta(relationName);
1301
1385
  if (meta.kind === "1:1" || meta.kind === "m:1") {
1302
1386
  const fkFieldName = `${relationName}Id`;
1303
- const assignData = {
1304
- [relationName]: null
1305
- };
1306
- if (fkFieldName in entity) {
1387
+ const assignData = {};
1388
+ const ownDescriptor = Object.getOwnPropertyDescriptor(entity, fkFieldName);
1389
+ const protoDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(entity), fkFieldName);
1390
+ const descriptor = ownDescriptor ?? protoDescriptor;
1391
+ const canAssignFk = fkFieldName in entity && (!descriptor || Boolean(descriptor.set) || descriptor.writable === true);
1392
+ if (canAssignFk) {
1307
1393
  assignData[fkFieldName] = null;
1394
+ } else {
1395
+ assignData[relationName] = null;
1308
1396
  }
1309
1397
  wrap(entity).assign(assignData);
1310
1398
  } else {
1399
+ if (meta.kind === "1:m" && meta.mappedBy) {
1400
+ wrap(relation).assign({
1401
+ [meta.mappedBy]: null
1402
+ });
1403
+ await this.repo.getEntityManager().flush();
1404
+ return entity;
1405
+ }
1311
1406
  const collection = entity[relationName];
1312
1407
  if (collection && typeof collection.remove === "function") {
1313
1408
  await collection.init();
@@ -1328,13 +1423,14 @@ var RelationQueryService = class {
1328
1423
  * @param query - A query to filter, page or sort relations.
1329
1424
  */
1330
1425
  async batchQueryRelations(RelationClass, relationName, entities, query) {
1331
- const assembler = AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1426
+ const bypassAssembler = this.isRelationClassIdentity(RelationClass, relationName);
1427
+ const assembler = bypassAssembler ? void 0 : AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1332
1428
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1333
- const convertedQuery = assembler.convertQuery(query);
1429
+ const convertedQuery = assembler ? assembler.convertQuery(query) : query;
1334
1430
  const results = /* @__PURE__ */ new Map();
1335
1431
  await Promise.all(entities.map(async (entity) => {
1336
1432
  const relations = await relationQueryBuilder.selectAndExecute(entity, convertedQuery);
1337
- const relationDtos = assembler.convertToDTOs(relations);
1433
+ const relationDtos = bypassAssembler ? relations : await assembler.convertToDTOs(relations);
1338
1434
  if (relationDtos.length > 0) {
1339
1435
  results.set(entity, relationDtos);
1340
1436
  }
@@ -1404,6 +1500,10 @@ var RelationQueryService = class {
1404
1500
  });
1405
1501
  return results;
1406
1502
  }
1503
+ isRelationClassIdentity(RelationClass, relationName) {
1504
+ const relationEntity = this.getRelationEntity(relationName);
1505
+ return RelationClass === relationEntity || RelationClass.name === relationEntity.name;
1506
+ }
1407
1507
  getRelationMeta(relationName) {
1408
1508
  const em = this.repo.getEntityManager();
1409
1509
  const metadata = em.getMetadata().get(this.repo.getEntityName());
@@ -1414,12 +1514,14 @@ var RelationQueryService = class {
1414
1514
  return {
1415
1515
  kind: relationMeta.kind,
1416
1516
  type: relationMeta.type,
1417
- entity: relationMeta.entity
1517
+ entity: relationMeta.entity,
1518
+ mappedBy: relationMeta.mappedBy
1418
1519
  };
1419
1520
  }
1420
1521
  getRelationEntity(relationName) {
1421
1522
  const relationMeta = this.getRelationMeta(relationName);
1422
- return relationMeta.entity();
1523
+ const entity = relationMeta.entity();
1524
+ return entity && "class" in entity ? entity.class : entity;
1423
1525
  }
1424
1526
  async getRelations(relationName, ids, filter) {
1425
1527
  const em = this.repo.getEntityManager();
@@ -1481,7 +1583,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1481
1583
  return data;
1482
1584
  })(this.EntityClass);
1483
1585
  AssemblerDeserializer((d) => {
1484
- const entity = this.repo.getEntityManager().create(this.EntityClass, instanceToPlain(d));
1586
+ const entity = this.repo.getEntityManager().merge(this.EntityClass, d);
1485
1587
  return entity;
1486
1588
  })(this.EntityClass);
1487
1589
  }
@@ -1492,7 +1594,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1492
1594
  return metadata.class;
1493
1595
  }
1494
1596
  /**
1495
- * Query for multiple entities, using a Query from `@nestjs-query/core`.
1597
+ * Query for multiple entities, using a Query from `@ptc-org/nestjs-query-core`.
1496
1598
  *
1497
1599
  * @example
1498
1600
  * ```ts
@@ -1778,7 +1880,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1778
1880
  return entity;
1779
1881
  }
1780
1882
  /**
1781
- * Update multiple entities with a `@nestjs-query/core` Filter.
1883
+ * Update multiple entities with a `@ptc-org/nestjs-query-core` Filter.
1782
1884
  *
1783
1885
  * @example
1784
1886
  * ```ts
@@ -1829,7 +1931,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1829
1931
  return entity;
1830
1932
  }
1831
1933
  /**
1832
- * Delete multiple records with a `@nestjs-query/core` `Filter`.
1934
+ * Delete multiple records with a `@ptc-org/nestjs-query-core` `Filter`.
1833
1935
  *
1834
1936
  * @example
1835
1937
  *
@@ -1905,7 +2007,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1905
2007
  return entity;
1906
2008
  }
1907
2009
  /**
1908
- * Restores multiple records with a `@nestjs-query/core` `Filter`.
2010
+ * Restores multiple records with a `@ptc-org/nestjs-query-core` `Filter`.
1909
2011
  *
1910
2012
  * @example
1911
2013
  *