select.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // ███████╗███████╗██╗ ███████╗ ██████╗████████╗ █████╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
  2. // ██╔════╝██╔════╝██║ ██╔════╝██╔════╝╚══██╔══╝ ██╔══██╗██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
  3. // ███████╗█████╗ ██║ █████╗ ██║ ██║ ███████║██║ ██║ ██║██║ ██║██╔██╗ ██║
  4. // ╚════██║██╔══╝ ██║ ██╔══╝ ██║ ██║ ██╔══██║██║ ██║ ██║██║ ██║██║╚██╗██║
  5. // ███████║███████╗███████╗███████╗╚██████╗ ██║ ██║ ██║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
  6. // ╚══════╝╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
  7. //
  8. module.exports = require('machine').build({
  9. friendlyName: 'Select',
  10. description: 'Find record(s) in the database.',
  11. inputs: {
  12. datastore: {
  13. description: 'The datastore to use for connections.',
  14. extendedDescription: 'Datastores represent the config and manager required to obtain an active database connection.',
  15. required: true,
  16. readOnly: true,
  17. example: '==='
  18. },
  19. models: {
  20. description: 'An object containing all of the model definitions that have been registered.',
  21. required: true,
  22. example: '==='
  23. },
  24. query: {
  25. description: 'A valid stage three Waterline query.',
  26. required: true,
  27. example: '==='
  28. }
  29. },
  30. exits: {
  31. success: {
  32. description: 'The results of the select query.',
  33. outputVariableName: 'records',
  34. outputType: 'ref'
  35. },
  36. invalidDatastore: {
  37. description: 'The datastore used is invalid. It is missing key pieces.'
  38. },
  39. badConnection: {
  40. friendlyName: 'Bad connection',
  41. description: 'A connection either could not be obtained or there was an error using the connection.'
  42. }
  43. },
  44. fn: function select(inputs, exits) {
  45. // Dependencies
  46. var _ = require('@sailshq/lodash');
  47. var WLUtils = require('waterline-utils');
  48. var Converter = WLUtils.query.converter;
  49. var Helpers = require('./private');
  50. // Store the Query input for easier access
  51. var query = inputs.query;
  52. query.meta = query.meta || {};
  53. // Find the model definition
  54. var model = inputs.models[query.using];
  55. if (!model) {
  56. return exits.invalidDatastore();
  57. }
  58. // Set a flag if a leased connection from outside the adapter was used or not.
  59. var leased = _.has(query.meta, 'leasedConnection');
  60. // ╔═╗╔═╗╔╗╔╦ ╦╔═╗╦═╗╔╦╗ ┌┬┐┌─┐ ┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┐┌┌┬┐
  61. // ║ ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║ │ │ │ └─┐ │ ├─┤ │ ├┤ │││├┤ │││ │
  62. // ╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩ ┴ └─┘ └─┘ ┴ ┴ ┴ ┴ └─┘┴ ┴└─┘┘└┘ ┴
  63. // Convert the Waterline criteria into a Waterline Query Statement. This
  64. // turns it into something that is declarative and can be easily used to
  65. // build a SQL query.
  66. // See: https://github.com/treelinehq/waterline-query-docs for more info
  67. // on Waterline Query Statements.
  68. var statement;
  69. try {
  70. statement = Converter({
  71. model: query.using,
  72. method: 'find',
  73. criteria: query.criteria
  74. });
  75. } catch (e) {
  76. return exits.error(e);
  77. }
  78. // Compile the original Waterline Query
  79. var compiledQuery;
  80. try {
  81. compiledQuery = Helpers.query.compileStatement(statement);
  82. } catch (e) {
  83. return exits.error(e);
  84. }
  85. // ╔═╗╔═╗╔═╗╦ ╦╔╗╔ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
  86. // ╚═╗╠═╝╠═╣║║║║║║ │ │ │││││││├┤ │ │ ││ ││││
  87. // ╚═╝╩ ╩ ╩╚╩╝╝╚╝ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
  88. // ┌─┐┬─┐ ┬ ┬┌─┐┌─┐ ┬ ┌─┐┌─┐┌─┐┌─┐┌┬┐ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
  89. // │ │├┬┘ │ │└─┐├┤ │ ├┤ ├─┤└─┐├┤ ││ │ │ │││││││├┤ │ │ ││ ││││
  90. // └─┘┴└─ └─┘└─┘└─┘ ┴─┘└─┘┴ ┴└─┘└─┘─┴┘ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
  91. // Spawn a new connection for running queries on.
  92. Helpers.connection.spawnOrLeaseConnection(inputs.datastore, query.meta, function spawnConnectionCb(err, connection) {
  93. if (err) {
  94. return exits.badConnection(err);
  95. }
  96. // ╦═╗╦ ╦╔╗╔ ┌─┐┌─┐┬ ┌─┐┌─┐┌┬┐ ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
  97. // ╠╦╝║ ║║║║ └─┐├┤ │ ├┤ │ │ │─┼┐│ │├┤ ├┬┘└┬┘
  98. // ╩╚═╚═╝╝╚╝ └─┘└─┘┴─┘└─┘└─┘ ┴ └─┘└└─┘└─┘┴└─ ┴
  99. var queryType = 'select';
  100. Helpers.query.runQuery({
  101. connection: connection,
  102. nativeQuery: compiledQuery.nativeQuery,
  103. valuesToEscape: compiledQuery.valuesToEscape,
  104. meta: compiledQuery.meta,
  105. queryType: queryType,
  106. disconnectOnError: leased ? false : true
  107. },
  108. function runQueryCb(err, report) {
  109. // The runQuery helper will automatically release the connection on error
  110. // if needed.
  111. if (err) {
  112. return exits.error(err);
  113. }
  114. // Always release the connection unless a leased connection from outside
  115. // the adapter was used.
  116. Helpers.connection.releaseConnection(connection, leased, function releaseConnectionCb() {
  117. var selectRecords = report.result;
  118. var orm = {
  119. collections: inputs.models
  120. };
  121. // Process each record to normalize output
  122. try {
  123. Helpers.query.processEachRecord({
  124. records: selectRecords,
  125. identity: model.identity,
  126. orm: orm
  127. });
  128. } catch (e) {
  129. return exits.error(e);
  130. }
  131. return exits.success({ records: selectRecords });
  132. }); // </ releaseConnection >
  133. }); // </ runQuery >
  134. }); // </ spawnConnection >
  135. }
  136. });