parse-native-query-error.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Dependencies
  2. var _ = require('@sailshq/lodash');
  3. module.exports = {
  4. friendlyName: 'Parse native query error',
  5. description: 'Attempt to identify and parse a raw error from sending a native query and normalize it to a standard error footprint.',
  6. moreInfoUrl: 'https://github.com/node-machine/waterline-driver-interface#footprints',
  7. sideEffects: 'cacheable',
  8. sync: true,
  9. inputs: {
  10. nativeQueryError: {
  11. description: 'The error sent back from the database as a result of a failed native query.',
  12. extendedDescription: 'This is referring to the raw error; i.e. the `error` property of the dictionary returned through the `queryFailed` exit of `sendNativeQuery()` in this driver.',
  13. required: true,
  14. example: '==='
  15. },
  16. meta: {
  17. friendlyName: 'Meta (custom)',
  18. description: 'Additional stuff to pass to the driver.',
  19. extendedDescription: 'This is reserved for custom driver-specific extensions. Please refer to the documentation for the driver you are using for more specific information.',
  20. example: '==='
  21. }
  22. },
  23. exits: {
  24. success: {
  25. description: 'The normalization is complete. If the error cannot be normalized into any other more specific footprint, then the catchall footprint will be returned.',
  26. moreInfoUrl: 'https://github.com/node-machine/waterline-driver-interface#footprints',
  27. outputVariableName: 'report',
  28. outputDescription: 'The `footprint` property is the normalized "footprint" representing the provided raw error. Conforms to one of a handful of standardized footprint types expected by the Waterline driver interface. The `meta` property is reserved for custom driver-specific extensions.',
  29. outputExample: '==='
  30. // example: {
  31. // footprint: {},
  32. // meta: '==='
  33. // }
  34. },
  35. },
  36. fn: function parseNativeQueryError(inputs, exits) {
  37. // Quick reference of hand-tested errors:
  38. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  39. // `code` : 'ER_PARSE_ERROR'
  40. // `errno` : 1064
  41. // `sqlState` : '42000'
  42. // `index` : 0
  43. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  44. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  45. // `code` : 'ER_NO_SUCH_TABLE'
  46. // `errno` : 1146
  47. // `sqlState` : '42S02'
  48. // `index` : 0
  49. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  50. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  51. // `code` : 'ER_DUP_ENTRY'
  52. // `errno` : 1062
  53. // `sqlState` : '23000'
  54. // `index` : 0
  55. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  56. // Local variable (`err`) for convenience.
  57. var err = inputs.nativeQueryError;
  58. // `footprint` is primarily what will be returned by this machine.
  59. // For miscellaneous errors which are not explicitly in the
  60. // spec, return the catchall footprint. Drivers should not
  61. // add their own additional footprints-- instead, if they want
  62. // to allow for easily identifying a particular error, the
  63. // `catchall` footprint should still be used; but additional
  64. // information sent back in `meta`.
  65. var footprint = { identity: 'catchall' };
  66. // If the incoming native query error is not an object, or it is
  67. // missing a `code` property, then we'll go ahead and bail out w/
  68. // the "catchall" footprint to avoid continually doing these basic
  69. // checks in the more detailed error negotiation below.
  70. if (!_.isObject(err) || !err.code) {
  71. return exits.success({
  72. footprint: footprint,
  73. meta: inputs.meta
  74. });
  75. }
  76. //
  77. // Otherwise, continue inspecting the native query error in more detail.
  78. //
  79. // > Note that the conditional blocks below are **disjoint**--
  80. // > that is, only one of them should be run.
  81. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  82. // `code` : 'ER_DUP_ENTRY'
  83. // `errno` : 1062
  84. // `sqlState` : '23000'
  85. // `index` : 0
  86. //
  87. // -- Recognized as the `notUnique` footprint from the
  88. // Waterline driver spec. If additional information
  89. // is needed in userland beyond what is guaranteed in
  90. // the spec, then you should take advantage of `meta`.
  91. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  92. if (err.code === 'ER_DUP_ENTRY') {
  93. // Negotiate `notUnique` error footprint.
  94. footprint = {
  95. identity: 'notUnique',
  96. keys: []
  97. };
  98. // Now build our footprint's `keys` property by manually parsing
  99. // the MySQL error message and extracting the relevant bits.
  100. // (See also: https://github.com/balderdashy/sails-mysql/blob/2c414f1191c3595df2cea8e40259811eb3ca05f9/lib/adapter.js#L1223)
  101. if (_.isString(err.message)) {
  102. var matches = err.message.match(/Duplicate entry '.*' for key '(.*?)'$/);
  103. if (matches && matches.length > 0) {
  104. footprint.keys.push(matches[1]);
  105. }
  106. }
  107. }
  108. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  109. // `code` : 'ER_NO_SUCH_TABLE'
  110. // `errno` : 1146
  111. // `sqlState` : '42S02'
  112. // `index` : 0
  113. //
  114. // -- Not in specification yet; just listed here for
  115. // reference. If this driver wants to move ahead of
  116. // the core Waterline/machine spec, this can be handled
  117. // using the `catchall` footprint + `meta`.
  118. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  119. // else if ( ... ){
  120. // footprint = { identity: 'catchall' };
  121. // // e.g.
  122. // meta = { problem: 'noSuchTable', foo: ..., bar: ... };
  123. // }
  124. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  125. // `code` : 'ER_PARSE_ERROR'
  126. // `errno` : 1064
  127. // `sqlState` : '42000'
  128. // `index` : 0
  129. //
  130. // -- Not in specification yet; just listed here for
  131. // reference. If this driver wants to move ahead of
  132. // the core Waterline/machine spec, this can be handled
  133. // using the `catchall` footprint + `meta`.
  134. // --o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-<>
  135. // else if ( ... ){
  136. // footprint = { identity: 'catchall' };
  137. // // e.g.
  138. // meta = { problem: 'couldNotParse', foo: ..., bar: ... };
  139. // }
  140. // Finally, return the normalized footprint.
  141. //
  142. // (as well as any additional metadata that was stuffed
  143. // into `meta` above)
  144. return exits.success({
  145. footprint: footprint,
  146. meta: inputs.meta
  147. });
  148. }
  149. };