references-many-resolver.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import {Service} from '../service/index.js';
  2. import {cloneDeep} from '../utils/index.js';
  3. import {singularize} from '../utils/index.js';
  4. import {InvalidArgumentError} from '../errors/index.js';
  5. import {RepositoryRegistry} from '../repository/index.js';
  6. import {ModelDefinitionUtils} from '../definition/index.js';
  7. /**
  8. * References many resolver.
  9. */
  10. export class ReferencesManyResolver extends Service {
  11. /**
  12. * Include to.
  13. *
  14. * @param {Record<string, unknown>[]} entities
  15. * @param {string} sourceName
  16. * @param {string} targetName
  17. * @param {string} relationName
  18. * @param {string|undefined} foreignKey
  19. * @param {Record<string, unknown>|undefined} scope
  20. * @return {Promise<void>}
  21. */
  22. async includeTo(
  23. entities,
  24. sourceName,
  25. targetName,
  26. relationName,
  27. foreignKey = undefined,
  28. scope = undefined,
  29. ) {
  30. if (!entities || !Array.isArray(entities))
  31. throw new InvalidArgumentError(
  32. 'The parameter "entities" of ReferencesManyResolver.includeTo requires ' +
  33. 'an Array of Object, but %s given.',
  34. entities,
  35. );
  36. if (!sourceName || typeof sourceName !== 'string')
  37. throw new InvalidArgumentError(
  38. 'The parameter "sourceName" of ReferencesManyResolver.includeTo requires ' +
  39. 'a non-empty String, but %s given.',
  40. sourceName,
  41. );
  42. if (!targetName || typeof targetName !== 'string')
  43. throw new InvalidArgumentError(
  44. 'The parameter "targetName" of ReferencesManyResolver.includeTo requires ' +
  45. 'a non-empty String, but %s given.',
  46. targetName,
  47. );
  48. if (!relationName || typeof relationName !== 'string')
  49. throw new InvalidArgumentError(
  50. 'The parameter "relationName" of ReferencesManyResolver.includeTo requires ' +
  51. 'a non-empty String, but %s given.',
  52. relationName,
  53. );
  54. if (foreignKey && typeof foreignKey !== 'string')
  55. throw new InvalidArgumentError(
  56. 'The provided parameter "foreignKey" of ReferencesManyResolver.includeTo ' +
  57. 'should be a String, but %s given.',
  58. foreignKey,
  59. );
  60. if (scope && (typeof scope !== 'object' || Array.isArray(scope)))
  61. throw new InvalidArgumentError(
  62. 'The provided parameter "scope" of ReferencesManyResolver.includeTo ' +
  63. 'should be an Object, but %s given.',
  64. scope,
  65. );
  66. if (foreignKey == null) {
  67. const singularRelationName = singularize(relationName);
  68. foreignKey = `${singularRelationName}Ids`;
  69. }
  70. const targetIds = entities.reduce((acc, entity) => {
  71. if (!entity || typeof entity !== 'object' || Array.isArray(entity))
  72. throw new InvalidArgumentError(
  73. 'The parameter "entities" of ReferencesManyResolver.includeTo requires ' +
  74. 'an Array of Object, but %s given.',
  75. entity,
  76. );
  77. const ids = entity[foreignKey];
  78. if (Array.isArray(ids))
  79. ids.forEach(id => {
  80. if (id == null || acc.includes(id)) return;
  81. acc.push(id);
  82. });
  83. return acc;
  84. }, []);
  85. const targetRepository =
  86. this.get(RepositoryRegistry).getRepository(targetName);
  87. const targetPkPropName =
  88. this.get(ModelDefinitionUtils).getPrimaryKeyAsPropertyName(targetName);
  89. scope = scope ? cloneDeep(scope) : {};
  90. const filter = cloneDeep(scope);
  91. filter.where = {
  92. and: [
  93. {[targetPkPropName]: {inq: targetIds}},
  94. ...(scope.where ? [scope.where] : []),
  95. ],
  96. };
  97. const targets = await targetRepository.find(filter);
  98. entities.forEach(entity => {
  99. const ids = entity[foreignKey];
  100. entity[relationName] = [];
  101. if (Array.isArray(ids))
  102. targets.forEach(target => {
  103. const targetId = target[targetPkPropName];
  104. if (ids.includes(targetId)) entity[relationName].push(target);
  105. });
  106. });
  107. }
  108. }