nestjs-query-mikro-orm 0.0.7 → 0.0.9

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.cjs CHANGED
@@ -1,13 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var nestjs = require('@mikro-orm/nestjs');
4
- var core$1 = require('@nestjs-query/core');
5
- var core = require('@mikro-orm/core');
4
+ var core = require('@nestjs-query/core');
5
+ var core$1 = require('@mikro-orm/core');
6
6
  var assembler_serializer = require('@nestjs-query/core/dist/src/assemblers/assembler.serializer');
7
7
  var common = require('@nestjs/common');
8
8
  var classTransformer = require('class-transformer');
9
9
  var merge = require('lodash.merge');
10
- var camelCase = require('camel-case');
11
10
 
12
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
12
 
@@ -15,146 +14,6 @@ var merge__default = /*#__PURE__*/_interopDefault(merge);
15
14
 
16
15
  var __defProp = Object.defineProperty;
17
16
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
18
- var AGG_REGEXP = /(AVG|SUM|COUNT|MAX|MIN|GROUP_BY)_(.*)/;
19
- var AggregateBuilder = class _AggregateBuilder {
20
- static {
21
- __name(this, "AggregateBuilder");
22
- }
23
- static async asyncConvertToAggregateResponse(responsePromise) {
24
- const aggResponse = await responsePromise;
25
- return this.convertToAggregateResponse(aggResponse);
26
- }
27
- static getAggregateSelects(query) {
28
- return [
29
- ...this.getAggregateGroupBySelects(query),
30
- ...this.getAggregateFuncSelects(query)
31
- ];
32
- }
33
- static getAggregateGroupBySelects(query) {
34
- return (query.groupBy ?? []).map((f) => this.getGroupByAlias(f));
35
- }
36
- static getAggregateFuncSelects(query) {
37
- const aggs = [
38
- [
39
- "COUNT",
40
- query.count
41
- ],
42
- [
43
- "SUM",
44
- query.sum
45
- ],
46
- [
47
- "AVG",
48
- query.avg
49
- ],
50
- [
51
- "MAX",
52
- query.max
53
- ],
54
- [
55
- "MIN",
56
- query.min
57
- ]
58
- ];
59
- return aggs.reduce((cols, [func, fields]) => {
60
- const aliases = (fields ?? []).map((f) => this.getAggregateAlias(func, f));
61
- return [
62
- ...cols,
63
- ...aliases
64
- ];
65
- }, []);
66
- }
67
- static getAggregateAlias(func, field) {
68
- return `${func}_${field}`;
69
- }
70
- static getGroupByAlias(field) {
71
- return `GROUP_BY_${field}`;
72
- }
73
- static convertToAggregateResponse(rawAggregates) {
74
- return rawAggregates.map((response) => {
75
- return Object.keys(response).reduce((agg, resultField) => {
76
- const matchResult = AGG_REGEXP.exec(resultField);
77
- if (!matchResult) {
78
- throw new Error("Unknown aggregate column encountered.");
79
- }
80
- const [matchedFunc, matchedFieldName] = matchResult.slice(1);
81
- const aggFunc = camelCase.camelCase(matchedFunc.toLowerCase());
82
- const fieldName = matchedFieldName;
83
- const aggResult = agg[aggFunc] || {};
84
- return {
85
- ...agg,
86
- [aggFunc]: {
87
- ...aggResult,
88
- [fieldName]: response[resultField]
89
- }
90
- };
91
- }, {});
92
- });
93
- }
94
- /**
95
- * Gets the actual database column name for a property from entity metadata.
96
- * @param metadata - the entity metadata
97
- * @param propertyName - the property name
98
- * @returns the database column name
99
- */
100
- getColumnName(metadata, propertyName) {
101
- const prop = metadata.properties[propertyName];
102
- if (prop && prop.fieldNames && prop.fieldNames.length > 0) {
103
- return prop.fieldNames[0];
104
- }
105
- return propertyName;
106
- }
107
- /**
108
- * Builds aggregate SELECT clause for MikroORM QueryBuilder.
109
- * @param qb - the MikroORM QueryBuilder
110
- * @param aggregate - the aggregates to select.
111
- * @param alias - optional alias to use to qualify an identifier
112
- */
113
- build(qb, aggregate, alias) {
114
- const metadata = qb.mainAlias?.metadata;
115
- const selects = [
116
- ...this.createGroupBySelect(aggregate.groupBy, alias, metadata),
117
- ...this.createAggSelect("COUNT", aggregate.count, alias, metadata),
118
- ...this.createAggSelect("SUM", aggregate.sum, alias, metadata),
119
- ...this.createAggSelect("AVG", aggregate.avg, alias, metadata),
120
- ...this.createAggSelect("MAX", aggregate.max, alias, metadata),
121
- ...this.createAggSelect("MIN", aggregate.min, alias, metadata)
122
- ];
123
- if (!selects.length) {
124
- throw new common.BadRequestException("No aggregate fields found.");
125
- }
126
- selects.forEach(([selectExpr, selectAlias]) => {
127
- qb.addSelect(core.raw(`${selectExpr} as "${selectAlias}"`));
128
- });
129
- return qb;
130
- }
131
- createAggSelect(func, fields, alias, metadata) {
132
- if (!fields) {
133
- return [];
134
- }
135
- return fields.map((field) => {
136
- const columnName = metadata ? this.getColumnName(metadata, field) : field;
137
- const col = alias ? `\`${alias}\`.\`${columnName}\`` : `\`${columnName}\``;
138
- return [
139
- `${func}(${col})`,
140
- _AggregateBuilder.getAggregateAlias(func, field)
141
- ];
142
- });
143
- }
144
- createGroupBySelect(fields, alias, metadata) {
145
- if (!fields) {
146
- return [];
147
- }
148
- return fields.map((field) => {
149
- const columnName = metadata ? this.getColumnName(metadata, field) : field;
150
- const col = alias ? `\`${alias}\`.\`${columnName}\`` : `\`${columnName}\``;
151
- return [
152
- `${col}`,
153
- _AggregateBuilder.getGroupByAlias(field)
154
- ];
155
- });
156
- }
157
- };
158
17
 
159
18
  // src/lib/query/where.builder.ts
160
19
  var WhereBuilder = class {
@@ -394,81 +253,50 @@ var FilterQueryBuilder = class {
394
253
  }
395
254
  repo;
396
255
  whereBuilder;
397
- aggregateBuilder;
398
- constructor(repo, whereBuilder = new WhereBuilder(), aggregateBuilder = new AggregateBuilder()) {
256
+ constructor(repo, whereBuilder = new WhereBuilder()) {
399
257
  this.repo = repo;
400
258
  this.whereBuilder = whereBuilder;
401
- this.aggregateBuilder = aggregateBuilder;
402
259
  }
403
260
  /**
404
- * Create a MikroORM QueryBuilder with `WHERE`, `ORDER BY` and `LIMIT/OFFSET` clauses.
405
- *
406
- * @param query - the query to apply.
261
+ * NOTE: QueryBuilder-specific helpers removed; use `buildFindOptions` to
262
+ * produce a filter and options for `em.find`/`repo.find`.
407
263
  */
408
- select(query) {
409
- const alias = this.getEntityAlias();
410
- const qb = this.createQueryBuilder(alias);
411
- this.applyFilter(qb, query.filter, alias);
412
- this.applySorting(qb, query.sorting, alias);
413
- this.applyPaging(qb, query.paging);
414
- return qb;
415
- }
416
- selectById(id, query) {
417
- const alias = this.getEntityAlias();
418
- const qb = this.createQueryBuilder(alias);
419
- const metadata = this.repo.getEntityManager().getMetadata().get(this.repo.getEntityName());
420
- const primaryKey = metadata.primaryKeys[0];
421
- if (Array.isArray(id)) {
422
- qb.where({
423
- [primaryKey]: {
424
- $in: id
425
- }
426
- });
427
- } else {
428
- qb.where({
429
- [primaryKey]: id
430
- });
431
- }
432
- this.applyFilter(qb, query.filter, alias);
433
- this.applySorting(qb, query.sorting, alias);
434
- this.applyPaging(qb, query.paging);
435
- return qb;
436
- }
437
- aggregate(query, aggregate) {
438
- const alias = this.getEntityAlias();
439
- const qb = this.createQueryBuilder(alias);
440
- this.applyAggregate(qb, aggregate, alias);
441
- this.applyFilter(qb, query.filter, alias);
442
- this.applyAggregateSorting(qb, aggregate.groupBy, alias);
443
- this.applyGroupBy(qb, aggregate.groupBy, alias);
444
- return qb;
445
- }
446
264
  /**
447
- * Applies paging to a MikroORM query builder
448
- * @param qb - the MikroORM QueryBuilder
449
- * @param paging - the Paging options.
265
+ * Build a filter query and find options suitable for `em.find`/`repo.find` calls.
266
+ * This keeps usage DB-agnostic by returning plain filter objects and options
267
+ * instead of driver-specific QueryBuilder instances.
450
268
  */
451
- applyPaging(qb, paging) {
452
- if (!paging) {
453
- return qb;
454
- }
455
- if (paging.limit !== void 0) {
456
- qb.limit(paging.limit);
457
- }
458
- if (paging.offset !== void 0) {
459
- qb.offset(paging.offset);
269
+ buildFindOptions(query) {
270
+ const result = {};
271
+ if (query.filter) {
272
+ const mikroOrmFilter = this.whereBuilder.build(query.filter);
273
+ result.filterQuery = mikroOrmFilter;
274
+ }
275
+ const paging = query.paging;
276
+ const sorting = query.sorting;
277
+ if (paging && (paging.limit !== void 0 || paging.offset !== void 0) || sorting && sorting.length) {
278
+ const options = {};
279
+ if (paging) {
280
+ if (paging.limit !== void 0) options.limit = paging.limit;
281
+ if (paging.offset !== void 0) options.offset = paging.offset;
282
+ }
283
+ if (sorting && sorting.length > 0) {
284
+ const orderBy = sorting.reduce((acc, { field, direction, nulls }) => {
285
+ const order = direction === "ASC" ? "asc" : "desc";
286
+ let orderValue = order;
287
+ if (nulls) {
288
+ orderValue = `${order} ${nulls.toLowerCase().replace("_", " ")}`;
289
+ }
290
+ return {
291
+ ...acc,
292
+ [field]: orderValue
293
+ };
294
+ }, {});
295
+ options.orderBy = orderBy;
296
+ }
297
+ result.options = options;
460
298
  }
461
- return qb;
462
- }
463
- /**
464
- * Applies the aggregate selects from a Query to a MikroORM QueryBuilder.
465
- *
466
- * @param qb - the MikroORM QueryBuilder.
467
- * @param aggregate - the aggregates to select.
468
- * @param alias - optional alias to use to qualify an identifier
469
- */
470
- applyAggregate(qb, aggregate, alias) {
471
- return this.aggregateBuilder.build(qb, aggregate, alias);
299
+ return result;
472
300
  }
473
301
  /**
474
302
  * Applies the filter from a Query to a MikroORM QueryBuilder.
@@ -530,7 +358,7 @@ var FilterQueryBuilder = class {
530
358
  * Create a MikroORM QueryBuilder.
531
359
  */
532
360
  createQueryBuilder(alias) {
533
- return this.repo.createQueryBuilder(alias);
361
+ return this.repo.createQueryBuilder?.(alias);
534
362
  }
535
363
  /**
536
364
  * Gets the entity alias based on the entity name.
@@ -555,7 +383,7 @@ var FilterQueryBuilder = class {
555
383
  }
556
384
  getReferencedRelations(filter) {
557
385
  const relationNames = this.relationNames;
558
- const referencedFields = core$1.getFilterFields(filter);
386
+ const referencedFields = core.getFilterFields(filter);
559
387
  return referencedFields.filter((f) => relationNames.includes(f));
560
388
  }
561
389
  getReferencedRelationsRecursive(metadataOrFilter = {}, filter) {
@@ -619,10 +447,10 @@ var FilterQueryBuilder = class {
619
447
  }
620
448
  };
621
449
 
622
- // src/lib/query/sql-comparison.builder.ts
623
- var SQLComparisonBuilder = class {
450
+ // src/lib/query/comparison.builder.ts
451
+ var ComparisonBuilder = class {
624
452
  static {
625
- __name(this, "SQLComparisonBuilder");
453
+ __name(this, "ComparisonBuilder");
626
454
  }
627
455
  /**
628
456
  * Maps a comparison operator to MikroORM filter format.
@@ -832,68 +660,162 @@ var RelationQueryBuilder = class {
832
660
  this.filterQueryBuilder = new FilterQueryBuilder(relationRepo);
833
661
  }
834
662
  /**
835
- * Builds and returns a QueryBuilder for selecting relations without executing it.
836
- * This is useful for testing or when you need to inspect/modify the query before execution.
663
+ * Executes a relation select using `em.find` so the implementation is database-agnostic.
837
664
  */
838
- select(entity, query) {
665
+ async selectAndExecute(entity, query) {
839
666
  const relationMeta = this.getRelationMeta();
840
667
  const em = this.repo.getEntityManager();
841
- const relationEntityName = relationMeta.type;
842
- const entityMeta = em.getMetadata().get(this.repo.getEntityName());
843
- const entityPrimaryKey = entityMeta.primaryKeys[0];
844
- const entityId = entity[entityPrimaryKey];
845
- let qb = em.createQueryBuilder(relationEntityName);
846
- if (relationMeta.kind === "1:1" && relationMeta.owner && relationMeta.inversedBy) {
847
- const fkFieldName = relationMeta.joinColumns?.[0] || relationMeta.fieldNames?.[0];
848
- const fkValue = fkFieldName ? entity[fkFieldName] : void 0;
849
- if (fkValue === void 0) {
850
- const parentAlias = "parent";
851
- const relationAlias = qb.alias;
852
- qb = qb.leftJoin(`${relationAlias}.${relationMeta.inversedBy}`, parentAlias).where({
853
- [`${parentAlias}.${entityPrimaryKey}`]: entityId
854
- });
855
- qb = this.filterQueryBuilder.applyFilter(qb, query.filter);
856
- qb = this.filterQueryBuilder.applyPaging(qb, query.paging);
857
- qb = this.filterQueryBuilder.applySorting(qb, query.sorting);
858
- return qb;
859
- }
860
- }
861
- const whereCondition = this.buildWhereCondition(entity, relationMeta);
862
- qb = qb.where(whereCondition);
863
- qb = this.filterQueryBuilder.applyFilter(qb, query.filter);
864
- qb = this.filterQueryBuilder.applyPaging(qb, query.paging);
865
- qb = this.filterQueryBuilder.applySorting(qb, query.sorting);
866
- return qb;
867
- }
868
- /**
869
- * Executes the select query and returns the results.
870
- */
871
- async selectAndExecute(entity, query) {
872
- const qb = this.select(entity, query);
873
- return qb.getResultList();
668
+ const RelationEntity = relationMeta.type;
669
+ const baseWhere = this.buildWhereCondition(entity, relationMeta);
670
+ const { filterQuery, options } = this.filterQueryBuilder.buildFindOptions(query);
671
+ const finalWhere = filterQuery ? {
672
+ $and: [
673
+ baseWhere,
674
+ filterQuery
675
+ ]
676
+ } : baseWhere;
677
+ const findOptions = {};
678
+ if (options?.orderBy) findOptions.orderBy = options.orderBy;
679
+ if (options?.limit !== void 0) findOptions.limit = options.limit;
680
+ if (options?.offset !== void 0) findOptions.offset = options.offset;
681
+ return await em.find(RelationEntity, finalWhere, findOptions);
874
682
  }
875
683
  async count(entity, query) {
876
684
  const relationMeta = this.getRelationMeta();
877
685
  const em = this.repo.getEntityManager();
878
- const relationEntityName = relationMeta.type;
879
- let qb = em.createQueryBuilder(relationEntityName);
880
- const whereCondition = this.buildWhereCondition(entity, relationMeta);
881
- qb = qb.where(whereCondition);
882
- qb = this.filterQueryBuilder.applyFilter(qb, query.filter);
883
- return qb.getCount();
686
+ const RelationEntity = relationMeta.type;
687
+ const baseWhere = this.buildWhereCondition(entity, relationMeta);
688
+ const { filterQuery } = this.filterQueryBuilder.buildFindOptions(query);
689
+ const finalWhere = filterQuery ? {
690
+ $and: [
691
+ baseWhere,
692
+ filterQuery
693
+ ]
694
+ } : baseWhere;
695
+ return em.count(RelationEntity, finalWhere);
884
696
  }
885
697
  async aggregate(entity, query, aggregateQuery) {
886
698
  const relationMeta = this.getRelationMeta();
887
699
  const em = this.repo.getEntityManager();
888
- const relationEntityName = relationMeta.type;
889
- let qb = em.createQueryBuilder(relationEntityName);
890
- const whereCondition = this.buildWhereCondition(entity, relationMeta);
891
- qb = qb.where(whereCondition);
892
- qb = this.filterQueryBuilder.applyAggregate(qb, aggregateQuery);
893
- qb = this.filterQueryBuilder.applyFilter(qb, query.filter);
894
- qb = this.filterQueryBuilder.applyAggregateSorting(qb, aggregateQuery.groupBy);
895
- qb = this.filterQueryBuilder.applyGroupBy(qb, aggregateQuery.groupBy);
896
- return qb.execute();
700
+ const RelationEntity = relationMeta.type;
701
+ const baseWhere = this.buildWhereCondition(entity, relationMeta);
702
+ const { filterQuery } = this.filterQueryBuilder.buildFindOptions(query);
703
+ const finalWhere = filterQuery ? {
704
+ $and: [
705
+ baseWhere,
706
+ filterQuery
707
+ ]
708
+ } : baseWhere;
709
+ const rows = await em.find(RelationEntity, finalWhere);
710
+ const aggs = aggregateQuery;
711
+ const groupBy = aggs.groupBy ?? [];
712
+ const makeAggKey = /* @__PURE__ */ __name((func, field) => `${func}_${field}`, "makeAggKey");
713
+ const makeGroupKey = /* @__PURE__ */ __name((field) => `GROUP_BY_${field}`, "makeGroupKey");
714
+ const records = [];
715
+ const isNumeric = /* @__PURE__ */ __name((v) => typeof v === "number" || v instanceof Date, "isNumeric");
716
+ if (groupBy.length === 0) {
717
+ const out = {};
718
+ const computeField = /* @__PURE__ */ __name((fn, field) => {
719
+ const values = rows.map((r) => r[field]).filter((v) => v !== void 0 && v !== null);
720
+ if (fn === "COUNT") {
721
+ out[makeAggKey("COUNT", field)] = values.length;
722
+ return;
723
+ }
724
+ if (values.length === 0) {
725
+ out[makeAggKey(fn, field)] = null;
726
+ return;
727
+ }
728
+ if (fn === "SUM" || fn === "AVG") {
729
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v)).filter((n) => !Number.isNaN(n));
730
+ const sum = nums.reduce((s, v) => s + v, 0);
731
+ out[makeAggKey(fn, field)] = fn === "SUM" ? sum : nums.length ? sum / nums.length : null;
732
+ return;
733
+ }
734
+ if (fn === "MAX") {
735
+ if (values.every(isNumeric)) {
736
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
737
+ out[makeAggKey("MAX", field)] = Math.max(...nums);
738
+ } else {
739
+ out[makeAggKey("MAX", field)] = values.reduce((a, b) => String(a) > String(b) ? a : b);
740
+ }
741
+ return;
742
+ }
743
+ if (fn === "MIN") {
744
+ if (values.every(isNumeric)) {
745
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
746
+ out[makeAggKey("MIN", field)] = Math.min(...nums);
747
+ } else {
748
+ out[makeAggKey("MIN", field)] = values.reduce((a, b) => String(a) < String(b) ? a : b);
749
+ }
750
+ return;
751
+ }
752
+ }, "computeField");
753
+ (aggs.count ?? []).forEach((f) => computeField("COUNT", String(f)));
754
+ (aggs.sum ?? []).forEach((f) => computeField("SUM", String(f)));
755
+ (aggs.avg ?? []).forEach((f) => computeField("AVG", String(f)));
756
+ (aggs.max ?? []).forEach((f) => computeField("MAX", String(f)));
757
+ (aggs.min ?? []).forEach((f) => computeField("MIN", String(f)));
758
+ records.push(out);
759
+ } else {
760
+ const groups = /* @__PURE__ */ new Map();
761
+ rows.forEach((r) => {
762
+ const keyParts = groupBy.map((g) => JSON.stringify(r[String(g)]));
763
+ const key = keyParts.join("|");
764
+ const arr = groups.get(key) ?? [];
765
+ arr.push(r);
766
+ groups.set(key, arr);
767
+ });
768
+ groups.forEach((groupRows, key) => {
769
+ const parts = key.split("|").map((p) => JSON.parse(p));
770
+ const out = {};
771
+ groupBy.forEach((g, i) => {
772
+ const val = parts[i];
773
+ out[makeGroupKey(String(g))] = typeof val === "boolean" ? val ? 1 : 0 : val;
774
+ });
775
+ const computeField = /* @__PURE__ */ __name((fn, field) => {
776
+ const values = groupRows.map((r) => r[field]).filter((v) => v !== void 0 && v !== null);
777
+ if (fn === "COUNT") {
778
+ out[makeAggKey("COUNT", field)] = values.length;
779
+ return;
780
+ }
781
+ if (values.length === 0) {
782
+ out[makeAggKey(fn, field)] = null;
783
+ return;
784
+ }
785
+ if (fn === "SUM" || fn === "AVG") {
786
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v)).filter((n) => !Number.isNaN(n));
787
+ const sum = nums.reduce((s, v) => s + v, 0);
788
+ out[makeAggKey(fn, field)] = fn === "SUM" ? sum : nums.length ? sum / nums.length : null;
789
+ return;
790
+ }
791
+ if (fn === "MAX") {
792
+ if (values.every(isNumeric)) {
793
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
794
+ out[makeAggKey("MAX", field)] = Math.max(...nums);
795
+ } else {
796
+ out[makeAggKey("MAX", field)] = values.reduce((a, b) => String(a) > String(b) ? a : b);
797
+ }
798
+ return;
799
+ }
800
+ if (fn === "MIN") {
801
+ if (values.every(isNumeric)) {
802
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
803
+ out[makeAggKey("MIN", field)] = Math.min(...nums);
804
+ } else {
805
+ out[makeAggKey("MIN", field)] = values.reduce((a, b) => String(a) < String(b) ? a : b);
806
+ }
807
+ return;
808
+ }
809
+ }, "computeField");
810
+ (aggs.count ?? []).forEach((f) => computeField("COUNT", String(f)));
811
+ (aggs.sum ?? []).forEach((f) => computeField("SUM", String(f)));
812
+ (aggs.avg ?? []).forEach((f) => computeField("AVG", String(f)));
813
+ (aggs.max ?? []).forEach((f) => computeField("MAX", String(f)));
814
+ (aggs.min ?? []).forEach((f) => computeField("MIN", String(f)));
815
+ records.push(out);
816
+ });
817
+ }
818
+ return records;
897
819
  }
898
820
  buildWhereCondition(entity, relationMeta) {
899
821
  const em = this.repo.getEntityManager();
@@ -1011,6 +933,217 @@ var RelationQueryBuilder = class {
1011
933
  });
1012
934
  }
1013
935
  };
936
+ var AGG_REGEXP = /^(AVG|SUM|COUNT|MAX|MIN|GROUP_BY|group_by|groupBy|avg|sum|count|max|min)_(.*)$/i;
937
+ var AggregateBuilder = class _AggregateBuilder {
938
+ static {
939
+ __name(this, "AggregateBuilder");
940
+ }
941
+ static buildSelectExpressions(aggregate, alias) {
942
+ const aggs = [
943
+ [
944
+ "COUNT",
945
+ aggregate.count
946
+ ],
947
+ [
948
+ "SUM",
949
+ aggregate.sum
950
+ ],
951
+ [
952
+ "AVG",
953
+ aggregate.avg
954
+ ],
955
+ [
956
+ "MAX",
957
+ aggregate.max
958
+ ],
959
+ [
960
+ "MIN",
961
+ aggregate.min
962
+ ]
963
+ ];
964
+ const groupBySelects = (aggregate.groupBy ?? []).map((f) => {
965
+ const col = alias ? `\`${alias}\`.\`${String(f)}\`` : `\`${String(f)}\``;
966
+ return [
967
+ col,
968
+ _AggregateBuilder.getGroupByAlias(f)
969
+ ];
970
+ });
971
+ const funcSelects = [];
972
+ aggs.forEach(([func, fields]) => {
973
+ const aliases = (fields ?? []).map((f) => {
974
+ const col = alias ? `\`${alias}\`.\`${String(f)}\`` : `\`${String(f)}\``;
975
+ return [
976
+ `${func}(${col})`,
977
+ _AggregateBuilder.getAggregateAlias(func, f)
978
+ ];
979
+ });
980
+ funcSelects.push(...aliases);
981
+ });
982
+ const selects = [
983
+ ...groupBySelects,
984
+ ...funcSelects
985
+ ];
986
+ if (!selects.length) {
987
+ throw new common.BadRequestException("No aggregate fields found.");
988
+ }
989
+ return selects;
990
+ }
991
+ static async asyncConvertToAggregateResponse(responsePromise) {
992
+ const aggResponse = await responsePromise;
993
+ return this.convertToAggregateResponse(aggResponse);
994
+ }
995
+ static getAggregateSelects(query) {
996
+ return [
997
+ ...this.getAggregateGroupBySelects(query),
998
+ ...this.getAggregateFuncSelects(query)
999
+ ];
1000
+ }
1001
+ static getAggregateGroupBySelects(query) {
1002
+ return (query.groupBy ?? []).map((f) => this.getGroupByAlias(f));
1003
+ }
1004
+ static getAggregateFuncSelects(query) {
1005
+ const aggs = [
1006
+ [
1007
+ "COUNT",
1008
+ query.count
1009
+ ],
1010
+ [
1011
+ "SUM",
1012
+ query.sum
1013
+ ],
1014
+ [
1015
+ "AVG",
1016
+ query.avg
1017
+ ],
1018
+ [
1019
+ "MAX",
1020
+ query.max
1021
+ ],
1022
+ [
1023
+ "MIN",
1024
+ query.min
1025
+ ]
1026
+ ];
1027
+ return aggs.reduce((cols, [func, fields]) => {
1028
+ const aliases = (fields ?? []).map((f) => this.getAggregateAlias(func, f));
1029
+ return [
1030
+ ...cols,
1031
+ ...aliases
1032
+ ];
1033
+ }, []);
1034
+ }
1035
+ static getAggregateAlias(func, field) {
1036
+ return `${func}_${field}`;
1037
+ }
1038
+ static getGroupByAlias(field) {
1039
+ return `GROUP_BY_${field}`;
1040
+ }
1041
+ static convertToAggregateResponse(rawAggregates) {
1042
+ return rawAggregates.map((response) => {
1043
+ const agg = {};
1044
+ if (response._id && typeof response._id === "object") {
1045
+ const idObj = response._id;
1046
+ Object.keys(idObj).forEach((k) => {
1047
+ const m = /^(?:GROUP_BY|group_by|groupBy)_(.*)$/i.exec(k);
1048
+ if (m) {
1049
+ const field = m[1];
1050
+ agg.groupBy = {
1051
+ ...agg.groupBy,
1052
+ [field]: idObj[k]
1053
+ };
1054
+ }
1055
+ });
1056
+ }
1057
+ Object.keys(response).forEach((resultField) => {
1058
+ if (resultField === "_id") return;
1059
+ const matchResult = AGG_REGEXP.exec(resultField);
1060
+ if (!matchResult) {
1061
+ throw new Error("Unknown aggregate column encountered.");
1062
+ }
1063
+ const matchedFunc = matchResult[1];
1064
+ const matchedFieldName = matchResult[2];
1065
+ const funcKey = matchedFunc.toLowerCase();
1066
+ const aggFunc = funcKey === "group_by" || funcKey === "groupby" ? "groupBy" : funcKey;
1067
+ if (aggFunc === "groupBy") {
1068
+ agg.groupBy = {
1069
+ ...agg.groupBy,
1070
+ [matchedFieldName]: response[resultField]
1071
+ };
1072
+ return;
1073
+ }
1074
+ const fieldName = matchedFieldName;
1075
+ agg[aggFunc] = {
1076
+ ...agg[aggFunc],
1077
+ [fieldName]: response[resultField]
1078
+ };
1079
+ });
1080
+ return agg;
1081
+ });
1082
+ }
1083
+ /**
1084
+ * Gets the actual database column name for a property from entity metadata.
1085
+ * @param metadata - the entity metadata
1086
+ * @param propertyName - the property name
1087
+ * @returns the database column name
1088
+ */
1089
+ getColumnName(metadata, propertyName) {
1090
+ const prop = metadata.properties[propertyName];
1091
+ if (prop && prop.fieldNames && prop.fieldNames.length > 0) {
1092
+ return prop.fieldNames[0];
1093
+ }
1094
+ return propertyName;
1095
+ }
1096
+ /**
1097
+ * Builds aggregate SELECT clause for MikroORM QueryBuilder.
1098
+ * @param qb - the MikroORM QueryBuilder
1099
+ * @param aggregate - the aggregates to select.
1100
+ * @param alias - optional alias to use to qualify an identifier
1101
+ */
1102
+ build(qb, aggregate, alias) {
1103
+ const metadata = qb.mainAlias?.metadata;
1104
+ const selects = [
1105
+ ...this.createGroupBySelect(aggregate.groupBy, alias, metadata),
1106
+ ...this.createAggSelect("COUNT", aggregate.count, alias, metadata),
1107
+ ...this.createAggSelect("SUM", aggregate.sum, alias, metadata),
1108
+ ...this.createAggSelect("AVG", aggregate.avg, alias, metadata),
1109
+ ...this.createAggSelect("MAX", aggregate.max, alias, metadata),
1110
+ ...this.createAggSelect("MIN", aggregate.min, alias, metadata)
1111
+ ];
1112
+ if (!selects.length) {
1113
+ throw new common.BadRequestException("No aggregate fields found.");
1114
+ }
1115
+ selects.forEach(([selectExpr, selectAlias]) => {
1116
+ qb.addSelect(core$1.raw(`${selectExpr} as "${selectAlias}"`));
1117
+ });
1118
+ return qb;
1119
+ }
1120
+ createAggSelect(func, fields, alias, metadata) {
1121
+ if (!fields) {
1122
+ return [];
1123
+ }
1124
+ return fields.map((field) => {
1125
+ const columnName = metadata ? this.getColumnName(metadata, field) : field;
1126
+ const col = alias ? `\`${alias}\`.\`${columnName}\`` : `\`${columnName}\``;
1127
+ return [
1128
+ `${func}(${col})`,
1129
+ _AggregateBuilder.getAggregateAlias(func, field)
1130
+ ];
1131
+ });
1132
+ }
1133
+ createGroupBySelect(fields, alias, metadata) {
1134
+ if (!fields) {
1135
+ return [];
1136
+ }
1137
+ return fields.map((field) => {
1138
+ const columnName = metadata ? this.getColumnName(metadata, field) : field;
1139
+ const col = alias ? `\`${alias}\`.\`${columnName}\`` : `\`${columnName}\``;
1140
+ return [
1141
+ `${col}`,
1142
+ _AggregateBuilder.getGroupByAlias(field)
1143
+ ];
1144
+ });
1145
+ }
1146
+ };
1014
1147
  var RelationQueryService = class {
1015
1148
  static {
1016
1149
  __name(this, "RelationQueryService");
@@ -1019,7 +1152,7 @@ var RelationQueryService = class {
1019
1152
  if (Array.isArray(dto)) {
1020
1153
  return this.batchQueryRelations(RelationClass, relationName, dto, query);
1021
1154
  }
1022
- const assembler = core$1.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1155
+ const assembler = core.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1023
1156
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1024
1157
  return assembler.convertAsyncToDTOs(relationQueryBuilder.selectAndExecute(dto, assembler.convertQuery(query)));
1025
1158
  }
@@ -1027,7 +1160,7 @@ var RelationQueryService = class {
1027
1160
  if (Array.isArray(dto)) {
1028
1161
  return this.batchAggregateRelations(RelationClass, relationName, dto, filter, aggregate);
1029
1162
  }
1030
- const assembler = core$1.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1163
+ const assembler = core.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1031
1164
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1032
1165
  const rawResults = await relationQueryBuilder.aggregate(dto, assembler.convertQuery({
1033
1166
  filter
@@ -1042,7 +1175,7 @@ var RelationQueryService = class {
1042
1175
  if (Array.isArray(dto)) {
1043
1176
  return this.batchCountRelations(RelationClass, relationName, dto, filter);
1044
1177
  }
1045
- const assembler = core$1.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1178
+ const assembler = core.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1046
1179
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1047
1180
  return relationQueryBuilder.count(dto, assembler.convertQuery({
1048
1181
  filter
@@ -1052,7 +1185,7 @@ var RelationQueryService = class {
1052
1185
  if (Array.isArray(dto)) {
1053
1186
  return this.batchFindRelations(RelationClass, relationName, dto, opts);
1054
1187
  }
1055
- const assembler = core$1.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1188
+ const assembler = core.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1056
1189
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1057
1190
  const relations = await relationQueryBuilder.selectAndExecute(dto, {
1058
1191
  filter: opts?.filter,
@@ -1126,7 +1259,7 @@ var RelationQueryService = class {
1126
1259
  if (!relation) {
1127
1260
  throw new Error(`Unable to find ${relationName} to set on ${this.EntityClass.name}`);
1128
1261
  }
1129
- core.wrap(entity).assign({
1262
+ core$1.wrap(entity).assign({
1130
1263
  [relationName]: relation
1131
1264
  });
1132
1265
  await this.repo.getEntityManager().flush();
@@ -1179,7 +1312,7 @@ var RelationQueryService = class {
1179
1312
  if (fkFieldName in entity) {
1180
1313
  assignData[fkFieldName] = null;
1181
1314
  }
1182
- core.wrap(entity).assign(assignData);
1315
+ core$1.wrap(entity).assign(assignData);
1183
1316
  } else {
1184
1317
  const collection = entity[relationName];
1185
1318
  if (collection && typeof collection.remove === "function") {
@@ -1201,7 +1334,7 @@ var RelationQueryService = class {
1201
1334
  * @param query - A query to filter, page or sort relations.
1202
1335
  */
1203
1336
  async batchQueryRelations(RelationClass, relationName, entities, query) {
1204
- const assembler = core$1.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1337
+ const assembler = core.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1205
1338
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1206
1339
  const convertedQuery = assembler.convertQuery(query);
1207
1340
  const results = /* @__PURE__ */ new Map();
@@ -1222,7 +1355,7 @@ var RelationQueryService = class {
1222
1355
  * @param query - A query to filter, page or sort relations.
1223
1356
  */
1224
1357
  async batchAggregateRelations(RelationClass, relationName, entities, filter, aggregate) {
1225
- const assembler = core$1.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1358
+ const assembler = core.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1226
1359
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1227
1360
  const convertedQuery = assembler.convertQuery({
1228
1361
  filter
@@ -1243,7 +1376,7 @@ var RelationQueryService = class {
1243
1376
  * @param filter - The filter to apply to the relation query.
1244
1377
  */
1245
1378
  async batchCountRelations(RelationClass, relationName, entities, filter) {
1246
- const assembler = core$1.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1379
+ const assembler = core.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
1247
1380
  const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
1248
1381
  const convertedQuery = assembler.convertQuery({
1249
1382
  filter
@@ -1338,14 +1471,14 @@ var MikroOrmQueryService = class extends RelationQueryService {
1338
1471
  this.useSoftDelete = opts?.useSoftDelete ?? false;
1339
1472
  const serializer = assembler_serializer.getAssemblerSerializer(this.EntityClass);
1340
1473
  if (!serializer) {
1341
- core$1.AssemblerSerializer((e) => {
1474
+ core.AssemblerSerializer((e) => {
1342
1475
  const json = classTransformer.instanceToPlain(e, {
1343
1476
  enableImplicitConversion: true,
1344
1477
  excludeExtraneousValues: true,
1345
1478
  exposeDefaultValues: true
1346
1479
  });
1347
1480
  const jsonWithRemovedEmptyObjects = Object.fromEntries(Object.entries(json).filter(([, value]) => !(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0)));
1348
- const wrapped = core.wrap(e, true);
1481
+ const wrapped = core$1.wrap(e, true);
1349
1482
  const ormJson = "toObject" in wrapped ? wrapped.toObject() : {};
1350
1483
  const data = {
1351
1484
  ...ormJson,
@@ -1353,7 +1486,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1353
1486
  };
1354
1487
  return data;
1355
1488
  })(this.EntityClass);
1356
- core$1.AssemblerDeserializer((d) => {
1489
+ core.AssemblerDeserializer((d) => {
1357
1490
  const entity = this.repo.getEntityManager().create(this.EntityClass, classTransformer.instanceToPlain(d));
1358
1491
  return entity;
1359
1492
  })(this.EntityClass);
@@ -1378,24 +1511,169 @@ var MikroOrmQueryService = class extends RelationQueryService {
1378
1511
  * @param query - The Query used to filter, page, and sort rows.
1379
1512
  */
1380
1513
  async query(query) {
1381
- const qb = this.filterQueryBuilder.select(query);
1382
- await qb.applyFilters();
1383
- return qb.getResultList();
1514
+ const { filterQuery, options } = this.filterQueryBuilder.buildFindOptions(query);
1515
+ const em = this.repo.getEntityManager();
1516
+ let where = filterQuery;
1517
+ if (this.useSoftDelete) {
1518
+ const deletedFilter = {
1519
+ deletedAt: null
1520
+ };
1521
+ where = where ? {
1522
+ $and: [
1523
+ where,
1524
+ deletedFilter
1525
+ ]
1526
+ } : deletedFilter;
1527
+ }
1528
+ return em.find(this.EntityClass, where ?? {}, options);
1384
1529
  }
1385
1530
  async aggregate(filter, aggregate) {
1386
- const qb = this.filterQueryBuilder.aggregate({
1531
+ const { filterQuery } = this.filterQueryBuilder.buildFindOptions({
1387
1532
  filter
1388
- }, aggregate);
1389
- await qb.applyFilters();
1390
- const rawResults = await qb.execute();
1391
- return AggregateBuilder.convertToAggregateResponse(rawResults);
1533
+ });
1534
+ const em = this.repo.getEntityManager();
1535
+ let where = filterQuery;
1536
+ if (this.useSoftDelete) {
1537
+ const deletedFilter = {
1538
+ deletedAt: null
1539
+ };
1540
+ where = where ? {
1541
+ $and: [
1542
+ where,
1543
+ deletedFilter
1544
+ ]
1545
+ } : deletedFilter;
1546
+ }
1547
+ const rows = await em.find(this.EntityClass, where ?? {});
1548
+ const aggs = aggregate;
1549
+ const groupBy = aggs.groupBy ?? [];
1550
+ const records = [];
1551
+ const makeAggKey = /* @__PURE__ */ __name((func, field) => `${func}_${field}`, "makeAggKey");
1552
+ const makeGroupKey = /* @__PURE__ */ __name((field) => `GROUP_BY_${field}`, "makeGroupKey");
1553
+ const isNumeric = /* @__PURE__ */ __name((v) => typeof v === "number" || v instanceof Date, "isNumeric");
1554
+ if (groupBy.length === 0) {
1555
+ const out = {};
1556
+ const computeField = /* @__PURE__ */ __name((fn, field) => {
1557
+ const values = rows.map((r) => r[field]).filter((v) => v !== void 0 && v !== null);
1558
+ if (fn === "COUNT") {
1559
+ out[makeAggKey("COUNT", field)] = values.length;
1560
+ return;
1561
+ }
1562
+ if (values.length === 0) {
1563
+ out[makeAggKey(fn, field)] = null;
1564
+ return;
1565
+ }
1566
+ if (fn === "SUM" || fn === "AVG") {
1567
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v)).filter((n) => !Number.isNaN(n));
1568
+ const sum = nums.reduce((s, v) => s + v, 0);
1569
+ out[makeAggKey(fn, field)] = fn === "SUM" ? sum : nums.length ? sum / nums.length : null;
1570
+ return;
1571
+ }
1572
+ if (fn === "MAX") {
1573
+ if (values.every(isNumeric)) {
1574
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
1575
+ out[makeAggKey("MAX", field)] = Math.max(...nums);
1576
+ } else {
1577
+ out[makeAggKey("MAX", field)] = values.reduce((a, b) => String(a) > String(b) ? a : b);
1578
+ }
1579
+ return;
1580
+ }
1581
+ if (fn === "MIN") {
1582
+ if (values.every(isNumeric)) {
1583
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
1584
+ out[makeAggKey("MIN", field)] = Math.min(...nums);
1585
+ } else {
1586
+ out[makeAggKey("MIN", field)] = values.reduce((a, b) => String(a) < String(b) ? a : b);
1587
+ }
1588
+ return;
1589
+ }
1590
+ }, "computeField");
1591
+ (aggs.count ?? []).forEach((f) => computeField("COUNT", String(f)));
1592
+ (aggs.sum ?? []).forEach((f) => computeField("SUM", String(f)));
1593
+ (aggs.avg ?? []).forEach((f) => computeField("AVG", String(f)));
1594
+ (aggs.max ?? []).forEach((f) => computeField("MAX", String(f)));
1595
+ (aggs.min ?? []).forEach((f) => computeField("MIN", String(f)));
1596
+ records.push(out);
1597
+ } else {
1598
+ const groups = /* @__PURE__ */ new Map();
1599
+ rows.forEach((r) => {
1600
+ const key = groupBy.map((g) => JSON.stringify(r[String(g)])).join("|");
1601
+ const arr = groups.get(key) ?? [];
1602
+ arr.push(r);
1603
+ groups.set(key, arr);
1604
+ });
1605
+ groups.forEach((groupRows, key) => {
1606
+ const parts = key.split("|").map((p) => JSON.parse(p));
1607
+ const out = {};
1608
+ groupBy.forEach((g, i) => {
1609
+ const val = parts[i];
1610
+ out[makeGroupKey(String(g))] = typeof val === "boolean" ? val ? 1 : 0 : val;
1611
+ });
1612
+ const computeField = /* @__PURE__ */ __name((fn, field) => {
1613
+ const values = groupRows.map((r) => r[field]).filter((v) => v !== void 0 && v !== null);
1614
+ if (fn === "COUNT") {
1615
+ out[makeAggKey("COUNT", field)] = values.length;
1616
+ return;
1617
+ }
1618
+ if (values.length === 0) {
1619
+ out[makeAggKey(fn, field)] = null;
1620
+ return;
1621
+ }
1622
+ if (fn === "SUM" || fn === "AVG") {
1623
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v)).filter((n) => !Number.isNaN(n));
1624
+ const sum = nums.reduce((s, v) => s + v, 0);
1625
+ out[makeAggKey(fn, field)] = fn === "SUM" ? sum : nums.length ? sum / nums.length : null;
1626
+ return;
1627
+ }
1628
+ if (fn === "MAX") {
1629
+ if (values.every(isNumeric)) {
1630
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
1631
+ out[makeAggKey("MAX", field)] = Math.max(...nums);
1632
+ } else {
1633
+ out[makeAggKey("MAX", field)] = values.reduce((a, b) => String(a) > String(b) ? a : b);
1634
+ }
1635
+ return;
1636
+ }
1637
+ if (fn === "MIN") {
1638
+ if (values.every(isNumeric)) {
1639
+ const nums = values.map((v) => v instanceof Date ? v.getTime() : Number(v));
1640
+ out[makeAggKey("MIN", field)] = Math.min(...nums);
1641
+ } else {
1642
+ out[makeAggKey("MIN", field)] = values.reduce((a, b) => String(a) < String(b) ? a : b);
1643
+ }
1644
+ return;
1645
+ }
1646
+ }, "computeField");
1647
+ (aggs.count ?? []).forEach((f) => computeField("COUNT", String(f)));
1648
+ (aggs.sum ?? []).forEach((f) => computeField("SUM", String(f)));
1649
+ (aggs.avg ?? []).forEach((f) => computeField("AVG", String(f)));
1650
+ (aggs.max ?? []).forEach((f) => computeField("MAX", String(f)));
1651
+ (aggs.min ?? []).forEach((f) => computeField("MIN", String(f)));
1652
+ records.push(out);
1653
+ });
1654
+ }
1655
+ return records.map((r) => AggregateBuilder.convertToAggregateResponse([
1656
+ r
1657
+ ])[0]);
1392
1658
  }
1393
1659
  async count(filter) {
1394
- const qb = this.filterQueryBuilder.select({
1660
+ const { filterQuery } = this.filterQueryBuilder.buildFindOptions({
1395
1661
  filter
1396
1662
  });
1397
- await qb.applyFilters();
1398
- return qb.getCount();
1663
+ const em = this.repo.getEntityManager();
1664
+ let where = filterQuery;
1665
+ if (this.useSoftDelete) {
1666
+ const deletedFilter = {
1667
+ deletedAt: null
1668
+ };
1669
+ where = where ? {
1670
+ $and: [
1671
+ where,
1672
+ deletedFilter
1673
+ ]
1674
+ } : deletedFilter;
1675
+ }
1676
+ return em.count(this.EntityClass, where ?? {});
1399
1677
  }
1400
1678
  /**
1401
1679
  * Find an entity by it's `id`.
@@ -1407,10 +1685,33 @@ var MikroOrmQueryService = class extends RelationQueryService {
1407
1685
  * @param id - The id of the record to find.
1408
1686
  */
1409
1687
  async findById(id, opts) {
1410
- const qb = this.filterQueryBuilder.selectById(id, opts ?? {});
1411
- await qb.applyFilters();
1412
- const result = await qb.getSingleResult();
1413
- return result ?? void 0;
1688
+ const metadata = this.em.getMetadata().get(this.repo.getEntityName());
1689
+ const primaryKey = metadata.primaryKeys[0];
1690
+ let where = {
1691
+ [primaryKey]: id
1692
+ };
1693
+ if (opts?.filter) {
1694
+ const whereBuilder = new WhereBuilder();
1695
+ const additional = whereBuilder.build(opts.filter);
1696
+ where = {
1697
+ $and: [
1698
+ where,
1699
+ additional
1700
+ ]
1701
+ };
1702
+ }
1703
+ if (this.useSoftDelete) {
1704
+ where = {
1705
+ $and: [
1706
+ where,
1707
+ {
1708
+ deletedAt: null
1709
+ }
1710
+ ]
1711
+ };
1712
+ }
1713
+ const entity = await this.em.findOne(this.EntityClass, where);
1714
+ return entity ?? void 0;
1414
1715
  }
1415
1716
  /**
1416
1717
  * Gets an entity by it's `id`. If the entity is not found a rejected promise is returned.
@@ -1475,9 +1776,10 @@ var MikroOrmQueryService = class extends RelationQueryService {
1475
1776
  * @param opts - Additional options.
1476
1777
  */
1477
1778
  async updateOne(id, update, opts) {
1478
- this.ensureIdIsNotPresent(update);
1779
+ const dateWithClearUndefined = Object.fromEntries(Object.entries(update).filter(([, value]) => value !== void 0));
1780
+ this.ensureIdIsNotPresent(dateWithClearUndefined);
1479
1781
  const entity = await this.getById(id, opts);
1480
- core.wrap(entity).assign(update);
1782
+ core$1.wrap(entity).assign(dateWithClearUndefined);
1481
1783
  await this.repo.getEntityManager().flush();
1482
1784
  return entity;
1483
1785
  }
@@ -1500,7 +1802,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1500
1802
  filter
1501
1803
  });
1502
1804
  for (const entity of entities) {
1503
- core.wrap(entity).assign(update);
1805
+ core$1.wrap(entity).assign(update);
1504
1806
  }
1505
1807
  await this.repo.getEntityManager().flush();
1506
1808
  return {
@@ -1523,7 +1825,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1523
1825
  const entity = await this.getById(id, opts);
1524
1826
  const em = this.repo.getEntityManager();
1525
1827
  if (this.useSoftDelete) {
1526
- core.wrap(entity).assign({
1828
+ core$1.wrap(entity).assign({
1527
1829
  deletedAt: /* @__PURE__ */ new Date()
1528
1830
  });
1529
1831
  await em.flush();
@@ -1552,7 +1854,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1552
1854
  const em = this.repo.getEntityManager();
1553
1855
  if (this.useSoftDelete) {
1554
1856
  for (const entity of entities) {
1555
- core.wrap(entity).assign({
1857
+ core$1.wrap(entity).assign({
1556
1858
  deletedAt: /* @__PURE__ */ new Date()
1557
1859
  });
1558
1860
  }
@@ -1602,7 +1904,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1602
1904
  if (!entity) {
1603
1905
  throw new common.NotFoundException(`Unable to find ${this.EntityClass.name} with id: ${id}`);
1604
1906
  }
1605
- core.wrap(entity).assign({
1907
+ core$1.wrap(entity).assign({
1606
1908
  deletedAt: null
1607
1909
  });
1608
1910
  await em.flush();
@@ -1630,7 +1932,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1630
1932
  filters: false
1631
1933
  });
1632
1934
  for (const entity of entities) {
1633
- core.wrap(entity).assign({
1935
+ core$1.wrap(entity).assign({
1634
1936
  deletedAt: null
1635
1937
  });
1636
1938
  }
@@ -1682,7 +1984,7 @@ var MikroOrmQueryService = class extends RelationQueryService {
1682
1984
  function createMikroOrmQueryServiceProvider(EntityClass, contextName) {
1683
1985
  return {
1684
1986
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
1685
- provide: core$1.getQueryServiceToken(EntityClass),
1987
+ provide: core.getQueryServiceToken(EntityClass),
1686
1988
  useFactory(repo) {
1687
1989
  return new MikroOrmQueryService(repo);
1688
1990
  },
@@ -1719,12 +2021,12 @@ var NestjsQueryMikroOrmModule = class _NestjsQueryMikroOrmModule {
1719
2021
  };
1720
2022
 
1721
2023
  exports.AggregateBuilder = AggregateBuilder;
2024
+ exports.ComparisonBuilder = ComparisonBuilder;
1722
2025
  exports.FilterQueryBuilder = FilterQueryBuilder;
1723
2026
  exports.MikroOrmQueryService = MikroOrmQueryService;
1724
2027
  exports.NestjsQueryMikroOrmModule = NestjsQueryMikroOrmModule;
1725
2028
  exports.RelationQueryBuilder = RelationQueryBuilder;
1726
2029
  exports.RelationQueryService = RelationQueryService;
1727
- exports.SQLComparisonBuilder = SQLComparisonBuilder;
1728
2030
  exports.WhereBuilder = WhereBuilder;
1729
2031
  exports.createMikroOrmQueryServiceProviders = createMikroOrmQueryServiceProviders;
1730
2032
  //# sourceMappingURL=index.cjs.map