detect-children-records.js 5.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. // ██████╗ ███████╗████████╗███████╗ ██████╗████████╗ ██████╗██╗ ██╗██╗██╗ ██████╗ ██████╗ ███████╗███╗ ██╗
  2. // ██╔══██╗██╔════╝╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝ ██╔════╝██║ ██║██║██║ ██╔══██╗██╔══██╗██╔════╝████╗ ██║
  3. // ██║ ██║█████╗ ██║ █████╗ ██║ ██║ ██║ ███████║██║██║ ██║ ██║██████╔╝█████╗ ██╔██╗ ██║
  4. // ██║ ██║██╔══╝ ██║ ██╔══╝ ██║ ██║ ██║ ██╔══██║██║██║ ██║ ██║██╔══██╗██╔══╝ ██║╚██╗██║
  5. // ██████╔╝███████╗ ██║ ███████╗╚██████╗ ██║ ╚██████╗██║ ██║██║███████╗██████╔╝██║ ██║███████╗██║ ╚████║
  6. // ╚═════╝ ╚══════╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝╚══════╝╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝
  7. //
  8. // ██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ██████╗ ███████╗
  9. // ██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔══██╗██╔════╝
  10. // ██████╔╝█████╗ ██║ ██║ ██║██████╔╝██║ ██║███████╗
  11. // ██╔══██╗██╔══╝ ██║ ██║ ██║██╔══██╗██║ ██║╚════██║
  12. // ██║ ██║███████╗╚██████╗╚██████╔╝██║ ██║██████╔╝███████║
  13. // ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝
  14. //
  15. // Given a set of records from a join query, pull out any children records that
  16. // have been added. These are found by checking the namespace used in the SELECT
  17. // statement. For children they are selected using an alias similar to:
  18. //
  19. // SELECT childTable.childColumn as childTable__childColumn
  20. //
  21. // This prevents collisions between column names on the parent and child record.
  22. // It also allows the children to easily be grabbed from the flat record and
  23. // nested. This functions takes a result set from a query that looks like the one
  24. // above and pulls out the children.
  25. //
  26. var util = require('util');
  27. var _ = require('@sailshq/lodash');
  28. module.exports = function detectChildrenRecords(primaryKeyAttr, records) {
  29. // Hold children records from all the records
  30. var children = {};
  31. // Go through each record and pull out any children.
  32. _.each(records, function searchForChildren(record) {
  33. // Build a local cache to use for the children of this record
  34. var cache = {};
  35. // Find the Primary Key of the record
  36. var recordPk = record[primaryKeyAttr];
  37. if (!recordPk) {
  38. throw new Error('Could not find a primary key for a record. Perhaps it wasn\'t selected in the query. The primary key was set to: ' + primaryKeyAttr + ' and the record returned was: ' + util.inspect(record, false, null));
  39. }
  40. // Process each key in the record and build up a child record that can
  41. // then be nested into the parent.
  42. _.forIn(record, function checkForChildren(val, key) {
  43. // Check if the key can be split this on the special alias identifier '__' (two underscores).
  44. var split = key.split('__');
  45. if (split.length < 2) {
  46. return;
  47. }
  48. var alias = _.first(split);
  49. var attribute = _.last(split);
  50. // Make sure the local cache knows about this child (i.e. the populated alias name - pets).
  51. if (!_.has(cache, alias)) {
  52. cache[alias] = {};
  53. }
  54. // Add the child value to the cache
  55. cache[alias][attribute] = val;
  56. // Remove the child attribute from the parent
  57. delete record[key];
  58. });
  59. // Combine the local cache into the children cache which holds values
  60. // for all the records.
  61. _.each(cache, function cacheChild(val, key) {
  62. if (!_.has(children, key)) {
  63. children[key] = [];
  64. }
  65. // Store the local cache on the top level cache
  66. children[key] = children[key].concat(cache[key]);
  67. });
  68. });
  69. return {
  70. parents: _.uniq(records, primaryKeyAttr),
  71. children: children
  72. };
  73. };