query-result-error.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * Copyright (c) 2015-present, Vitaly Tomilov
  3. *
  4. * See the LICENSE file at the top-level directory of this distribution
  5. * for licensing information.
  6. *
  7. * Removal or modification of this copyright notice is prohibited.
  8. */
  9. const npm = {
  10. os: require('os'),
  11. utils: require('../utils'),
  12. text: require('../text')
  13. };
  14. /**
  15. * @enum {number}
  16. * @alias errors.queryResultErrorCode
  17. * @readonly
  18. * @description
  19. * `queryResultErrorCode` enumerator, available from the {@link errors} namespace.
  20. *
  21. * Represents an integer code for each type of error supported by type {@link errors.QueryResultError}.
  22. *
  23. * @see {@link errors.QueryResultError}
  24. */
  25. const queryResultErrorCode = {
  26. /** No data returned from the query. */
  27. noData: 0,
  28. /** No return data was expected. */
  29. notEmpty: 1,
  30. /** Multiple rows were not expected. */
  31. multiple: 2
  32. };
  33. const errorMessages = [
  34. {name: 'noData', message: npm.text.noData},
  35. {name: 'notEmpty', message: npm.text.notEmpty},
  36. {name: 'multiple', message: npm.text.multiple}
  37. ];
  38. /**
  39. * @class errors.QueryResultError
  40. * @augments external:Error
  41. * @description
  42. *
  43. * This error is specified as the rejection reason for all result-specific methods when the result doesn't match
  44. * the expectation, i.e. when a query result doesn't match its Query Result Mask - the value of {@link queryResult}.
  45. *
  46. * The error applies to the result from the following methods: {@link Database#none none},
  47. * {@link Database#one one}, {@link Database#oneOrNone oneOrNone} and {@link Database#many many}.
  48. *
  49. * Supported errors:
  50. *
  51. * - `No return data was expected.`, method {@link Database#none none}
  52. * - `No data returned from the query.`, methods {@link Database#one one} and {@link Database#many many}
  53. * - `Multiple rows were not expected.`, methods {@link Database#one one} and {@link Database#oneOrNone oneOrNone}
  54. *
  55. * Like any other error, this one is notified with through the global event {@link event:error error}.
  56. *
  57. * The type is available from the {@link errors} namespace.
  58. *
  59. * @property {string} name
  60. * Standard {@link external:Error Error} property - error type name = `QueryResultError`.
  61. *
  62. * @property {string} message
  63. * Standard {@link external:Error Error} property - the error message.
  64. *
  65. * @property {string} stack
  66. * Standard {@link external:Error Error} property - the stack trace.
  67. *
  68. * @property {object} result
  69. * The original $[Result] object that was received.
  70. *
  71. * @property {number} received
  72. * Total number of rows received. It is simply the value of `result.rows.length`.
  73. *
  74. * @property {number} code
  75. * Error code - {@link errors.queryResultErrorCode queryResultErrorCode} value.
  76. *
  77. * @property {string} query
  78. * Query that was executed.
  79. *
  80. * Normally, it is the query already formatted with values, if there were any.
  81. * But if you are using initialization option `pgFormatting`, then the query string is before formatting.
  82. *
  83. * @property {*} values
  84. * Values passed in as query parameters. Available only when initialization option `pgFormatting` is used.
  85. * Otherwise, the values are within the pre-formatted `query` string.
  86. *
  87. * @example
  88. *
  89. * const QueryResultError = pgp.errors.QueryResultError;
  90. * const qrec = pgp.errors.queryResultErrorCode;
  91. *
  92. * const initOptions = {
  93. *
  94. * // pg-promise initialization options...
  95. *
  96. * error(err, e) {
  97. * if (err instanceof QueryResultError) {
  98. * // A query returned unexpected number of records, and thus rejected;
  99. *
  100. * // we can check the error code, if we want specifics:
  101. * if(err.code === qrec.noData) {
  102. * // expected some data, but received none;
  103. * }
  104. *
  105. * // If you write QueryResultError into the console,
  106. * // you will get a nicely formatted output.
  107. *
  108. * console.log(err);
  109. *
  110. * // See also: err, e.query, e.params, etc.
  111. * }
  112. * }
  113. * };
  114. *
  115. * @see
  116. * {@link queryResult}, {@link Database#none none}, {@link Database#one one},
  117. * {@link Database#oneOrNone oneOrNone}, {@link Database#many many}
  118. *
  119. */
  120. class QueryResultError extends Error {
  121. constructor(code, result, query, values) {
  122. const message = errorMessages[code].message;
  123. super(message);
  124. this.name = this.constructor.name;
  125. this.code = code;
  126. this.result = result;
  127. this.query = query;
  128. this.values = values;
  129. this.received = result.rows.length;
  130. Error.captureStackTrace(this, this.constructor);
  131. }
  132. }
  133. /**
  134. * @method errors.QueryResultError#toString
  135. * @description
  136. * Creates a well-formatted multi-line string that represents the error.
  137. *
  138. * It is called automatically when writing the object into the console.
  139. *
  140. * @param {number} [level=0]
  141. * Nested output level, to provide visual offset.
  142. *
  143. * @returns {string}
  144. */
  145. QueryResultError.prototype.toString = function (level) {
  146. level = level > 0 ? parseInt(level) : 0;
  147. const gap0 = npm.utils.messageGap(level),
  148. gap1 = npm.utils.messageGap(level + 1),
  149. lines = [
  150. 'QueryResultError {',
  151. gap1 + 'code: queryResultErrorCode.' + errorMessages[this.code].name,
  152. gap1 + 'message: "' + this.message + '"',
  153. gap1 + 'received: ' + this.received,
  154. gap1 + 'query: ' + (typeof this.query === 'string' ? '"' + this.query + '"' : npm.utils.toJson(this.query))
  155. ];
  156. if (this.values !== undefined) {
  157. lines.push(gap1 + 'values: ' + npm.utils.toJson(this.values));
  158. }
  159. lines.push(gap0 + '}');
  160. return lines.join(npm.os.EOL);
  161. };
  162. npm.utils.addInspection(QueryResultError, function () {
  163. return this.toString();
  164. });
  165. module.exports = {
  166. QueryResultError,
  167. queryResultErrorCode
  168. };