RelationFindOperation.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. const FindOperation = require('../queryBuilder/operations/FindOperation');
  2. const { uniqBy } = require('../utils/objectUtils');
  3. class RelationFindOperation extends FindOperation {
  4. constructor(name, opt) {
  5. super(name, opt);
  6. this.relation = opt.relation;
  7. this.owners = opt.owners;
  8. this.alwaysReturnArray = false;
  9. this.assignResultToOwner = true;
  10. this.relationProperty = opt.relationProperty || this.relation.name;
  11. this.omitProps = [];
  12. }
  13. onBuild(builder) {
  14. let ids = new Array(this.owners.length);
  15. for (let i = 0, l = this.owners.length; i < l; ++i) {
  16. ids[i] = this.relation.ownerProp.getProps(this.owners[i]);
  17. }
  18. this.relation.findQuery(builder, {
  19. ownerIds: uniqBy(ids, join)
  20. });
  21. this.selectMissingJoinColumns(builder);
  22. }
  23. onAfter2(builder, related) {
  24. const isOneToOne = this.relation.isOneToOne();
  25. if (this.assignResultToOwner) {
  26. const owners = this.owners;
  27. const relatedByOwnerId = new Map();
  28. for (let i = 0, l = related.length; i < l; ++i) {
  29. const rel = related[i];
  30. const key = this.relation.relatedProp.propKey(rel);
  31. let arr = relatedByOwnerId.get(key);
  32. if (!arr) {
  33. arr = [];
  34. relatedByOwnerId.set(key, arr);
  35. }
  36. arr.push(rel);
  37. }
  38. for (let i = 0, l = owners.length; i < l; ++i) {
  39. const own = owners[i];
  40. const key = this.relation.ownerProp.propKey(own);
  41. const related = relatedByOwnerId.get(key);
  42. if (isOneToOne) {
  43. own[this.relationProperty] = (related && related[0]) || null;
  44. } else {
  45. own[this.relationProperty] = related || [];
  46. }
  47. }
  48. }
  49. return related;
  50. }
  51. onAfter3(builder, related) {
  52. const isOneToOne = this.relation.isOneToOne();
  53. const intOpt = builder.internalOptions();
  54. if (!intOpt.keepImplicitJoinProps) {
  55. this.omitImplicitJoinProps(related);
  56. }
  57. if (!this.alwaysReturnArray && isOneToOne && related.length <= 1) {
  58. related = related[0] || undefined;
  59. }
  60. return super.onAfter3(builder, related);
  61. }
  62. selectMissingJoinColumns(builder) {
  63. const relatedProp = this.relation.relatedProp;
  64. const addedSelects = [];
  65. for (let c = 0, lc = relatedProp.size; c < lc; ++c) {
  66. const fullCol = relatedProp.fullCol(builder, c);
  67. const prop = relatedProp.props[c];
  68. const col = relatedProp.cols[c];
  69. if (!builder.hasSelectionAs(fullCol, col) && addedSelects.indexOf(fullCol) === -1) {
  70. this.omitProps.push(prop);
  71. addedSelects.push(fullCol);
  72. }
  73. }
  74. if (addedSelects.length) {
  75. builder.select(addedSelects);
  76. }
  77. }
  78. omitImplicitJoinProps(related) {
  79. const relatedModelClass = this.relation.relatedModelClass;
  80. if (!this.omitProps.length || !related) {
  81. return related;
  82. }
  83. if (!Array.isArray(related)) {
  84. return this.omitImplicitJoinPropsFromOne(relatedModelClass, related);
  85. }
  86. if (!related.length) {
  87. return related;
  88. }
  89. for (let i = 0, l = related.length; i < l; ++i) {
  90. this.omitImplicitJoinPropsFromOne(relatedModelClass, related[i]);
  91. }
  92. return related;
  93. }
  94. omitImplicitJoinPropsFromOne(relatedModelClass, model) {
  95. for (let c = 0, lc = this.omitProps.length; c < lc; ++c) {
  96. relatedModelClass.omitImpl(model, this.omitProps[c]);
  97. }
  98. return model;
  99. }
  100. }
  101. function join(arr) {
  102. return arr.join();
  103. }
  104. module.exports = RelationFindOperation;