UNPKG

@goatlab/fluent

Version:

Readable query Interface & API generator for TS and Node

134 lines (133 loc) 5.92 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadRelations = void 0; const js_utils_1 = require("@goatlab/js-utils"); const loadRelations = async ({ data, relations, modelRelations, provider, self, returnPivot }) => { if (!relations) { return data; } const chunkSize = provider === 'typeorm' ? 100 : 10; for (const relation of Object.keys(relations)) { if (!modelRelations[relation]) { throw new Error(`Relationship does not exist: ${relation}. Did you create it in your DB entity?`); } if (!self[relation]) { throw new Error(`Relationship does not exist: ${relation}. Did you create it in your Repository?`); } const relationModel = modelRelations[relation]; const Repository = self[relation](); if (relationModel.isOneToMany) { const ids = new Set(data.map(d => d.id)); const chunks = js_utils_1.Arrays.chunk(Array.from(ids), chunkSize); const promises = []; for (const relatedIds of chunks) { promises.push(Repository.findMany({ where: { [relationModel.inverseSidePropertyPath]: { in: relatedIds } } })); } const relatedResults = js_utils_1.Arrays.collapse(await Promise.all(promises)); const grouped = js_utils_1.Arrays.groupBy(relatedResults, r => r[relationModel.inverseSidePropertyPath]); data.map(d => { if (grouped[d.id]) { d[relationModel.propertyName] = grouped[d.id]; } return d; }); return data; } if (relationModel.isManyToOne) { const ids = js_utils_1.Arrays.deDuplicate(data.map(d => d[relationModel.joinColumns[0].propertyPath])); const chunks = js_utils_1.Arrays.chunk(ids, chunkSize); const promises = []; for (const relatedIds of chunks) { promises.push(Repository.findMany({ where: { id: { in: relatedIds } } })); } const relatedResults = js_utils_1.Arrays.collapse(await Promise.all(promises)); const grouped = js_utils_1.Arrays.groupBy(relatedResults, r => r.id); data.map(d => { if (grouped[d[relationModel.joinColumns[0].propertyPath]]) { d[relationModel.propertyName] = grouped[d[relationModel.joinColumns[0].propertyPath]][0]; } }); return data; } if (relationModel.isManyToMany) { const ids = js_utils_1.Arrays.deDuplicate(data.map(d => d.id)); const chunks = js_utils_1.Arrays.chunk(ids, chunkSize); if (relationModel.joinColumns.length === 0) { return data; } const pivotForeignField = self.modelRelations[relationModel.propertyName].joinColumns[0] .propertyPath; const inverseForeignField = self.modelRelations[relationModel.propertyName].inverseJoinColumns[0] .propertyPath; const pivotRepository = Repository?.relatedQuery.pivot; const calleeKey = Repository?.relatedQuery.key; if (!pivotForeignField || !inverseForeignField || !pivotRepository || !calleeKey) { throw new Error('The Many-to-Many relationship is not properly defined.Please check both your Model and Repository'); } const promises = []; for (const pivotIds of chunks) { const results = await pivotRepository.findMany({ where: { [pivotForeignField]: { in: pivotIds } } }); promises.push(results); } const pivotResults = js_utils_1.Arrays.collapse(await Promise.all(promises)); const uniquePivotIds = pivotResults.map(p => p[inverseForeignField]); const relationChunks = js_utils_1.Arrays.chunk(uniquePivotIds, chunkSize); const relationPromises = []; for (const relatedIds of relationChunks) { const results = await Repository.findMany({ where: { id: { in: relatedIds } } }); relationPromises.push(results); } let relatedResults = js_utils_1.Arrays.collapse(await Promise.all(relationPromises)); relatedResults = relatedResults.map(r => { return { ...r, pivot: pivotResults.find(p => p[inverseForeignField] === r.id) }; }); const groupedPivot = js_utils_1.Arrays.groupBy(pivotResults, r => r[relationModel.joinColumns[0].propertyName]); const groupedRelated = js_utils_1.Arrays.groupBy(relatedResults, r => r.id); data.map(d => { groupedPivot[d.id]?.forEach(gp => { if (!d[calleeKey]) { d[calleeKey] = []; } const mapped = groupedRelated[gp[relationModel.inverseJoinColumns[0].propertyName]]; if (mapped) { d[calleeKey] = [...d[calleeKey], ...mapped]; } }); }); return data; } } return data; }; exports.loadRelations = loadRelations;