update.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // ██╗ ██╗██████╗ ██████╗ █████╗ ████████╗███████╗ █████╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
  2. // ██║ ██║██╔══██╗██╔══██╗██╔══██╗╚══██╔══╝██╔════╝ ██╔══██╗██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
  3. // ██║ ██║██████╔╝██║ ██║███████║ ██║ █████╗ ███████║██║ ██║ ██║██║ ██║██╔██╗ ██║
  4. // ██║ ██║██╔═══╝ ██║ ██║██╔══██║ ██║ ██╔══╝ ██╔══██║██║ ██║ ██║██║ ██║██║╚██╗██║
  5. // ╚██████╔╝██║ ██████╔╝██║ ██║ ██║ ███████╗ ██║ ██║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
  6. // ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
  7. //
  8. module.exports = require('machine').build({
  9. friendlyName: 'Update',
  10. description: 'Update record(s) in the database based on a query criteria.',
  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 records were successfully updated.',
  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. notUnique: {
  44. friendlyName: 'Not Unique',
  45. outputType: 'ref'
  46. }
  47. },
  48. fn: function update(inputs, exits) {
  49. // Dependencies
  50. var _ = require('@sailshq/lodash');
  51. var WLUtils = require('waterline-utils');
  52. var Helpers = require('./private');
  53. var Converter = WLUtils.query.converter;
  54. // Store the Query input for easier access
  55. var query = inputs.query;
  56. query.meta = query.meta || {};
  57. // Find the model definition
  58. var model = inputs.models[query.using];
  59. if (!model) {
  60. return exits.invalidDatastore();
  61. }
  62. // Set a flag if a leased connection from outside the adapter was used or not.
  63. var leased = _.has(query.meta, 'leasedConnection');
  64. // Set a flag to determine if records are being returned
  65. var fetchRecords = false;
  66. // Build a faux ORM for use in processEachRecords
  67. var fauxOrm = {
  68. collections: inputs.models
  69. };
  70. // ╔═╗╦═╗╔═╗ ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ┬─┐┌─┐┌─┐┌─┐┬─┐┌┬┐┌─┐
  71. // ╠═╝╠╦╝║╣───╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ├┬┘├┤ │ │ │├┬┘ ││└─┐
  72. // ╩ ╩╚═╚═╝ ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ┴└─└─┘└─┘└─┘┴└──┴┘└─┘
  73. // Process each record to normalize output
  74. try {
  75. Helpers.query.preProcessRecord({
  76. records: [query.valuesToSet],
  77. identity: model.identity,
  78. orm: fauxOrm
  79. });
  80. } catch (e) {
  81. return exits.error(e);
  82. }
  83. // ╔═╗╔═╗╔╗╔╦ ╦╔═╗╦═╗╔╦╗ ┌┬┐┌─┐ ┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┐┌┌┬┐
  84. // ║ ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║ │ │ │ └─┐ │ ├─┤ │ ├┤ │││├┤ │││ │
  85. // ╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩ ┴ └─┘ └─┘ ┴ ┴ ┴ ┴ └─┘┴ ┴└─┘┘└┘ ┴
  86. // Convert the Waterline criteria into a Waterline Query Statement. This
  87. // turns it into something that is declarative and can be easily used to
  88. // build a SQL query.
  89. // See: https://github.com/treelinehq/waterline-query-docs for more info
  90. // on Waterline Query Statements.
  91. var statement;
  92. try {
  93. statement = Converter({
  94. model: query.using,
  95. method: 'update',
  96. criteria: query.criteria,
  97. values: query.valuesToSet
  98. });
  99. } catch (e) {
  100. return exits.error(e);
  101. }
  102. // ╔╦╗╔═╗╔╦╗╔═╗╦═╗╔╦╗╦╔╗╔╔═╗ ┬ ┬┬ ┬┬┌─┐┬ ┬ ┬ ┬┌─┐┬ ┬ ┬┌─┐┌─┐
  103. // ║║║╣ ║ ║╣ ╠╦╝║║║║║║║║╣ │││├─┤││ ├─┤ └┐┌┘├─┤│ │ │├┤ └─┐
  104. // ═╩╝╚═╝ ╩ ╚═╝╩╚═╩ ╩╩╝╚╝╚═╝ └┴┘┴ ┴┴└─┘┴ ┴ └┘ ┴ ┴┴─┘└─┘└─┘└─┘
  105. // ┌┬┐┌─┐ ┬─┐┌─┐┌┬┐┬ ┬┬─┐┌┐┌
  106. // │ │ │ ├┬┘├┤ │ │ │├┬┘│││
  107. // ┴ └─┘ ┴└─└─┘ ┴ └─┘┴└─┘└┘
  108. if (_.has(query.meta, 'fetch') && query.meta.fetch) {
  109. fetchRecords = true;
  110. }
  111. // Find the Primary Key
  112. var primaryKeyField = model.primaryKey;
  113. var primaryKeyColumnName = model.definition[primaryKeyField].columnName;
  114. // ╔═╗╔═╗╔═╗╦ ╦╔╗╔ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
  115. // ╚═╗╠═╝╠═╣║║║║║║ │ │ │││││││├┤ │ │ ││ ││││
  116. // ╚═╝╩ ╩ ╩╚╩╝╝╚╝ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
  117. // ┌─┐┬─┐ ┬ ┬┌─┐┌─┐ ┬ ┌─┐┌─┐┌─┐┌─┐┌┬┐ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
  118. // │ │├┬┘ │ │└─┐├┤ │ ├┤ ├─┤└─┐├┤ ││ │ │ │││││││├┤ │ │ ││ ││││
  119. // └─┘┴└─ └─┘└─┘└─┘ ┴─┘└─┘┴ ┴└─┘└─┘─┴┘ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
  120. // Spawn a new connection for running queries on.
  121. Helpers.connection.spawnOrLeaseConnection(inputs.datastore, query.meta, function spawnConnectionCb(err, connection) {
  122. if (err) {
  123. return exits.badConnection(err);
  124. }
  125. // ╦═╗╦ ╦╔╗╔ ┬ ┬┌─┐┌┬┐┌─┐┌┬┐┌─┐ ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
  126. // ╠╦╝║ ║║║║ │ │├─┘ ││├─┤ │ ├┤ │─┼┐│ │├┤ ├┬┘└┬┘
  127. // ╩╚═╚═╝╝╚╝ └─┘┴ ─┴┘┴ ┴ ┴ └─┘ └─┘└└─┘└─┘┴└─ ┴
  128. Helpers.query.update({
  129. connection: connection,
  130. statement: statement,
  131. fetch: fetchRecords,
  132. primaryKey: primaryKeyColumnName
  133. },
  134. function updateRecordCb(err, updatedRecords) {
  135. // Always release the connection unless a leased connection from outside
  136. // the adapter was used.
  137. Helpers.connection.releaseConnection(connection, leased, function cb() {
  138. // If there was an error return it.
  139. if (err) {
  140. if (err.footprint && err.footprint.identity === 'notUnique') {
  141. return exits.notUnique(err);
  142. }
  143. return exits.error(err);
  144. }
  145. if (fetchRecords) {
  146. // Process each record to normalize output
  147. try {
  148. Helpers.query.processEachRecord({
  149. records: updatedRecords,
  150. identity: model.identity,
  151. orm: fauxOrm
  152. });
  153. } catch (e) {
  154. return exits.error(e);
  155. }
  156. return exits.success({ records: updatedRecords });
  157. }
  158. return exits.success();
  159. }); // </ releaseConnection >
  160. }); // </ runQuery >
  161. }); // </ spawnConnection >
  162. }
  163. });