create-each.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // ██████╗██████╗ ███████╗ █████╗ ████████╗███████╗ ███████╗ █████╗ ██████╗██╗ ██╗
  2. // ██╔════╝██╔══██╗██╔════╝██╔══██╗╚══██╔══╝██╔════╝ ██╔════╝██╔══██╗██╔════╝██║ ██║
  3. // ██║ ██████╔╝█████╗ ███████║ ██║ █████╗ █████╗ ███████║██║ ███████║
  4. // ██║ ██╔══██╗██╔══╝ ██╔══██║ ██║ ██╔══╝ ██╔══╝ ██╔══██║██║ ██╔══██║
  5. // ╚██████╗██║ ██║███████╗██║ ██║ ██║ ███████╗ ███████╗██║ ██║╚██████╗██║ ██║
  6. // ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
  7. //
  8. // █████╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
  9. // ██╔══██╗██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
  10. // ███████║██║ ██║ ██║██║ ██║██╔██╗ ██║
  11. // ██╔══██║██║ ██║ ██║██║ ██║██║╚██╗██║
  12. // ██║ ██║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
  13. // ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
  14. //
  15. module.exports = require('machine').build({
  16. friendlyName: 'Create Each',
  17. description: 'Insert multiple records into a table in the database.',
  18. inputs: {
  19. datastore: {
  20. description: 'The datastore to use for connections.',
  21. extendedDescription: 'Datastores represent the config and manager required to obtain an active database connection.',
  22. required: true,
  23. readOnly: true,
  24. example: '==='
  25. },
  26. models: {
  27. description: 'An object containing all of the model definitions that have been registered.',
  28. required: true,
  29. example: '==='
  30. },
  31. query: {
  32. description: 'A valid stage three Waterline query.',
  33. required: true,
  34. example: '==='
  35. }
  36. },
  37. exits: {
  38. success: {
  39. description: 'The record was successfully inserted.',
  40. outputVariableName: 'record',
  41. outputExample: '==='
  42. },
  43. invalidDatastore: {
  44. description: 'The datastore used is invalid. It is missing key pieces.'
  45. },
  46. badConnection: {
  47. friendlyName: 'Bad connection',
  48. description: 'A connection either could not be obtained or there was an error using the connection.'
  49. },
  50. notUnique: {
  51. friendlyName: 'Not Unique',
  52. outputExample: '==='
  53. }
  54. },
  55. fn: function create(inputs, exits) {
  56. // Dependencies
  57. var _ = require('@sailshq/lodash');
  58. var utils = require('waterline-utils');
  59. var Helpers = require('./private');
  60. // Store the Query input for easier access
  61. var query = inputs.query;
  62. query.meta = query.meta || {};
  63. // Find the model definition
  64. var model = inputs.models[query.using];
  65. if (!model) {
  66. return exits.invalidDatastore();
  67. }
  68. // Set a flag if a leased connection from outside the adapter was used or not.
  69. var leased = _.has(query.meta, 'leasedConnection');
  70. // Set a flag to determine if records are being returned
  71. var fetchRecords = false;
  72. // Build a faux ORM for use in processEachRecords
  73. var fauxOrm = {
  74. collections: inputs.models
  75. };
  76. // ╔═╗╦═╗╔═╗ ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ┬─┐┌─┐┌─┐┌─┐┬─┐┌┬┐┌─┐
  77. // ╠═╝╠╦╝║╣───╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ├┬┘├┤ │ │ │├┬┘ ││└─┐
  78. // ╩ ╩╚═╚═╝ ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ┴└─└─┘└─┘└─┘┴└──┴┘└─┘
  79. // Process each record to normalize output
  80. try {
  81. Helpers.query.preProcessRecord({
  82. records: query.newRecords,
  83. identity: model.identity,
  84. orm: fauxOrm
  85. });
  86. } catch (e) {
  87. return exits.error(e);
  88. }
  89. // ╔═╗╔═╗╔╗╔╦ ╦╔═╗╦═╗╔╦╗ ┌┬┐┌─┐ ┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┬┐┌─┐┌┐┌┌┬┐
  90. // ║ ║ ║║║║╚╗╔╝║╣ ╠╦╝ ║ │ │ │ └─┐ │ ├─┤ │ ├┤ │││├┤ │││ │
  91. // ╚═╝╚═╝╝╚╝ ╚╝ ╚═╝╩╚═ ╩ ┴ └─┘ └─┘ ┴ ┴ ┴ ┴ └─┘┴ ┴└─┘┘└┘ ┴
  92. // Convert the Waterline criteria into a Waterline Query Statement. This
  93. // turns it into something that is declarative and can be easily used to
  94. // build a SQL query.
  95. // See: https://github.com/treelinehq/waterline-query-docs for more info
  96. // on Waterline Query Statements.
  97. var statement;
  98. try {
  99. statement = utils.query.converter({
  100. model: query.using,
  101. method: 'createEach',
  102. values: query.newRecords
  103. });
  104. } catch (e) {
  105. return exits.error(e);
  106. }
  107. // ╔╦╗╔═╗╔╦╗╔═╗╦═╗╔╦╗╦╔╗╔╔═╗ ┬ ┬┬ ┬┬┌─┐┬ ┬ ┬ ┬┌─┐┬ ┬ ┬┌─┐┌─┐
  108. // ║║║╣ ║ ║╣ ╠╦╝║║║║║║║║╣ │││├─┤││ ├─┤ └┐┌┘├─┤│ │ │├┤ └─┐
  109. // ═╩╝╚═╝ ╩ ╚═╝╩╚═╩ ╩╩╝╚╝╚═╝ └┴┘┴ ┴┴└─┘┴ ┴ └┘ ┴ ┴┴─┘└─┘└─┘└─┘
  110. // ┌┬┐┌─┐ ┬─┐┌─┐┌┬┐┬ ┬┬─┐┌┐┌
  111. // │ │ │ ├┬┘├┤ │ │ │├┬┘│││
  112. // ┴ └─┘ ┴└─└─┘ ┴ └─┘┴└─┘└┘
  113. if (_.has(query.meta, 'fetch') && query.meta.fetch) {
  114. fetchRecords = true;
  115. }
  116. // Find the Primary Key
  117. var primaryKeyField = model.primaryKey;
  118. var primaryKeyColumnName = model.definition[primaryKeyField].columnName;
  119. // Remove primary key if the value is NULL
  120. _.each(statement.insert, function removeNullPrimaryKey(record) {
  121. if (_.isNull(record[primaryKeyColumnName])) {
  122. delete record[primaryKeyColumnName];
  123. }
  124. });
  125. // ╔═╗╔═╗╔═╗╦ ╦╔╗╔ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
  126. // ╚═╗╠═╝╠═╣║║║║║║ │ │ │││││││├┤ │ │ ││ ││││
  127. // ╚═╝╩ ╩ ╩╚╩╝╝╚╝ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
  128. // ┌─┐┬─┐ ┬ ┬┌─┐┌─┐ ┬ ┌─┐┌─┐┌─┐┌─┐┌┬┐ ┌─┐┌─┐┌┐┌┌┐┌┌─┐┌─┐┌┬┐┬┌─┐┌┐┌
  129. // │ │├┬┘ │ │└─┐├┤ │ ├┤ ├─┤└─┐├┤ ││ │ │ │││││││├┤ │ │ ││ ││││
  130. // └─┘┴└─ └─┘└─┘└─┘ ┴─┘└─┘┴ ┴└─┘└─┘─┴┘ └─┘└─┘┘└┘┘└┘└─┘└─┘ ┴ ┴└─┘┘└┘
  131. // Spawn a new connection for running queries on.
  132. Helpers.connection.spawnOrLeaseConnection(inputs.datastore, query.meta, function spawnOrLeaseConnectionCb(err, connection) {
  133. if (err) {
  134. return exits.badConnection(err);
  135. }
  136. // ╔═╗╦═╗╔═╗╔═╗╔╦╗╔═╗ ┌─┐┌─┐┌─┐┬ ┬
  137. // ║ ╠╦╝║╣ ╠═╣ ║ ║╣ ├┤ ├─┤│ ├─┤
  138. // ╚═╝╩╚═╚═╝╩ ╩ ╩ ╚═╝ └─┘┴ ┴└─┘┴ ┴
  139. // Run the Create Each util
  140. Helpers.query.createEach({
  141. connection: connection,
  142. statement: statement,
  143. fetch: fetchRecords,
  144. primaryKey: primaryKeyColumnName
  145. },
  146. function createEachCb(err, insertedRecords) {
  147. // Release the connection if needed.
  148. Helpers.connection.releaseConnection(connection, leased, function releaseCb() {
  149. // If there was an error return it.
  150. if (err) {
  151. if (err.footprint && err.footprint.identity === 'notUnique') {
  152. return exits.notUnique(err);
  153. }
  154. return exits.error(err);
  155. }
  156. if (fetchRecords) {
  157. // Process each record to normalize output
  158. try {
  159. Helpers.query.processEachRecord({
  160. records: insertedRecords,
  161. identity: model.identity,
  162. orm: fauxOrm
  163. });
  164. } catch (e) {
  165. return exits.error(e);
  166. }
  167. return exits.success({ records: insertedRecords });
  168. }
  169. return exits.success();
  170. }); // </ .releaseConnection(); >
  171. }); // </ .insertRecord(); >
  172. }); // </ .spawnOrLeaseConnection(); >
  173. }
  174. });