BVB Source Codes

waterline Show help-find.js Source code

Return Download waterline: download help-find.js Source code - Download waterline Source code - Type:.js
  1. /**
  2.  * Module dependencies
  3.  */
  4.  
  5. var util = require('util');
  6. var _ = require('@sailshq/lodash');
  7. var async = require('async');
  8. var forgeStageThreeQuery = require('./forge-stage-three-query');
  9. var transformPopulatedChildRecords = require('./transform-populated-child-records');
  10.  
  11. /**
  12.  * helpFind()
  13.  *
  14.  * Given a stage 2 "find" or "findOne" query, build and execute a sequence
  15.  * of generated stage 3 queries (aka "find" operations)-- and then run them.
  16.  * If disparate data sources need to be used, then perform in-memory joins
  17.  * as needed.  Afterwards, transform the normalized result set into an array
  18.  * of records, and (potentially) populate them.
  19.  *
  20.  * > Fun facts:
  21.  * > 鈥 This file is sometimes informally known as the "operations runner".
  22.  * > 鈥 If particlebanana and mikermcneil were trees and you chopped us down,
  23.  * >   the months in 2013-2016 we spent figuring out the original implementation
  24.  * >   of the code in this file & the integrator would be a charred, necrotic
  25.  * >   ring that imparts frostbite when touched.
  26.  * > 鈥 This is used for `.find()` and `.findOne()` queries.
  27.  * > 鈥 It's a key piece of the puzzle when it comes to populating records in a
  28.  * >   cross-datastore/adapter (xD/A) fashion.
  29.  *
  30.  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  31.  *
  32.  * @param  {Ref} WLModel
  33.  *         The live Waterline model.
  34.  *
  35.  * @param  {Dictionary} s2q
  36.  *         Stage two query.
  37.  *
  38.  * @param  {Function} done
  39.  *         @param {Error?} err   [if an error occured]
  40.  *         @param {Array} records
  41.  *
  42.  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  43.  */
  44.  
  45. module.exports = function helpFind(WLModel, s2q, done) {
  46.  
  47.   if (!WLModel) {
  48.     return done(new Error('Consistency violation: Live Waterline model should be provided as the 1st argument'));
  49.   }
  50.   if (!s2q) {
  51.     return done(new Error('Consistency violation: Stage two query (S2Q) should be provided as the 2nd argument'));
  52.   }
  53.   if (!_.isFunction(done)) {
  54.     return done(new Error('Consistency violation: `done` (3rd argument) should be a function'));
  55.   }
  56.  
  57.   // Build an initial stage three query (s3q) from the incoming stage 2 query (s2q).
  58.   var parentQuery = forgeStageThreeQuery({
  59.     stageTwoQuery: s2q,
  60.     identity: WLModel.identity,
  61.     transformer: WLModel._transformer,
  62.     originalModels: WLModel.waterline.collections
  63.   });
  64.  
  65.   // Expose a reference to the entire set of all WL models available
  66.   // in the current ORM instance.
  67.   var collections = WLModel.waterline.collections;
  68.  
  69.   var parentDatastoreName = WLModel.datastore;
  70.  
  71.   // Get a reference to the parent adapter.
  72.   var parentAdapter = WLModel._adapter;
  73.  
  74.   // Now, run whatever queries we need, and merge the results together.
  75.   (function _getPopulatedRecords(proceed){
  76.  
  77.     //  鈹屸敩鈹愨攲鈹€鈹  鈹 鈹攲鈹€鈹  鈹屸攼鈹屸攲鈹€鈹愨攲鈹€鈹愨攲鈹攼  鈹屸攢鈹愨敩 鈹敩鈹屸敩鈹愨攲鈹€鈹
  78.     //   鈹傗攤鈹 鈹  鈹傗攤鈹傗敎鈹   鈹傗攤鈹傗敎鈹 鈹溾敜  鈹傗攤  鈹斺攢鈹愨敎鈹€鈹も攤鈹傗攤鈹 鈹屸敇
  79.     //  鈹€鈹粹敇鈹斺攢鈹  鈹斺敶鈹樷敂鈹€鈹  鈹樷敂鈹樷敂鈹€鈹樷敂鈹€鈹樷攢鈹粹敇  鈹斺攢鈹樷敶 鈹粹敶鈹 鈹 o
  80.     // First, determine if the parent model's adapter can handle all of the joining.
  81.     var doJoinsInParentAdapter = (function () {
  82.       // First of all, there must be joins in the query to make this relevant.
  83.       return (parentQuery.joins && parentQuery.joins.length) &&
  84.       // Second, the adapter must support native joins.
  85.       _.isFunction(WLModel._adapter.join) &&
  86.       // And lastly, all of the child models must be on the same datastore.
  87.       _.all(parentQuery.joins, function(join) {
  88.         // Check the child table in the join (we've already checked the parent table,
  89.         // either in a previous iteration or because it's the main parent).
  90.         return collections[join.childCollectionIdentity].datastore === WLModel.datastore;
  91.       });
  92.     })();
  93.  
  94.     //  鈹屸敩鈹愨攲鈹€鈹  鈹屸攼鈹屸攲鈹€鈹愨攲鈹攼鈹敩  鈹攲鈹€鈹   鈹攲鈹€鈹愨敩鈹屸攼鈹屸攲鈹€鈹
  95.     //   鈹傗攤鈹 鈹  鈹傗攤鈹傗敎鈹€鈹 鈹 鈹傗敂鈹愨攲鈹樷敎鈹    鈹傗攤 鈹傗攤鈹傗攤鈹傗敂鈹€鈹
  96.     //  鈹€鈹粹敇鈹斺攢鈹  鈹樷敂鈹樷敶 鈹 鈹 鈹 鈹斺敇 鈹斺攢鈹  鈹斺敇鈹斺攢鈹樷敶鈹樷敂鈹樷敂鈹€鈹
  97.     // If the adapter can handle all of the joining of records itself, great -- we'll just
  98.     // send it the one stage 3 query, get the populated records back and continue on.
  99.     if (doJoinsInParentAdapter) {
  100.       // Run the stage 3 query and proceed.
  101.       parentAdapter.join(parentDatastoreName, parentQuery, proceed);
  102.     }
  103.  
  104.     //  鈹 鈹攲鈹€鈹  鈹 鈹攲鈹€鈹愨攲鈹€鈹  鈹屸攼鈹屸攲鈹€鈹   鈹攲鈹€鈹愨敩鈹屸攼鈹屸攲鈹€鈹
  105.     //  鈹傗攤鈹傗敎鈹   鈹溾攢鈹も敎鈹€鈹も攲鈹€鈹  鈹傗攤鈹傗攤 鈹   鈹傗攤 鈹傗攤鈹傗攤鈹傗敂鈹€鈹
  106.     //  鈹斺敶鈹樷敂鈹€鈹  鈹 鈹粹敶 鈹粹敂鈹€鈹  鈹樷敂鈹樷敂鈹€鈹  鈹斺敇鈹斺攢鈹樷敶鈹樷敂鈹樷敂鈹€鈹
  107.     // If there are no joins, just run the `find` method on the parent adapter, get the
  108.     // results and proceed.
  109.     else if (!_.isArray(parentQuery.joins) || parentQuery.joins.length === 0) {
  110.       parentAdapter.find(parentDatastoreName, parentQuery, proceed);
  111.     }
  112.  
  113.     //  鈹屸敩鈹愨攲鈹€鈹   鈹攲鈹€鈹愨敩鈹屸攼鈹屸攲鈹€鈹  鈹 鈹敩鈹屸敩鈹愨敩 鈹  鈹屸攢鈹愨敩 鈹敩鈹屸敩鈹
  114.     //   鈹傗攤鈹 鈹   鈹傗攤 鈹傗攤鈹傗攤鈹傗敂鈹€鈹  鈹傗攤鈹傗攤 鈹 鈹溾攢鈹  鈹斺攢鈹愨敎鈹€鈹も攤鈹傗攤鈹
  115.     //  鈹€鈹粹敇鈹斺攢鈹  鈹斺敇鈹斺攢鈹樷敶鈹樷敂鈹樷敂鈹€鈹  鈹斺敶鈹樷敶 鈹 鈹 鈹  鈹斺攢鈹樷敶 鈹粹敶鈹 鈹
  116.     // Otherwise we have some joining to do...
  117.     else {
  118.  
  119.       // First step -- group all of the joins by alias.
  120.       var joinsByAlias = _.groupBy(parentQuery.joins, function(join) { return join.alias; });
  121.  
  122.       // console.log('joinsByAlias', require('util').inspect(joinsByAlias, {depth: null}));
  123.  
  124.       // Example entry in `joinsByAlias`:
  125.       // pets:
  126.       //    [ { parentCollectionIdentity: 'user',
  127.       //        parent: 'user',
  128.       //        parentAlias: 'user__pets',
  129.       //        parentKey: 'id',
  130.       //        childCollectionIdentity: 'pet_owners__user_pets',
  131.       //        child: 'pet_owners__user_pets',
  132.       //        childAlias: 'pet_owners__user_pets__pets',
  133.       //        childKey: 'user_pets',
  134.       //        alias: 'pets',
  135.       //        removeParentKey: false,
  136.       //        model: false,
  137.       //        collection: true,
  138.       //        select: false },
  139.       //      { parentCollectionIdentity: 'pet_owners__user_pets',
  140.       //        parent: 'pet_owners__user_pets',
  141.       //        parentAlias: 'pet_owners__user_pets__pets',
  142.       //        parentKey: 'pet_owners',
  143.       //        childCollectionIdentity: 'pet',
  144.       //        child: 'pet',
  145.       //        childAlias: 'pet__pets',
  146.       //        childKey: 'id',
  147.       //        alias: 'pets',
  148.       //        junctionTable: true,
  149.       //        removeParentKey: false,
  150.       //        model: false,
  151.       //        collection: true,
  152.       //        criteria:
  153.       //         { sort: [ { name: 'DESC' } ],
  154.       //           select: [ 'id', 'name' ],
  155.       //           where: {},
  156.       //           limit: 9007199254740991,
  157.       //           skip: 0 } } ],
  158.  
  159.       // Next, run the parent query and get the initial results. Just to be safe, we'll create a copy
  160.       // of the parent query _without_ the joins array, in case the underlying adapter is sneaky and
  161.       // tries to do joins even in its `find` method.
  162.       var parentQueryWithoutJoins = _.omit(parentQuery, 'joins');
  163.       parentAdapter.find(parentDatastoreName, parentQueryWithoutJoins, function(err, parentResults) {
  164.  
  165.         if (err) {return done(err);}
  166.  
  167.         // Now that we have the parent query results, we'll run each set of joins and integrate.
  168.         async.reduce(_.keys(joinsByAlias), parentResults, function(populatedParentRecords, alias, nextSetOfJoins) {
  169.  
  170.           // Get the set of joins for this alias.
  171.           var aliasJoins = joinsByAlias[alias];
  172.  
  173.           //  鈹屸敩鈹愨攲鈹€鈹愨攲鈹愨攲鈹 鈹  鈹屸敩鈹愨攲鈹€鈹   鈹屸敩鈹愨攲鈹€鈹愨攲鈹愨攲鈹 鈹  鈹屸攢鈹愨敩鈹€鈹  鈹  鈹敩鈹屸攢鈹愨敩  鈹屸攢鈹愨攲鈹€鈹愨攲鈹€鈹
  174.           //  鈹傗攤鈹傗敎鈹€鈹も攤鈹傗攤鈹斺敩鈹樷攢鈹€鈹€鈹 鈹 鈹傗攢鈹€鈹€鈹傗攤鈹傗敎鈹€鈹も攤鈹傗攤鈹斺敩鈹  鈹 鈹傗敎鈹敇  鈹斺攼鈹屸敇鈹傗敎鈹€鈹も攤  鈹溾敜 鈹斺攢鈹愨敂鈹€鈹
  175.           //  鈹 鈹粹敶 鈹粹敇鈹斺敇 鈹    鈹 鈹斺攢鈹   鈹 鈹粹敶 鈹粹敇鈹斺敇 鈹   鈹斺攢鈹樷敶鈹斺攢   鈹斺敇 鈹粹敶 鈹粹敶鈹€鈹樷敂鈹€鈹樷敂鈹€鈹樷敂鈹€鈹
  176.           // If there's two joins in the set, we're using a junction table.
  177.           if (aliasJoins.length === 2) {
  178.  
  179.             // The first query we want to run is from the parent table to the junction table.
  180.             var firstJoin = _.first(_.remove(aliasJoins, function(join) { return join.parentCollectionIdentity === WLModel.identity; }));
  181.  
  182.             // The remaining join is to the child table.
  183.             var secondJoin = aliasJoins[0];
  184.  
  185.             // Start building the query to the junction table.
  186.             var junctionTableQuery = {
  187.               using: firstJoin.child,
  188.               method: 'find',
  189.               criteria: {
  190.                 where: {
  191.                   and: []
  192.                 },
  193.                 skip: 0,
  194.                 limit: Number.MAX_SAFE_INTEGER||9007199254740991,
  195.                 select: [ firstJoin.childKey, secondJoin.parentKey ]
  196.               },
  197.               meta: parentQuery.meta,
  198.             };
  199.  
  200.             // Get a reference to the junction table model.
  201.             var junctionTableModel = collections[firstJoin.childCollectionIdentity];
  202.  
  203.             // Add a "sort" clause to the criteria, using the junction table's primary key.
  204.             var sortClause = {};
  205.             sortClause[junctionTableModel.primaryKey] = 'ASC';
  206.             junctionTableQuery.criteria.sort = [sortClause];
  207.  
  208.             // Grab all of the primary keys found in the parent query, and add them as an `in` clause
  209.             // to the junction table query criteria.
  210.             var junctionTableQueryInClause = {};
  211.             junctionTableQueryInClause[firstJoin.childKey] = {in: _.pluck(parentResults, firstJoin.parentKey)};
  212.             junctionTableQuery.criteria.where.and.push(junctionTableQueryInClause);
  213.  
  214.             // We now have a valid "stage 3" query, so let's run that and get the junction table results.
  215.             // First, figure out what datastore the junction table is on.
  216.             var junctionTableDatastoreName = junctionTableModel.datastore;
  217.             // Next, get the adapter for that datastore.
  218.             var junctionTableAdapter = junctionTableModel._adapter;
  219.             // Finally, run the query on the adapter.
  220.             junctionTableAdapter.find(junctionTableDatastoreName, junctionTableQuery, function(err, junctionTableResults) {
  221.  
  222.               if (err) { return nextSetOfJoins(err); }
  223.  
  224.               // Okay!  We have a set of records from the junction table.
  225.               // For example:
  226.               // [ { user_pets: 1, pet_owners: 1 }, { user_pets: 1, pet_owners: 2 }, { user_pets: 2, pet_owners: 3 } ]
  227.               // Now, for each parent PK in that result set (e.g. each value of `user_pets` above), we'll build
  228.               // and run a query on the child table using all of the associated child pks (e.g. `1` and `2`), applying
  229.               // the skip, limit and sort (if any) provided in the user's `populate` clause.
  230.  
  231.               // Get a reference to the child table model.
  232.               var childTableModel = collections[secondJoin.childCollectionIdentity];
  233.  
  234.               // Figure out what datastore the child table is on.
  235.               var childTableDatastoreName = childTableModel.datastore;
  236.  
  237.               // Get the adapter for that datastore.
  238.               var childTableAdapter = childTableModel._adapter;
  239.  
  240.               // Start a base query object for the child table.  We'll use a copy of this with modified
  241.               // "in" criteria for each query to the child table (one per unique parent ID in the join results).
  242.               var baseChildTableQuery = {
  243.                 using: secondJoin.child,
  244.                 method: 'find',
  245.                 criteria: {
  246.                   where: {
  247.                     and: []
  248.                   }
  249.                 },
  250.                 meta: parentQuery.meta
  251.               };
  252.  
  253.               // If the user added a "where" clause, add it to our "and"
  254.               if (secondJoin.criteria.where && _.keys(secondJoin.criteria.where).length > 0) {
  255.                 // If the "where" clause has an "and" modifier already, just push it onto our "and".
  256.                 if (secondJoin.criteria.where.and) {
  257.                   baseChildTableQuery.criteria.where.and.push(secondJoin.criteria.where.and);
  258.                 }
  259.                 // Otherwise push the whole "where" clause in to the "and" array.
  260.                 // This handles cases like `populate('pets', {name: 'alice'})`
  261.                 baseChildTableQuery.criteria.where.and.push(secondJoin.criteria.where);
  262.               }
  263.  
  264.               // If the user added a skip, limit, sort or select, add it to our criteria.
  265.               if (!_.isUndefined(secondJoin.criteria.skip)) { baseChildTableQuery.criteria.skip = secondJoin.criteria.skip; }
  266.               if (!_.isUndefined(secondJoin.criteria.limit)) { baseChildTableQuery.criteria.limit = secondJoin.criteria.limit; }
  267.               if (!_.isUndefined(secondJoin.criteria.sort)) { baseChildTableQuery.criteria.sort = secondJoin.criteria.sort; }
  268.               if (!_.isUndefined(secondJoin.criteria.select)) { baseChildTableQuery.criteria.select = secondJoin.criteria.select; }
  269.  
  270.               // Get the unique parent primary keys from the junction table result.
  271.               var parentPks = _.uniq(_.pluck(junctionTableResults, firstJoin.childKey));
  272.  
  273.               // Loop over those parent primary keys and do one query to the child table per parent,
  274.               // collecting the results in a dictionary organized by parent PK.
  275.               async.reduce(parentPks, {}, function(memo, parentPk, nextParentPk) {
  276.  
  277.                 var childTableQuery = _.cloneDeep(baseChildTableQuery);
  278.  
  279.                 // Get all the records in the junction table result where the value of the foreign key
  280.                 // to the parent table is equal to the parent table primary key value we're currently looking at.
  281.                 // For example, if parentPK is 2, get records from pet_owners__user_pets where `user_pets` == 2.
  282.                 var junctionTableRecordsForThisParent = _.filter(junctionTableResults, function(record) {
  283.                   return record[firstJoin.childKey] === parentPk;
  284.                 });
  285.  
  286.                 // Get the child table primary keys to look for by plucking the value of the foreign key to
  287.                 // the child table from the filtered record set we just created.
  288.                 var childPks = _.pluck(junctionTableRecordsForThisParent, secondJoin.parentKey);
  289.  
  290.                 // Create an `in` clause for our child table query that looks for just thosr primary keys.
  291.                 var inClause = {};
  292.                 inClause[secondJoin.childKey] = {in: childPks};
  293.                 childTableQuery.criteria.where.and.push(inClause);
  294.  
  295.                 // We now have another valid "stage 3" query, so let's run that and get the child table results.
  296.                 // Finally, run the query on the adapter.
  297.                 childTableAdapter.find(childTableDatastoreName, childTableQuery, function(err, childTableResults) {
  298.  
  299.                   if (err) {return nextParentPk(err);}
  300.  
  301.                   // Add these results to the child table results dictionary, under the current parent's pk.
  302.                   memo[parentPk] = childTableResults;
  303.  
  304.                   // Continue!
  305.                   return nextParentPk(undefined, memo);
  306.  
  307.                 }); // </childTableAdapter.find(...)>
  308.  
  309.  
  310.  
  311.               }, function doneGettingChildRecords(err, childRecordsByParent) {
  312.  
  313.                 if (err) { return nextSetOfJoins(err); }
  314.  
  315.                 // Get the name of the primary key of the parent table.
  316.                 var parentKey = firstJoin.parentKey;
  317.  
  318.                 // Loop through the current populated parent records.
  319.                 _.each(populatedParentRecords, function(parentRecord) {
  320.  
  321.                   // Get the current parent record's primary key value.
  322.                   var parentPk = parentRecord[parentKey];
  323.  
  324.                   // If we have child records for this parent, attach them.
  325.                   parentRecord[alias] = childRecordsByParent[parentPk] || [];
  326.  
  327.                 });
  328.  
  329.                 return nextSetOfJoins(null, populatedParentRecords);
  330.  
  331.               }); // </ doneGettingChildRecords>
  332.  
  333.  
  334.             }); // </ junctionTableAdapter.find(...)>
  335.  
  336.  
  337.  
  338.           } // </ "do multi join", i.e. `if (aliasJoins.length === 2)`>
  339.  
  340.           //  鈹屸敩鈹愨攲鈹€鈹  鈹屸攢鈹愨攲鈹愨攲鈹屸攢鈹  鈹屸攢鈹愨敩鈹€鈹  鈹屸敩鈹愨攲鈹€鈹   鈹屸敩鈹愨攲鈹€鈹愨攲鈹愨攲鈹 鈹  鈹 鈹敩鈹屸敩鈹愨敩 鈹  鈹  鈹敩鈹屸攢鈹
  341.           //   鈹 鈹 鈹  鈹 鈹傗攤鈹傗攤鈹溾敜   鈹 鈹傗敎鈹敇   鈹 鈹 鈹傗攢鈹€鈹€鈹傗攤鈹傗敎鈹€鈹も攤鈹傗攤鈹斺敩鈹  鈹傗攤鈹傗攤 鈹 鈹溾攢鈹  鈹斺攼鈹屸敇鈹傗敎鈹€鈹
  342.           //   鈹 鈹斺攢鈹  鈹斺攢鈹樷敇鈹斺敇鈹斺攢鈹  鈹斺攢鈹樷敶鈹斺攢   鈹 鈹斺攢鈹   鈹 鈹粹敶 鈹粹敇鈹斺敇 鈹   鈹斺敶鈹樷敶 鈹 鈹 鈹   鈹斺敇 鈹粹敶 鈹
  343.           // Otherwise there's one join in the set, so no junction table.
  344.           else if (aliasJoins.length === 1) {
  345.  
  346.             // Get a reference to the single join we're doing.
  347.             var singleJoin = aliasJoins[0];
  348.  
  349.             // Get a reference to the child table model.
  350.             var childTableModel = collections[singleJoin.childCollectionIdentity];
  351.  
  352.             // Figure out what datastore the child table is on.
  353.             var childTableDatastoreName = childTableModel.datastore;
  354.  
  355.             // Get the adapter for that datastore.
  356.             var childTableAdapter = childTableModel._adapter;
  357.  
  358.             // Start a base query object for the child table.  We'll use a copy of this with modifiec
  359.             // "in" criteria for each query to the child table (one per unique parent ID in the join results).
  360.             var baseChildTableQuery = {
  361.               using: singleJoin.child,
  362.               method: 'find',
  363.               criteria: {
  364.                 where: {
  365.                   and: []
  366.                 }
  367.               },
  368.               meta: parentQuery.meta
  369.             };
  370.  
  371.             // If the user added a "where" clause, add it to our "and"
  372.             if (singleJoin.criteria.where && _.keys(singleJoin.criteria.where).length > 0) {
  373.               // If the "where" clause has an "and" modifier already, just push it onto our "and".
  374.               if (singleJoin.criteria.where.and) {
  375.                 baseChildTableQuery.criteria.where.and.push(singleJoin.criteria.where.and);
  376.               }
  377.               // Otherwise push the whole "where" clause in to the "and" array.
  378.               // This handles cases like `populate('pets', {name: 'alice'})`
  379.               baseChildTableQuery.criteria.where.and.push(singleJoin.criteria.where);
  380.             }
  381.  
  382.             // If the user added a skip, limit, sort or select, add it to our criteria.
  383.             if (!_.isUndefined(singleJoin.criteria.skip)) { baseChildTableQuery.criteria.skip = singleJoin.criteria.skip; }
  384.             if (!_.isUndefined(singleJoin.criteria.limit)) { baseChildTableQuery.criteria.limit = singleJoin.criteria.limit; }
  385.             if (!_.isUndefined(singleJoin.criteria.sort)) { baseChildTableQuery.criteria.sort = singleJoin.criteria.sort; }
  386.             if (!_.isUndefined(singleJoin.criteria.select)) { baseChildTableQuery.criteria.select = singleJoin.criteria.select; }
  387.  
  388.             // Loop over those parent primary keys and do one query to the child table per parent,
  389.             // collecting the results in a dictionary organized by parent PK.
  390.             async.map(populatedParentRecords, function(parentRecord, nextParentRecord) {
  391.  
  392.               // Start with a copy of the base query.
  393.               var childTableQuery = _.cloneDeep(baseChildTableQuery);
  394.  
  395.               // Create the query clause that looks for child records that reference this parent record's PK value.
  396.               var pkClause = {};
  397.  
  398.               // Look for child records whose join key value matches the parent record's join key value.
  399.               pkClause[singleJoin.childKey] = parentRecord[singleJoin.parentKey];
  400.               childTableQuery.criteria.where.and.push(pkClause);
  401.  
  402.               // We now have another valid "stage 3" query, so let's run that and get the child table results.
  403.               childTableAdapter.find(childTableDatastoreName, childTableQuery, function(err, childTableResults) {
  404.  
  405.                 if (err) {return nextParentRecord(err);}
  406.  
  407.                 // If this is a to-many join, add the results to the alias on the parent record.
  408.                 if (singleJoin.collection === true) {
  409.                   parentRecord[alias] = childTableResults || [];
  410.                 }
  411.  
  412.                 // If this is a to-one join, add the single result to the join key column
  413.                 // on the parent record.  This will be normalized to an attribute name later,
  414.                 // in `_afterGettingPopulatedRecords()`.
  415.                 else {
  416.                   parentRecord[singleJoin.parentKey] = childTableResults[0] || null;
  417.                 }
  418.  
  419.                 // Continue!
  420.                 return nextParentRecord(undefined, parentRecord);
  421.  
  422.               }); // </childTableAdapter.find(...)>
  423.  
  424.             }, nextSetOfJoins);
  425.  
  426.           } // </ else "do single join" i.e. `if (aliasJoins.length === 1)`>
  427.  
  428.           // If we don't have 1 or 2 joins for the alias, that's a problem.
  429.           else {
  430.             return nextSetOfJoins(new Error('Consistency violation: the alias `' + alias + '` should have either 1 or 2 joins, but instead had ' + aliasJoins.length + '!'));
  431.           }
  432.  
  433.         }, proceed); // </ "async.reduce groups of joins" >
  434.  
  435.       }); // </ parentAdapter.find(...)>
  436.  
  437.     } // </ else do joins with shim>
  438.  
  439.    }) (function _afterGettingPopulatedRecords (err, populatedRecords){
  440.  
  441.     //  鈹屸敩鈹愨敩鈹€鈹愨攲鈹€鈹愨攲鈹愨攲鈹屸攢鈹愨攲鈹€鈹愨攲鈹€鈹愨敩鈹€鈹愨攲鈹攼  鈹屸攢鈹愨攲鈹€鈹愨攲鈹€鈹愨敩 鈹敩  鈹屸攢鈹愨攲鈹攼鈹屸攢鈹愨攲鈹攼  鈹攢鈹愨攲鈹€鈹愨攲鈹€鈹愨攲鈹€鈹愨敩鈹€鈹愨攲鈹攼鈹屸攢鈹
  442.     //   鈹 鈹溾敩鈹樷敎鈹€鈹も攤鈹傗攤鈹斺攢鈹愨敎鈹 鈹 鈹傗敎鈹敇鈹傗攤鈹  鈹溾攢鈹樷攤 鈹傗敎鈹€鈹樷攤 鈹傗攤  鈹溾攢鈹 鈹 鈹溾敜  鈹傗攤  鈹溾敩鈹樷敎鈹 鈹  鈹 鈹傗敎鈹敇 鈹傗攤鈹斺攢鈹
  443.     //   鈹 鈹粹敂鈹€鈹 鈹粹敇鈹斺敇鈹斺攢鈹樷敂  鈹斺攢鈹樷敶鈹斺攢鈹 鈹  鈹  鈹斺攢鈹樷敶  鈹斺攢鈹樷敶鈹€鈹樷敶 鈹 鈹 鈹斺攢鈹樷攢鈹粹敇  鈹粹敂鈹€鈹斺攢鈹樷敂鈹€鈹樷敂鈹€鈹樷敶鈹斺攢鈹€鈹粹敇鈹斺攢鈹
  444.  
  445.     if (err) {return done(err);}
  446.  
  447.     // Transform column names into attribute names for each of the result records
  448.     // before attempting any in-memory join logic on them.
  449.     var transformedRecords = _.map(populatedRecords, function(result) {
  450.       return WLModel._transformer.unserialize(result);
  451.     });
  452.  
  453.     // Transform column names into attribute names for all nested, populated records too.
  454.     var joins = parentQuery.joins ? parentQuery.joins : [];
  455.     if (!_.isArray(joins)) {
  456.       return done(new Error('Consistency violation: `joins` must be an array at this point.  But instead, somehow it is this: ' + util.inspect(joins, {
  457.         depth: 5
  458.       }) + ''));
  459.     }
  460.     var data;
  461.     try {
  462.       data = transformPopulatedChildRecords(joins, transformedRecords, WLModel);
  463.     } catch (e) {
  464.       return done(new Error('Unexpected error transforming populated child records.  ' + e.stack));
  465.     }
  466.  
  467.     // If `data` is invalid (not an array) return early to avoid getting into trouble.
  468.     if (!data || !_.isArray(data)) {
  469.       return done(new Error('Consistency violation: Result from operations runner should be an array, but instead got: ' + util.inspect(data, {
  470.         depth: 5
  471.       }) + ''));
  472.     } //-鈥
  473.  
  474.     return done(undefined, data);
  475.  
  476.   }); // </_afterGettingPopulatedRecords>
  477.  
  478. };
  479.  
downloadhelp-find.js Source code - Download waterline Source code
Related Source Codes/Software:
notepad-plus-plus - Notepad++ official repository h... 2017-01-10
che - Eclipse Che: Next-generation Eclipse IDE. Open sou... 2017-01-10
Gource - oftware version control visualization ... 2017-01-10
FDFullscreenPopGesture - A UINavigationController's category to enable full... 2017-01-10
node-style-guide - A guide for styling your node.js / JavaScript code... 2017-01-09
Workerman - An asynchronous event driven PHP framework for eas... 2017-01-10
structor - An advanced visual editor for React components ... 2017-01-10
golearn - Machine Learning for Go 2017-01-10
poisontap - Exploits locked/password protected computers over ... 2017-01-10
kcptun - A Simple UDP Tunnel Based On KCP 2017-01-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top