From 176b1c262ef30be881031ed4a08ba75198f97ef8 Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Thu, 9 Apr 2020 18:10:53 +0800 Subject: [PATCH] Allow populates to use select/omit for singular associations Currently the populates clause is allowed for plural ("collection") associations but disallowed for singular ("model") associations. This patch allows only a select or an omit for singular associations. --- .../utils/query/forge-stage-two-query.js | 55 +++++++++++++------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/lib/waterline/utils/query/forge-stage-two-query.js b/lib/waterline/utils/query/forge-stage-two-query.js index 6fd6ea1f6..7806acb45 100644 --- a/lib/waterline/utils/query/forge-stage-two-query.js +++ b/lib/waterline/utils/query/forge-stage-two-query.js @@ -862,6 +862,10 @@ module.exports = function forgeStageTwoQuery(query, orm) { // │ ├─┤├┤ │ ├┴┐ │ ├─┤├┤ ╠╦╝╠═╣╚═╗ // └─┘┴ ┴└─┘└─┘┴ ┴ ┴ ┴ ┴└─┘ ╩╚═╩ ╩╚═╝ + // we perform criteria normalization for plural ("collection") associations + // and *SOME* singular ("model") associations (only allowing `select` or `omit`) + var performNormalizeCriteria = false; + // If this is a singular ("model") association, then it should always have // an empty dictionary on the RHS. (For this type of association, there is // always either exactly one associated record, or none of them.) @@ -873,26 +877,34 @@ module.exports = function forgeStageTwoQuery(query, orm) { if (_.isEqual(query.populates[populateAttrName], {})) { query.populates[populateAttrName] = true; } - // Otherwise, this simply must be `true`. Otherwise it's invalid. + // Otherwise, this simply must be `true` or the allowed `select`/`omit` clause. Otherwise it's invalid. else { if (query.populates[populateAttrName] !== true) { - throw buildUsageError( - 'E_INVALID_POPULATES', - 'Could not populate `'+populateAttrName+'`. '+ - 'This is a singular ("model") association, which means it never refers to '+ - 'more than _one_ associated record. So passing in subcriteria (i.e. as '+ - 'the second argument to `.populate()`) is not supported for this association, '+ - 'since it generally wouldn\'t make any sense. But that\'s the trouble-- it '+ - 'looks like some sort of a subcriteria (or something) _was_ provided!\n'+ - '(Note that subcriterias consisting ONLY of `omit` or `select` are a special '+ - 'case that _does_ make sense. This usage will be supported in a future version '+ - 'of Waterline.)\n'+ - '\n'+ - 'Here\'s what was passed in:\n'+ - util.inspect(query.populates[populateAttrName], {depth: 5}), - query.using - ); + + // Allow populate for singular associations to only contain a `select` or + // `omit` clause. + var p = query.populates[populateAttrName]; + if (_.isObject(p) && !_.isArray(p) && _.size(p)===1 && (_.isArray(p.select) || _.isArray(p.omit))) { + // normalization performed below + performNormalizeCriteria = true; + } else { + throw buildUsageError( + 'E_INVALID_POPULATES', + 'Could not populate `'+populateAttrName+'`. '+ + 'This is a singular ("model") association, which means it never refers to '+ + 'more than _one_ associated record. So passing in subcriteria (i.e. as '+ + 'the second argument to `.populate()`) is not supported for this association, '+ + 'since it generally wouldn\'t make any sense. But that\'s the trouble-- it '+ + 'looks like some sort of a subcriteria (or something) _was_ provided!\n'+ + '(Note that subcriterias consisting ONLY of `omit` or `select` are a special '+ + 'case that _does_ make sense and is supported)\n'+ + '\n'+ + 'Here\'s what was passed in:\n'+ + util.inspect(query.populates[populateAttrName], {depth: 5}), + query.using + ); + }//-• }//-• }//>-• @@ -902,6 +914,13 @@ module.exports = function forgeStageTwoQuery(query, orm) { // validate and fully-normalize the provided subcriteria. else { + // normalization performed below + performNormalizeCriteria = true; + + }// + + if(performNormalizeCriteria) { + // For compatibility, interpet a subcriteria of `true` to mean that there // is really no subcriteria at all, and that we should just use the default (`{}`). // > This will be further expanded into a fully-formed criteria dictionary shortly. @@ -1025,7 +1044,7 @@ module.exports = function forgeStageTwoQuery(query, orm) { - }// + }//