expand-criteria.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // ███████╗██╗ ██╗██████╗ █████╗ ███╗ ██╗██████╗
  2. // ██╔════╝╚██╗██╔╝██╔══██╗██╔══██╗████╗ ██║██╔══██╗
  3. // █████╗ ╚███╔╝ ██████╔╝███████║██╔██╗ ██║██║ ██║
  4. // ██╔══╝ ██╔██╗ ██╔═══╝ ██╔══██║██║╚██╗██║██║ ██║
  5. // ███████╗██╔╝ ██╗██║ ██║ ██║██║ ╚████║██████╔╝
  6. // ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝
  7. //
  8. // ██████╗██████╗ ██╗████████╗███████╗██████╗ ██╗ █████╗
  9. // ██╔════╝██╔══██╗██║╚══██╔══╝██╔════╝██╔══██╗██║██╔══██╗
  10. // ██║ ██████╔╝██║ ██║ █████╗ ██████╔╝██║███████║
  11. // ██║ ██╔══██╗██║ ██║ ██╔══╝ ██╔══██╗██║██╔══██║
  12. // ╚██████╗██║ ██║██║ ██║ ███████╗██║ ██║██║██║ ██║
  13. // ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝
  14. //
  15. // When using native joins, the criteria values in the WHERE clause of a
  16. // statement MUST be prepended with the name of the table that contains the
  17. // attribute. Otherwise the query will return an error along the lines of:
  18. //
  19. // column reference "id" is ambiguous
  20. //
  21. // To prevent that, the WHERE criteria is recursively parsed and any column names
  22. // are pre-pendend with the given table name. So for example the following query
  23. // will be converted to something that would be rendered like so:
  24. //
  25. // Model.find({ name: 'foo' })
  26. // .populate('children')
  27. // .exec()
  28. //
  29. // Model.find({ 'model.name': 'foo' })
  30. // .populate('children')
  31. // .exec()
  32. //
  33. var _ = require('@sailshq/lodash');
  34. module.exports = function expandCriteria(originalCriteria, tableName) {
  35. // The following are the reserved keys in the criteria language:
  36. var RESERVED = [
  37. '>',
  38. '>=',
  39. '<',
  40. '<=',
  41. 'in',
  42. 'or',
  43. 'and',
  44. 'not',
  45. 'like',
  46. '!=',
  47. 'nin'
  48. ];
  49. // ╔═╗╔═╗╦═╗╔═╗╔═╗ ┌─┐┬ ┬┌┐┌┌─┐┌┬┐┬┌─┐┌┐┌
  50. // ╠═╝╠═╣╠╦╝╚═╗║╣ ├┤ │ │││││ │ ││ ││││
  51. // ╩ ╩ ╩╩╚═╚═╝╚═╝ └ └─┘┘└┘└─┘ ┴ ┴└─┘┘└┘
  52. // Can be called recursively
  53. var parseCriteria = function parseCriteria(criteria) {
  54. // If the values are an array, go through each one and parse
  55. if (_.isArray(criteria)) {
  56. _.each(criteria, function parseArray(item) {
  57. parseCriteria(item);
  58. });
  59. return;
  60. }
  61. // If the values are a dictionary, loop through the keys and parse them
  62. if (_.isPlainObject(criteria)) {
  63. _.each(criteria, function parseKeys(val, key) {
  64. // Check if the key is a reserved word. If not, expand the value and add
  65. // the tableName.
  66. if (_.indexOf(RESERVED, key) < 0) {
  67. criteria[tableName + '.' + key] = val;
  68. delete criteria[key];
  69. }
  70. // Check if there is any recursion that needs to take place
  71. if (_.isArray(val) || _.isPlainObject(val)) {
  72. parseCriteria(val);
  73. }
  74. });
  75. return;
  76. }
  77. };
  78. // Kick off the recursive parsing
  79. parseCriteria(originalCriteria);
  80. // Return the modified criteria
  81. return originalCriteria;
  82. };