nestjs-query-mikro-orm 0.1.3 → 0.1.5
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/README.md +138 -103
- package/dist/index.cjs +425 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -11
- package/dist/index.d.ts +47 -11
- package/dist/index.mjs +425 -138
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -660,53 +660,81 @@ var RelationQueryBuilder = class {
|
|
|
660
660
|
this.filterQueryBuilder = new FilterQueryBuilder(relationRepo);
|
|
661
661
|
}
|
|
662
662
|
/**
|
|
663
|
-
* Executes a relation select using
|
|
663
|
+
* Executes a relation select using MikroORM native relation population first.
|
|
664
664
|
*/
|
|
665
|
-
async selectAndExecute(entity, query) {
|
|
666
|
-
const
|
|
665
|
+
async selectAndExecute(entity, query, loadOptions) {
|
|
666
|
+
const nativeRelations = await this.tryLoadRelationsNatively(entity, loadOptions?.useDataloader, loadOptions?.strategy);
|
|
667
|
+
if (!nativeRelations) {
|
|
668
|
+
return this.queryByOwnerCondition(entity, query);
|
|
669
|
+
}
|
|
670
|
+
const resolvedRelations = nativeRelations;
|
|
671
|
+
if (!this.hasFilterSortingOrPaging(query)) {
|
|
672
|
+
return resolvedRelations;
|
|
673
|
+
}
|
|
674
|
+
if (!this.hasFilterOrSorting(query)) {
|
|
675
|
+
return this.applyPaging(resolvedRelations, query);
|
|
676
|
+
}
|
|
677
|
+
return this.queryResolvedRelations(resolvedRelations, query);
|
|
678
|
+
}
|
|
679
|
+
async batchSelectAndExecute(entities, query, loadOptions) {
|
|
680
|
+
if (entities.length === 0) {
|
|
681
|
+
return /* @__PURE__ */ new Map();
|
|
682
|
+
}
|
|
683
|
+
const nativeRelationsMap = await this.tryBatchLoadRelationsNatively(entities, loadOptions?.useDataloader, loadOptions?.strategy);
|
|
684
|
+
if (!nativeRelationsMap) {
|
|
685
|
+
const results2 = /* @__PURE__ */ new Map();
|
|
686
|
+
await Promise.all(entities.map(async (entity) => {
|
|
687
|
+
const relations = await this.queryByOwnerCondition(entity, query);
|
|
688
|
+
if (relations.length > 0) {
|
|
689
|
+
results2.set(entity, relations);
|
|
690
|
+
}
|
|
691
|
+
}));
|
|
692
|
+
return results2;
|
|
693
|
+
}
|
|
694
|
+
if (!this.hasFilterSortingOrPaging(query)) {
|
|
695
|
+
return nativeRelationsMap;
|
|
696
|
+
}
|
|
697
|
+
if (!this.hasFilterOrSorting(query)) {
|
|
698
|
+
return this.applyPagingToMap(nativeRelationsMap, query);
|
|
699
|
+
}
|
|
700
|
+
const results = /* @__PURE__ */ new Map();
|
|
701
|
+
await Promise.all(entities.map(async (entity) => {
|
|
702
|
+
const relations = nativeRelationsMap.get(entity) ?? [];
|
|
703
|
+
const queried = await this.queryResolvedRelations(relations, query);
|
|
704
|
+
if (queried.length > 0) {
|
|
705
|
+
results.set(entity, queried);
|
|
706
|
+
}
|
|
707
|
+
}));
|
|
708
|
+
return results;
|
|
709
|
+
}
|
|
710
|
+
async populateEntityRelation(entity, useDataloader, strategy) {
|
|
667
711
|
const em = this.repo.getEntityManager();
|
|
668
|
-
const
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
|
|
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);
|
|
712
|
+
const emPopulate = em;
|
|
713
|
+
try {
|
|
714
|
+
await emPopulate.populate([
|
|
715
|
+
entity
|
|
716
|
+
], [
|
|
717
|
+
this.relation
|
|
718
|
+
], this.getNativePopulateOptions(useDataloader, strategy));
|
|
719
|
+
return true;
|
|
720
|
+
} catch {
|
|
721
|
+
return false;
|
|
722
|
+
}
|
|
682
723
|
}
|
|
683
724
|
async count(entity, query) {
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
$and: [
|
|
691
|
-
baseWhere,
|
|
692
|
-
filterQuery
|
|
693
|
-
]
|
|
694
|
-
} : baseWhere;
|
|
695
|
-
return em.count(RelationEntity, finalWhere);
|
|
725
|
+
const relations = await this.selectAndExecute(entity, {
|
|
726
|
+
...query,
|
|
727
|
+
paging: void 0,
|
|
728
|
+
sorting: void 0
|
|
729
|
+
});
|
|
730
|
+
return relations.length;
|
|
696
731
|
}
|
|
697
732
|
async aggregate(entity, query, aggregateQuery) {
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
const finalWhere = filterQuery ? {
|
|
704
|
-
$and: [
|
|
705
|
-
baseWhere,
|
|
706
|
-
filterQuery
|
|
707
|
-
]
|
|
708
|
-
} : baseWhere;
|
|
709
|
-
const rows = await em.find(RelationEntity, finalWhere);
|
|
733
|
+
const rows = await this.selectAndExecute(entity, {
|
|
734
|
+
...query,
|
|
735
|
+
paging: void 0,
|
|
736
|
+
sorting: void 0
|
|
737
|
+
});
|
|
710
738
|
const aggs = aggregateQuery;
|
|
711
739
|
const groupBy = aggs.groupBy ?? [];
|
|
712
740
|
const makeAggKey = /* @__PURE__ */ __name((func, field) => `${func}_${field}`, "makeAggKey");
|
|
@@ -817,6 +845,259 @@ var RelationQueryBuilder = class {
|
|
|
817
845
|
}
|
|
818
846
|
return records;
|
|
819
847
|
}
|
|
848
|
+
getRelationMeta() {
|
|
849
|
+
const em = this.repo.getEntityManager();
|
|
850
|
+
const metadata = em.getMetadata().get(this.repo.getEntityName());
|
|
851
|
+
const relationProp = metadata.properties[this.relation];
|
|
852
|
+
if (!relationProp) {
|
|
853
|
+
throw new Error(`Unable to find relation '${this.relation}' on entity`);
|
|
854
|
+
}
|
|
855
|
+
return relationProp;
|
|
856
|
+
}
|
|
857
|
+
get entityIndexColName() {
|
|
858
|
+
return "__nestjsQuery__entityIndex__";
|
|
859
|
+
}
|
|
860
|
+
getRelationPrimaryKeysPropertyNameAndColumnsName() {
|
|
861
|
+
const em = this.repo.getEntityManager();
|
|
862
|
+
const relationMeta = this.getRelationMeta();
|
|
863
|
+
const relationEntityMeta = em.getMetadata().get(relationMeta.type);
|
|
864
|
+
return relationEntityMeta.primaryKeys.map((pk) => {
|
|
865
|
+
const prop = relationEntityMeta.properties[pk];
|
|
866
|
+
return {
|
|
867
|
+
propertyName: pk,
|
|
868
|
+
columnName: prop.fieldNames?.[0] || pk
|
|
869
|
+
};
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
getNativeLoadOptions(useDataloader = false) {
|
|
873
|
+
if (!useDataloader) {
|
|
874
|
+
return void 0;
|
|
875
|
+
}
|
|
876
|
+
return {
|
|
877
|
+
dataloader: true
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
getNativePopulateOptions(useDataloader = false, strategy) {
|
|
881
|
+
const nativeLoadOptions = this.getNativeLoadOptions(useDataloader);
|
|
882
|
+
const options = {};
|
|
883
|
+
if (nativeLoadOptions) {
|
|
884
|
+
options.dataloader = true;
|
|
885
|
+
}
|
|
886
|
+
if (strategy) {
|
|
887
|
+
options.strategy = strategy;
|
|
888
|
+
}
|
|
889
|
+
if (!Object.keys(options).length) {
|
|
890
|
+
return void 0;
|
|
891
|
+
}
|
|
892
|
+
return options;
|
|
893
|
+
}
|
|
894
|
+
async tryBatchLoadRelationsNatively(entities, useDataloader = false, strategy) {
|
|
895
|
+
const em = this.repo.getEntityManager();
|
|
896
|
+
const entityName = this.repo.getEntityName();
|
|
897
|
+
const metadata = em.getMetadata().get(entityName);
|
|
898
|
+
const primaryKey = metadata.primaryKeys[0];
|
|
899
|
+
const entityAndIds = entities.map((entity) => {
|
|
900
|
+
const id = entity[primaryKey];
|
|
901
|
+
return [
|
|
902
|
+
entity,
|
|
903
|
+
id
|
|
904
|
+
];
|
|
905
|
+
});
|
|
906
|
+
const ids = entityAndIds.map(([, id]) => id).filter((id) => id !== void 0 && id !== null);
|
|
907
|
+
if (!ids.length) {
|
|
908
|
+
return /* @__PURE__ */ new Map();
|
|
909
|
+
}
|
|
910
|
+
const where = {
|
|
911
|
+
[primaryKey]: {
|
|
912
|
+
$in: ids
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
const findOptions = {
|
|
916
|
+
...this.getNativePopulateOptions(useDataloader, strategy) ?? {},
|
|
917
|
+
populate: [
|
|
918
|
+
this.relation
|
|
919
|
+
]
|
|
920
|
+
};
|
|
921
|
+
let populatedEntities;
|
|
922
|
+
try {
|
|
923
|
+
populatedEntities = await em.find(entityName, where, findOptions);
|
|
924
|
+
} catch {
|
|
925
|
+
return void 0;
|
|
926
|
+
}
|
|
927
|
+
const relationMeta = this.getRelationMeta();
|
|
928
|
+
const relationsMap = /* @__PURE__ */ new Map();
|
|
929
|
+
const populatedById = /* @__PURE__ */ new Map();
|
|
930
|
+
populatedEntities.forEach((populatedEntity) => {
|
|
931
|
+
const id = populatedEntity[primaryKey];
|
|
932
|
+
if (id !== void 0 && id !== null) {
|
|
933
|
+
populatedById.set(this.serializePrimaryKeyValue(id), populatedEntity);
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
for (const [entity, id] of entityAndIds) {
|
|
937
|
+
if (id === void 0 || id === null) {
|
|
938
|
+
relationsMap.set(entity, []);
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
const resolvedEntity = populatedById.get(this.serializePrimaryKeyValue(id));
|
|
942
|
+
if (!resolvedEntity) {
|
|
943
|
+
relationsMap.set(entity, []);
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
const relations = this.readLoadedRelation(resolvedEntity, relationMeta);
|
|
947
|
+
if (relations === void 0) {
|
|
948
|
+
return void 0;
|
|
949
|
+
}
|
|
950
|
+
relationsMap.set(entity, relations);
|
|
951
|
+
}
|
|
952
|
+
return relationsMap;
|
|
953
|
+
}
|
|
954
|
+
async tryLoadRelationsNatively(entity, useDataloader = false, strategy) {
|
|
955
|
+
const relationsMap = await this.tryBatchLoadRelationsNatively([
|
|
956
|
+
entity
|
|
957
|
+
], useDataloader, strategy);
|
|
958
|
+
if (!relationsMap) {
|
|
959
|
+
return void 0;
|
|
960
|
+
}
|
|
961
|
+
return relationsMap.get(entity) ?? [];
|
|
962
|
+
}
|
|
963
|
+
readLoadedRelation(entity, relationMeta) {
|
|
964
|
+
const entityRecord = entity;
|
|
965
|
+
const propsRecord = entityRecord.props;
|
|
966
|
+
const relationValue = entityRecord[this.relation] !== void 0 ? entityRecord[this.relation] : propsRecord?.[this.relation];
|
|
967
|
+
if (relationMeta.kind === "1:m" || relationMeta.kind === "m:n") {
|
|
968
|
+
if (!relationValue || typeof relationValue !== "object") {
|
|
969
|
+
return void 0;
|
|
970
|
+
}
|
|
971
|
+
const maybeCollection = relationValue;
|
|
972
|
+
if (typeof maybeCollection.getItems === "function") {
|
|
973
|
+
return maybeCollection.getItems(false);
|
|
974
|
+
}
|
|
975
|
+
if (Array.isArray(relationValue)) {
|
|
976
|
+
return relationValue;
|
|
977
|
+
}
|
|
978
|
+
return void 0;
|
|
979
|
+
}
|
|
980
|
+
if (relationValue === null || relationValue === void 0) {
|
|
981
|
+
return [];
|
|
982
|
+
}
|
|
983
|
+
if (typeof relationValue !== "object") {
|
|
984
|
+
return void 0;
|
|
985
|
+
}
|
|
986
|
+
const maybeReference = relationValue;
|
|
987
|
+
if (maybeReference.$ !== void 0) {
|
|
988
|
+
return maybeReference.$ === null ? [] : [
|
|
989
|
+
maybeReference.$
|
|
990
|
+
];
|
|
991
|
+
}
|
|
992
|
+
if (typeof maybeReference.get === "function") {
|
|
993
|
+
try {
|
|
994
|
+
const loaded = maybeReference.get();
|
|
995
|
+
return loaded === null || loaded === void 0 ? [] : [
|
|
996
|
+
loaded
|
|
997
|
+
];
|
|
998
|
+
} catch {
|
|
999
|
+
return void 0;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (typeof maybeReference.getEntity === "function") {
|
|
1003
|
+
try {
|
|
1004
|
+
const loaded = maybeReference.getEntity();
|
|
1005
|
+
return loaded === null || loaded === void 0 ? [] : [
|
|
1006
|
+
loaded
|
|
1007
|
+
];
|
|
1008
|
+
} catch {
|
|
1009
|
+
return void 0;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
if (typeof maybeReference.unwrap === "function") {
|
|
1013
|
+
const loaded = maybeReference.unwrap();
|
|
1014
|
+
return loaded === null || loaded === void 0 ? [] : [
|
|
1015
|
+
loaded
|
|
1016
|
+
];
|
|
1017
|
+
}
|
|
1018
|
+
return [
|
|
1019
|
+
relationValue
|
|
1020
|
+
];
|
|
1021
|
+
}
|
|
1022
|
+
applyPaging(relations, query) {
|
|
1023
|
+
const limit = query.paging?.limit;
|
|
1024
|
+
const offset = query.paging?.offset ?? 0;
|
|
1025
|
+
if (limit === void 0 && offset === 0) {
|
|
1026
|
+
return relations;
|
|
1027
|
+
}
|
|
1028
|
+
if (limit === void 0) {
|
|
1029
|
+
return relations.slice(offset);
|
|
1030
|
+
}
|
|
1031
|
+
return relations.slice(offset, offset + limit);
|
|
1032
|
+
}
|
|
1033
|
+
applyPagingToMap(relationsMap, query) {
|
|
1034
|
+
const mapped = /* @__PURE__ */ new Map();
|
|
1035
|
+
for (const [entity, relations] of relationsMap.entries()) {
|
|
1036
|
+
const paged = this.applyPaging(relations, query);
|
|
1037
|
+
if (paged.length > 0) {
|
|
1038
|
+
mapped.set(entity, paged);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
return mapped;
|
|
1042
|
+
}
|
|
1043
|
+
serializePrimaryKeyValue(value) {
|
|
1044
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
1045
|
+
}
|
|
1046
|
+
hasFilterSortingOrPaging(query) {
|
|
1047
|
+
return this.hasFilterOrSorting(query) || Boolean(query.paging?.limit || query.paging?.offset);
|
|
1048
|
+
}
|
|
1049
|
+
hasFilterOrSorting(query) {
|
|
1050
|
+
return Boolean(query.sorting?.length) || Boolean(query.filter && Object.keys(query.filter).length);
|
|
1051
|
+
}
|
|
1052
|
+
async queryResolvedRelations(resolvedRelations, query) {
|
|
1053
|
+
if (resolvedRelations.length === 0) {
|
|
1054
|
+
return [];
|
|
1055
|
+
}
|
|
1056
|
+
const em = this.repo.getEntityManager();
|
|
1057
|
+
const relationMeta = this.getRelationMeta();
|
|
1058
|
+
const RelationEntity = relationMeta.type;
|
|
1059
|
+
const metadata = em.getMetadata().get(RelationEntity);
|
|
1060
|
+
const primaryKey = metadata.primaryKeys[0];
|
|
1061
|
+
const ids = resolvedRelations.map((r) => r[primaryKey]).filter((v) => v !== void 0 && v !== null);
|
|
1062
|
+
if (!ids.length) {
|
|
1063
|
+
return [];
|
|
1064
|
+
}
|
|
1065
|
+
const idFilter = {
|
|
1066
|
+
[primaryKey]: {
|
|
1067
|
+
$in: ids
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
const { filterQuery, options } = this.filterQueryBuilder.buildFindOptions(query);
|
|
1071
|
+
const finalWhere = filterQuery ? {
|
|
1072
|
+
$and: [
|
|
1073
|
+
idFilter,
|
|
1074
|
+
filterQuery
|
|
1075
|
+
]
|
|
1076
|
+
} : idFilter;
|
|
1077
|
+
const findOptions = {};
|
|
1078
|
+
if (options?.orderBy) findOptions.orderBy = options.orderBy;
|
|
1079
|
+
if (options?.limit !== void 0) findOptions.limit = options.limit;
|
|
1080
|
+
if (options?.offset !== void 0) findOptions.offset = options.offset;
|
|
1081
|
+
return em.find(RelationEntity, finalWhere, findOptions);
|
|
1082
|
+
}
|
|
1083
|
+
async queryByOwnerCondition(entity, query) {
|
|
1084
|
+
const relationMeta = this.getRelationMeta();
|
|
1085
|
+
const em = this.repo.getEntityManager();
|
|
1086
|
+
const RelationEntity = relationMeta.type;
|
|
1087
|
+
const baseWhere = this.buildWhereCondition(entity, relationMeta);
|
|
1088
|
+
const { filterQuery, options } = this.filterQueryBuilder.buildFindOptions(query);
|
|
1089
|
+
const finalWhere = filterQuery ? {
|
|
1090
|
+
$and: [
|
|
1091
|
+
baseWhere,
|
|
1092
|
+
filterQuery
|
|
1093
|
+
]
|
|
1094
|
+
} : baseWhere;
|
|
1095
|
+
const findOptions = {};
|
|
1096
|
+
if (options?.orderBy) findOptions.orderBy = options.orderBy;
|
|
1097
|
+
if (options?.limit !== void 0) findOptions.limit = options.limit;
|
|
1098
|
+
if (options?.offset !== void 0) findOptions.offset = options.offset;
|
|
1099
|
+
return em.find(RelationEntity, finalWhere, findOptions);
|
|
1100
|
+
}
|
|
820
1101
|
buildWhereCondition(entity, relationMeta) {
|
|
821
1102
|
const em = this.repo.getEntityManager();
|
|
822
1103
|
const entityMeta = em.getMetadata().get(this.repo.getEntityName());
|
|
@@ -888,16 +1169,14 @@ var RelationQueryBuilder = class {
|
|
|
888
1169
|
return {
|
|
889
1170
|
[relationPrimaryKey]: fkValue
|
|
890
1171
|
};
|
|
891
|
-
} else {
|
|
892
|
-
return {
|
|
893
|
-
[relationMeta.mappedBy]: entityId
|
|
894
|
-
};
|
|
895
1172
|
}
|
|
1173
|
+
return {
|
|
1174
|
+
[relationMeta.mappedBy]: entityId
|
|
1175
|
+
};
|
|
896
1176
|
}
|
|
897
1177
|
if (relationMeta.kind === "1:m") {
|
|
898
|
-
const mappedBy = relationMeta.mappedBy;
|
|
899
1178
|
return {
|
|
900
|
-
[mappedBy]: entityId
|
|
1179
|
+
[relationMeta.mappedBy]: entityId
|
|
901
1180
|
};
|
|
902
1181
|
}
|
|
903
1182
|
if (relationMeta.kind === "m:n") {
|
|
@@ -905,40 +1184,15 @@ var RelationQueryBuilder = class {
|
|
|
905
1184
|
return {
|
|
906
1185
|
[relationMeta.inversedBy]: entityId
|
|
907
1186
|
};
|
|
908
|
-
} else {
|
|
909
|
-
return {
|
|
910
|
-
[relationMeta.mappedBy]: entityId
|
|
911
|
-
};
|
|
912
1187
|
}
|
|
1188
|
+
return {
|
|
1189
|
+
[relationMeta.mappedBy]: entityId
|
|
1190
|
+
};
|
|
913
1191
|
}
|
|
914
1192
|
return {
|
|
915
1193
|
[entityPrimaryKey]: entityId
|
|
916
1194
|
};
|
|
917
1195
|
}
|
|
918
|
-
getRelationMeta() {
|
|
919
|
-
const em = this.repo.getEntityManager();
|
|
920
|
-
const metadata = em.getMetadata().get(this.repo.getEntityName());
|
|
921
|
-
const relationProp = metadata.properties[this.relation];
|
|
922
|
-
if (!relationProp) {
|
|
923
|
-
throw new Error(`Unable to find relation '${this.relation}' on entity`);
|
|
924
|
-
}
|
|
925
|
-
return relationProp;
|
|
926
|
-
}
|
|
927
|
-
get entityIndexColName() {
|
|
928
|
-
return "__nestjsQuery__entityIndex__";
|
|
929
|
-
}
|
|
930
|
-
getRelationPrimaryKeysPropertyNameAndColumnsName() {
|
|
931
|
-
const em = this.repo.getEntityManager();
|
|
932
|
-
const relationMeta = this.getRelationMeta();
|
|
933
|
-
const relationEntityMeta = em.getMetadata().get(relationMeta.type);
|
|
934
|
-
return relationEntityMeta.primaryKeys.map((pk) => {
|
|
935
|
-
const prop = relationEntityMeta.properties[pk];
|
|
936
|
-
return {
|
|
937
|
-
propertyName: pk,
|
|
938
|
-
columnName: prop.fieldNames?.[0] || pk
|
|
939
|
-
};
|
|
940
|
-
});
|
|
941
|
-
}
|
|
942
1196
|
};
|
|
943
1197
|
var AGG_REGEXP = /^(AVG|SUM|COUNT|MAX|MIN|GROUP_BY|group_by|groupBy|avg|sum|count|max|min)_(.*)$/i;
|
|
944
1198
|
var AggregateBuilder = class _AggregateBuilder {
|
|
@@ -1177,17 +1431,25 @@ var RelationQueryService = class {
|
|
|
1177
1431
|
static {
|
|
1178
1432
|
__name(this, "RelationQueryService");
|
|
1179
1433
|
}
|
|
1434
|
+
relationLoadingStrategy;
|
|
1435
|
+
nativeLoadUseDataloader;
|
|
1436
|
+
constructor(opts) {
|
|
1437
|
+
this.relationLoadingStrategy = opts?.relationLoading?.strategy;
|
|
1438
|
+
this.nativeLoadUseDataloader = opts?.relationLoading?.useDataloader ?? false;
|
|
1439
|
+
}
|
|
1180
1440
|
async queryRelations(RelationClass, relationName, dto, query) {
|
|
1181
1441
|
if (Array.isArray(dto)) {
|
|
1182
1442
|
return this.batchQueryRelations(RelationClass, relationName, dto, query);
|
|
1183
1443
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
}
|
|
1188
|
-
const assembler = nestjsQueryCore.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
|
|
1444
|
+
const bypassAssembler = this.isRelationClassIdentity(RelationClass, relationName);
|
|
1445
|
+
const assembler = bypassAssembler ? void 0 : nestjsQueryCore.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
|
|
1446
|
+
const convertedQuery = assembler ? assembler.convertQuery(query) : query;
|
|
1189
1447
|
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
|
|
1190
|
-
|
|
1448
|
+
const relations = await relationQueryBuilder.selectAndExecute(dto, convertedQuery, this.getRelationLoadOptions());
|
|
1449
|
+
if (bypassAssembler) {
|
|
1450
|
+
return relations;
|
|
1451
|
+
}
|
|
1452
|
+
return assembler.convertToDTOs(relations);
|
|
1191
1453
|
}
|
|
1192
1454
|
async aggregateRelations(RelationClass, relationName, dto, filter, aggregate) {
|
|
1193
1455
|
if (Array.isArray(dto)) {
|
|
@@ -1225,7 +1487,7 @@ var RelationQueryService = class {
|
|
|
1225
1487
|
paging: {
|
|
1226
1488
|
limit: 1
|
|
1227
1489
|
}
|
|
1228
|
-
});
|
|
1490
|
+
}, this.getRelationLoadOptions());
|
|
1229
1491
|
return relations2[0];
|
|
1230
1492
|
}
|
|
1231
1493
|
const assembler = nestjsQueryCore.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
|
|
@@ -1235,7 +1497,7 @@ var RelationQueryService = class {
|
|
|
1235
1497
|
paging: {
|
|
1236
1498
|
limit: 1
|
|
1237
1499
|
}
|
|
1238
|
-
});
|
|
1500
|
+
}, this.getRelationLoadOptions());
|
|
1239
1501
|
const relationEntity = relations[0];
|
|
1240
1502
|
return relationEntity ? assembler.convertToDTO(relationEntity) : void 0;
|
|
1241
1503
|
}
|
|
@@ -1253,19 +1515,24 @@ var RelationQueryService = class {
|
|
|
1253
1515
|
if (!this.foundAllRelations(relationIds, relations)) {
|
|
1254
1516
|
throw new Error(`Unable to find all ${relationName} to add to ${this.EntityClass.name}`);
|
|
1255
1517
|
}
|
|
1256
|
-
|
|
1518
|
+
const collection = entity[relationName];
|
|
1519
|
+
if (collection && typeof collection.add === "function") {
|
|
1520
|
+
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
|
|
1521
|
+
const populated = await relationQueryBuilder.populateEntityRelation(entity, this.nativeLoadUseDataloader, this.relationLoadingStrategy);
|
|
1522
|
+
if (!populated) {
|
|
1523
|
+
await collection.init();
|
|
1524
|
+
}
|
|
1257
1525
|
for (const relation of relations) {
|
|
1258
|
-
|
|
1259
|
-
[meta.mappedBy]: entity
|
|
1260
|
-
});
|
|
1526
|
+
collection.add(relation);
|
|
1261
1527
|
}
|
|
1262
1528
|
await this.repo.getEntityManager().flush();
|
|
1263
1529
|
return entity;
|
|
1264
1530
|
}
|
|
1265
|
-
|
|
1266
|
-
if (collection && typeof collection.add === "function") {
|
|
1531
|
+
if (meta.kind === "1:m" && meta.mappedBy) {
|
|
1267
1532
|
for (const relation of relations) {
|
|
1268
|
-
|
|
1533
|
+
core.wrap(relation).assign({
|
|
1534
|
+
[meta.mappedBy]: entity
|
|
1535
|
+
});
|
|
1269
1536
|
}
|
|
1270
1537
|
await this.repo.getEntityManager().flush();
|
|
1271
1538
|
}
|
|
@@ -1289,9 +1556,20 @@ var RelationQueryService = class {
|
|
|
1289
1556
|
throw new Error(`Unable to find all ${relationName} to set on ${this.EntityClass.name}`);
|
|
1290
1557
|
}
|
|
1291
1558
|
}
|
|
1559
|
+
const collection = entity[relationName];
|
|
1560
|
+
if (collection && typeof collection.set === "function") {
|
|
1561
|
+
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
|
|
1562
|
+
const populated = await relationQueryBuilder.populateEntityRelation(entity, this.nativeLoadUseDataloader, this.relationLoadingStrategy);
|
|
1563
|
+
if (!populated) {
|
|
1564
|
+
await collection.init();
|
|
1565
|
+
}
|
|
1566
|
+
collection.set(relations);
|
|
1567
|
+
await this.repo.getEntityManager().flush();
|
|
1568
|
+
return entity;
|
|
1569
|
+
}
|
|
1292
1570
|
if (meta.kind === "1:m" && meta.mappedBy) {
|
|
1293
1571
|
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
|
|
1294
|
-
const currentRelations = await relationQueryBuilder.selectAndExecute(entity, {});
|
|
1572
|
+
const currentRelations = await relationQueryBuilder.selectAndExecute(entity, {}, this.getRelationLoadOptions());
|
|
1295
1573
|
const nextSet = new Set(relations.map((r) => core.wrap(r).getPrimaryKey()));
|
|
1296
1574
|
for (const currentRelation of currentRelations) {
|
|
1297
1575
|
const currentPk = core.wrap(currentRelation).getPrimaryKey();
|
|
@@ -1307,13 +1585,6 @@ var RelationQueryService = class {
|
|
|
1307
1585
|
});
|
|
1308
1586
|
}
|
|
1309
1587
|
await this.repo.getEntityManager().flush();
|
|
1310
|
-
return entity;
|
|
1311
|
-
}
|
|
1312
|
-
const collection = entity[relationName];
|
|
1313
|
-
if (collection && typeof collection.set === "function") {
|
|
1314
|
-
await collection.init();
|
|
1315
|
-
collection.set(relations);
|
|
1316
|
-
await this.repo.getEntityManager().flush();
|
|
1317
1588
|
}
|
|
1318
1589
|
return entity;
|
|
1319
1590
|
}
|
|
@@ -1353,20 +1624,24 @@ var RelationQueryService = class {
|
|
|
1353
1624
|
if (!this.foundAllRelations(relationIds, relations)) {
|
|
1354
1625
|
throw new Error(`Unable to find all ${relationName} to remove from ${this.EntityClass.name}`);
|
|
1355
1626
|
}
|
|
1356
|
-
|
|
1627
|
+
const collection = entity[relationName];
|
|
1628
|
+
if (collection && typeof collection.remove === "function") {
|
|
1629
|
+
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
|
|
1630
|
+
const populated = await relationQueryBuilder.populateEntityRelation(entity, this.nativeLoadUseDataloader, this.relationLoadingStrategy);
|
|
1631
|
+
if (!populated) {
|
|
1632
|
+
await collection.init();
|
|
1633
|
+
}
|
|
1357
1634
|
for (const relation of relations) {
|
|
1358
|
-
|
|
1359
|
-
[meta.mappedBy]: null
|
|
1360
|
-
});
|
|
1635
|
+
collection.remove(relation);
|
|
1361
1636
|
}
|
|
1362
1637
|
await this.repo.getEntityManager().flush();
|
|
1363
1638
|
return entity;
|
|
1364
1639
|
}
|
|
1365
|
-
|
|
1366
|
-
if (collection && typeof collection.remove === "function") {
|
|
1367
|
-
await collection.init();
|
|
1640
|
+
if (meta.kind === "1:m" && meta.mappedBy) {
|
|
1368
1641
|
for (const relation of relations) {
|
|
1369
|
-
|
|
1642
|
+
core.wrap(relation).assign({
|
|
1643
|
+
[meta.mappedBy]: null
|
|
1644
|
+
});
|
|
1370
1645
|
}
|
|
1371
1646
|
await this.repo.getEntityManager().flush();
|
|
1372
1647
|
}
|
|
@@ -1390,29 +1665,30 @@ var RelationQueryService = class {
|
|
|
1390
1665
|
const meta = this.getRelationMeta(relationName);
|
|
1391
1666
|
if (meta.kind === "1:1" || meta.kind === "m:1") {
|
|
1392
1667
|
const fkFieldName = `${relationName}Id`;
|
|
1393
|
-
const assignData = {
|
|
1668
|
+
const assignData = {
|
|
1669
|
+
[relationName]: null
|
|
1670
|
+
};
|
|
1394
1671
|
const ownDescriptor = Object.getOwnPropertyDescriptor(entity, fkFieldName);
|
|
1395
1672
|
const protoDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(entity), fkFieldName);
|
|
1396
1673
|
const descriptor = ownDescriptor ?? protoDescriptor;
|
|
1397
1674
|
const canAssignFk = fkFieldName in entity && (!descriptor || Boolean(descriptor.set) || descriptor.writable === true);
|
|
1398
1675
|
if (canAssignFk) {
|
|
1399
1676
|
assignData[fkFieldName] = null;
|
|
1400
|
-
} else {
|
|
1401
|
-
assignData[relationName] = null;
|
|
1402
1677
|
}
|
|
1403
1678
|
core.wrap(entity).assign(assignData);
|
|
1404
1679
|
} else {
|
|
1405
|
-
if (meta.kind === "1:m" && meta.mappedBy) {
|
|
1406
|
-
core.wrap(relation).assign({
|
|
1407
|
-
[meta.mappedBy]: null
|
|
1408
|
-
});
|
|
1409
|
-
await this.repo.getEntityManager().flush();
|
|
1410
|
-
return entity;
|
|
1411
|
-
}
|
|
1412
1680
|
const collection = entity[relationName];
|
|
1413
1681
|
if (collection && typeof collection.remove === "function") {
|
|
1414
|
-
|
|
1682
|
+
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
|
|
1683
|
+
const populated = await relationQueryBuilder.populateEntityRelation(entity, this.nativeLoadUseDataloader, this.relationLoadingStrategy);
|
|
1684
|
+
if (!populated) {
|
|
1685
|
+
await collection.init();
|
|
1686
|
+
}
|
|
1415
1687
|
collection.remove(relation);
|
|
1688
|
+
} else if (meta.kind === "1:m" && meta.mappedBy) {
|
|
1689
|
+
core.wrap(relation).assign({
|
|
1690
|
+
[meta.mappedBy]: null
|
|
1691
|
+
});
|
|
1416
1692
|
}
|
|
1417
1693
|
}
|
|
1418
1694
|
await this.repo.getEntityManager().flush();
|
|
@@ -1433,15 +1709,18 @@ var RelationQueryService = class {
|
|
|
1433
1709
|
const assembler = bypassAssembler ? void 0 : nestjsQueryCore.AssemblerFactory.getAssembler(RelationClass, this.getRelationEntity(relationName));
|
|
1434
1710
|
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
|
|
1435
1711
|
const convertedQuery = assembler ? assembler.convertQuery(query) : query;
|
|
1436
|
-
const
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1712
|
+
const relationsMap = await relationQueryBuilder.batchSelectAndExecute(entities, convertedQuery, this.getRelationLoadOptions());
|
|
1713
|
+
if (bypassAssembler) {
|
|
1714
|
+
return relationsMap;
|
|
1715
|
+
}
|
|
1716
|
+
const dtoMap = /* @__PURE__ */ new Map();
|
|
1717
|
+
for (const [entity, relations] of relationsMap.entries()) {
|
|
1718
|
+
const relationDtos = await assembler.convertToDTOs(relations);
|
|
1440
1719
|
if (relationDtos.length > 0) {
|
|
1441
|
-
|
|
1720
|
+
dtoMap.set(entity, relationDtos);
|
|
1442
1721
|
}
|
|
1443
|
-
}
|
|
1444
|
-
return
|
|
1722
|
+
}
|
|
1723
|
+
return dtoMap;
|
|
1445
1724
|
}
|
|
1446
1725
|
/**
|
|
1447
1726
|
* Query for an array of relations for multiple dtos.
|
|
@@ -1510,6 +1789,12 @@ var RelationQueryService = class {
|
|
|
1510
1789
|
const relationEntity = this.getRelationEntity(relationName);
|
|
1511
1790
|
return RelationClass === relationEntity || RelationClass.name === relationEntity.name;
|
|
1512
1791
|
}
|
|
1792
|
+
getRelationLoadOptions() {
|
|
1793
|
+
return {
|
|
1794
|
+
strategy: this.relationLoadingStrategy,
|
|
1795
|
+
useDataloader: this.nativeLoadUseDataloader
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1513
1798
|
getRelationMeta(relationName) {
|
|
1514
1799
|
const em = this.repo.getEntityManager();
|
|
1515
1800
|
const metadata = em.getMetadata().get(this.repo.getEntityName());
|
|
@@ -1568,7 +1853,9 @@ var MikroOrmQueryService = class extends RelationQueryService {
|
|
|
1568
1853
|
filterQueryBuilder;
|
|
1569
1854
|
useSoftDelete;
|
|
1570
1855
|
constructor(repo, opts) {
|
|
1571
|
-
super(
|
|
1856
|
+
super({
|
|
1857
|
+
relationLoading: opts?.relationLoading
|
|
1858
|
+
}), this.repo = repo;
|
|
1572
1859
|
this.filterQueryBuilder = opts?.filterQueryBuilder ?? new FilterQueryBuilder(this.repo);
|
|
1573
1860
|
this.useSoftDelete = opts?.useSoftDelete ?? false;
|
|
1574
1861
|
const serializer = assembler_serializer.getAssemblerSerializer(this.EntityClass);
|
|
@@ -1589,14 +1876,12 @@ var MikroOrmQueryService = class extends RelationQueryService {
|
|
|
1589
1876
|
return data;
|
|
1590
1877
|
})(this.EntityClass);
|
|
1591
1878
|
nestjsQueryCore.AssemblerDeserializer((d) => {
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
return entity;
|
|
1599
|
-
}
|
|
1879
|
+
const entity = this.repo.getEntityManager().create(this.EntityClass, d, {
|
|
1880
|
+
managed: true,
|
|
1881
|
+
convertCustomTypes: true,
|
|
1882
|
+
partial: true
|
|
1883
|
+
});
|
|
1884
|
+
return entity;
|
|
1600
1885
|
})(this.EntityClass);
|
|
1601
1886
|
}
|
|
1602
1887
|
}
|
|
@@ -2092,12 +2377,12 @@ var MikroOrmQueryService = class extends RelationQueryService {
|
|
|
2092
2377
|
};
|
|
2093
2378
|
|
|
2094
2379
|
// src/lib/providers.ts
|
|
2095
|
-
function createMikroOrmQueryServiceProvider(EntityClass, contextName) {
|
|
2380
|
+
function createMikroOrmQueryServiceProvider(EntityClass, contextName, opts) {
|
|
2096
2381
|
return {
|
|
2097
2382
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2098
2383
|
provide: nestjsQueryCore.getQueryServiceToken(EntityClass),
|
|
2099
2384
|
useFactory(repo) {
|
|
2100
|
-
return new MikroOrmQueryService(repo);
|
|
2385
|
+
return new MikroOrmQueryService(repo, opts);
|
|
2101
2386
|
},
|
|
2102
2387
|
inject: [
|
|
2103
2388
|
nestjs.getRepositoryToken(EntityClass, contextName)
|
|
@@ -2105,15 +2390,17 @@ function createMikroOrmQueryServiceProvider(EntityClass, contextName) {
|
|
|
2105
2390
|
};
|
|
2106
2391
|
}
|
|
2107
2392
|
__name(createMikroOrmQueryServiceProvider, "createMikroOrmQueryServiceProvider");
|
|
2108
|
-
var createMikroOrmQueryServiceProviders = /* @__PURE__ */ __name((entities, contextName) => entities.map((entity) => createMikroOrmQueryServiceProvider(entity, contextName)), "createMikroOrmQueryServiceProviders");
|
|
2393
|
+
var createMikroOrmQueryServiceProviders = /* @__PURE__ */ __name((entities, contextName, opts) => entities.map((entity) => createMikroOrmQueryServiceProvider(entity, contextName, opts)), "createMikroOrmQueryServiceProviders");
|
|
2109
2394
|
|
|
2110
2395
|
// src/lib/nest-query-mikro-orm.module.ts
|
|
2111
2396
|
var NestjsQueryMikroOrmModule = class _NestjsQueryMikroOrmModule {
|
|
2112
2397
|
static {
|
|
2113
2398
|
__name(this, "NestjsQueryMikroOrmModule");
|
|
2114
2399
|
}
|
|
2115
|
-
static forFeature(entities,
|
|
2116
|
-
const
|
|
2400
|
+
static forFeature(entities, contextNameOrOptions) {
|
|
2401
|
+
const contextName = typeof contextNameOrOptions === "string" ? contextNameOrOptions : contextNameOrOptions?.contextName;
|
|
2402
|
+
const queryServiceOpts = typeof contextNameOrOptions === "string" ? void 0 : contextNameOrOptions?.queryServiceOpts;
|
|
2403
|
+
const queryServiceProviders = createMikroOrmQueryServiceProviders(entities, contextName, queryServiceOpts);
|
|
2117
2404
|
const mikroOrmModule = nestjs.MikroOrmModule.forFeature(entities, contextName);
|
|
2118
2405
|
return {
|
|
2119
2406
|
imports: [
|