run-query.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // ██████╗ ██╗ ██╗███╗ ██╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗
  2. // ██╔══██╗██║ ██║████╗ ██║ ██╔═══██╗██║ ██║██╔════╝██╔══██╗╚██╗ ██╔╝
  3. // ██████╔╝██║ ██║██╔██╗ ██║ ██║ ██║██║ ██║█████╗ ██████╔╝ ╚████╔╝
  4. // ██╔══██╗██║ ██║██║╚██╗██║ ██║▄▄ ██║██║ ██║██╔══╝ ██╔══██╗ ╚██╔╝
  5. // ██║ ██║╚██████╔╝██║ ╚████║ ╚██████╔╝╚██████╔╝███████╗██║ ██║ ██║
  6. // ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚══▀▀═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝
  7. //
  8. // Send a Native Query to the datastore and gracefully handle errors.
  9. var _ = require('@sailshq/lodash');
  10. var MySQL = require('machinepack-mysql');
  11. var releaseConnection = require('../connection/release-connection');
  12. module.exports = function runQuery(options, cb) {
  13. // ╦ ╦╔═╗╦ ╦╔╦╗╔═╗╔╦╗╔═╗ ┌─┐┌─┐┌┬┐┬┌─┐┌┐┌┌─┐
  14. // ╚╗╔╝╠═╣║ ║ ║║╠═╣ ║ ║╣ │ │├─┘ │ ││ ││││└─┐
  15. // ╚╝ ╩ ╩╩═╝╩═╩╝╩ ╩ ╩ ╚═╝ └─┘┴ ┴ ┴└─┘┘└┘└─┘
  16. if (_.isUndefined(options) || !_.isPlainObject(options)) {
  17. throw new Error('Invalid options argument. Options must contain: connection, nativeQuery, and leased.');
  18. }
  19. if (!_.has(options, 'connection') || !_.isObject(options.connection)) {
  20. throw new Error('Invalid option used in options argument. Missing or invalid connection.');
  21. }
  22. if (!_.has(options, 'nativeQuery')) {
  23. throw new Error('Invalid option used in options argument. Missing or invalid nativeQuery.');
  24. }
  25. // ╦═╗╦ ╦╔╗╔ ┌┐┌┌─┐┌┬┐┬┬ ┬┌─┐ ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬
  26. // ╠╦╝║ ║║║║ │││├─┤ │ │└┐┌┘├┤ │─┼┐│ │├┤ ├┬┘└┬┘
  27. // ╩╚═╚═╝╝╚╝ ┘└┘┴ ┴ ┴ ┴ └┘ └─┘ └─┘└└─┘└─┘┴└─ ┴
  28. MySQL.sendNativeQuery({
  29. connection: options.connection,
  30. nativeQuery: options.nativeQuery,
  31. valuesToEscape: options.valuesToEscape,
  32. meta: options.meta
  33. })
  34. .switch({
  35. // If there was an error, check if the connection should be
  36. // released back into the pool automatically.
  37. error: function error(err) {
  38. if (!options.disconnectOnError) {
  39. return cb(err);
  40. }
  41. releaseConnection(options.connection, options.leased, function releaseConnectionCb(err) {
  42. return cb(err);
  43. });
  44. },
  45. // If the query failed, try and parse it into a normalized format and
  46. // release the connection if needed.
  47. queryFailed: function queryFailed(report) {
  48. // Parse the native query error into a normalized format
  49. var parsedError;
  50. try {
  51. parsedError = MySQL.parseNativeQueryError({
  52. nativeQueryError: report.error
  53. }).execSync();
  54. } catch (e) {
  55. if (!options.disconnectOnError) {
  56. return cb(e);
  57. }
  58. releaseConnection(options.connection, function releaseConnectionCb() {
  59. return cb(e);
  60. });
  61. return;
  62. }
  63. // If the catch all error was used, return an error instance instead of
  64. // the footprint.
  65. var catchAllError = false;
  66. if (parsedError.footprint.identity === 'catchall') {
  67. catchAllError = true;
  68. }
  69. // If this shouldn't disconnect the connection, just return the normalized
  70. // error with the footprint.
  71. if (!options.disconnectOnError) {
  72. if (catchAllError) {
  73. return cb(report.error);
  74. }
  75. return cb(parsedError);
  76. }
  77. releaseConnection(options.connection, false, function releaseConnectionCb() {
  78. if (catchAllError) {
  79. return cb(report.error);
  80. }
  81. return cb(parsedError);
  82. });
  83. },
  84. success: function success(report) {
  85. // If a custom primary key was used and the record has an `insert` query
  86. // type, build a manual insert report because we don't have the actual
  87. // value that was used.
  88. if (options.customPrimaryKey) {
  89. return cb(null, {
  90. result: {
  91. inserted: options.customPrimaryKey
  92. }
  93. });
  94. }
  95. // ╔═╗╔═╗╦═╗╔═╗╔═╗ ┌─┐ ┬ ┬┌─┐┬─┐┬ ┬ ┬─┐┌─┐┌─┐┬ ┬┬ ┌┬┐┌─┐
  96. // ╠═╝╠═╣╠╦╝╚═╗║╣ │─┼┐│ │├┤ ├┬┘└┬┘ ├┬┘├┤ └─┐│ ││ │ └─┐
  97. // ╩ ╩ ╩╩╚═╚═╝╚═╝ └─┘└└─┘└─┘┴└─ ┴ ┴└─└─┘└─┘└─┘┴─┘┴ └─┘
  98. // If there was a query type given, parse the results.
  99. var queryResults = report.result;
  100. if (options.queryType) {
  101. try {
  102. queryResults = MySQL.parseNativeQueryResult({
  103. queryType: options.queryType,
  104. nativeQueryResult: report.result
  105. }).execSync();
  106. } catch (e) {
  107. return cb(e);
  108. }
  109. }
  110. return cb(null, queryResults);
  111. }
  112. });
  113. };