sqlite3.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. const path = require('path');
  2. const sqlite3 = require('./sqlite3-binding.js');
  3. const EventEmitter = require('events').EventEmitter;
  4. module.exports = exports = sqlite3;
  5. function normalizeMethod (fn) {
  6. return function (sql) {
  7. let errBack;
  8. const args = Array.prototype.slice.call(arguments, 1);
  9. if (typeof args[args.length - 1] === 'function') {
  10. const callback = args[args.length - 1];
  11. errBack = function(err) {
  12. if (err) {
  13. callback(err);
  14. }
  15. };
  16. }
  17. const statement = new Statement(this, sql, errBack);
  18. return fn.call(this, statement, args);
  19. };
  20. }
  21. function inherits(target, source) {
  22. for (const k in source.prototype)
  23. target.prototype[k] = source.prototype[k];
  24. }
  25. sqlite3.cached = {
  26. Database: function(file, a, b) {
  27. if (file === '' || file === ':memory:') {
  28. // Don't cache special databases.
  29. return new Database(file, a, b);
  30. }
  31. let db;
  32. file = path.resolve(file);
  33. if (!sqlite3.cached.objects[file]) {
  34. db = sqlite3.cached.objects[file] = new Database(file, a, b);
  35. }
  36. else {
  37. // Make sure the callback is called.
  38. db = sqlite3.cached.objects[file];
  39. const callback = (typeof a === 'number') ? b : a;
  40. if (typeof callback === 'function') {
  41. function cb() { callback.call(db, null); }
  42. if (db.open) process.nextTick(cb);
  43. else db.once('open', cb);
  44. }
  45. }
  46. return db;
  47. },
  48. objects: {}
  49. };
  50. const Database = sqlite3.Database;
  51. const Statement = sqlite3.Statement;
  52. const Backup = sqlite3.Backup;
  53. inherits(Database, EventEmitter);
  54. inherits(Statement, EventEmitter);
  55. inherits(Backup, EventEmitter);
  56. // Database#prepare(sql, [bind1, bind2, ...], [callback])
  57. Database.prototype.prepare = normalizeMethod(function(statement, params) {
  58. return params.length
  59. ? statement.bind.apply(statement, params)
  60. : statement;
  61. });
  62. // Database#run(sql, [bind1, bind2, ...], [callback])
  63. Database.prototype.run = normalizeMethod(function(statement, params) {
  64. statement.run.apply(statement, params).finalize();
  65. return this;
  66. });
  67. // Database#get(sql, [bind1, bind2, ...], [callback])
  68. Database.prototype.get = normalizeMethod(function(statement, params) {
  69. statement.get.apply(statement, params).finalize();
  70. return this;
  71. });
  72. // Database#all(sql, [bind1, bind2, ...], [callback])
  73. Database.prototype.all = normalizeMethod(function(statement, params) {
  74. statement.all.apply(statement, params).finalize();
  75. return this;
  76. });
  77. // Database#each(sql, [bind1, bind2, ...], [callback], [complete])
  78. Database.prototype.each = normalizeMethod(function(statement, params) {
  79. statement.each.apply(statement, params).finalize();
  80. return this;
  81. });
  82. Database.prototype.map = normalizeMethod(function(statement, params) {
  83. statement.map.apply(statement, params).finalize();
  84. return this;
  85. });
  86. // Database#backup(filename, [callback])
  87. // Database#backup(filename, destName, sourceName, filenameIsDest, [callback])
  88. Database.prototype.backup = function() {
  89. let backup;
  90. if (arguments.length <= 2) {
  91. // By default, we write the main database out to the main database of the named file.
  92. // This is the most likely use of the backup api.
  93. backup = new Backup(this, arguments[0], 'main', 'main', true, arguments[1]);
  94. } else {
  95. // Otherwise, give the user full control over the sqlite3_backup_init arguments.
  96. backup = new Backup(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
  97. }
  98. // Per the sqlite docs, exclude the following errors as non-fatal by default.
  99. backup.retryErrors = [sqlite3.BUSY, sqlite3.LOCKED];
  100. return backup;
  101. };
  102. Statement.prototype.map = function() {
  103. const params = Array.prototype.slice.call(arguments);
  104. const callback = params.pop();
  105. params.push(function(err, rows) {
  106. if (err) return callback(err);
  107. const result = {};
  108. if (rows.length) {
  109. const keys = Object.keys(rows[0]);
  110. const key = keys[0];
  111. if (keys.length > 2) {
  112. // Value is an object
  113. for (let i = 0; i < rows.length; i++) {
  114. result[rows[i][key]] = rows[i];
  115. }
  116. } else {
  117. const value = keys[1];
  118. // Value is a plain value
  119. for (let i = 0; i < rows.length; i++) {
  120. result[rows[i][key]] = rows[i][value];
  121. }
  122. }
  123. }
  124. callback(err, result);
  125. });
  126. return this.all.apply(this, params);
  127. };
  128. let isVerbose = false;
  129. const supportedEvents = [ 'trace', 'profile', 'change' ];
  130. Database.prototype.addListener = Database.prototype.on = function(type) {
  131. const val = EventEmitter.prototype.addListener.apply(this, arguments);
  132. if (supportedEvents.indexOf(type) >= 0) {
  133. this.configure(type, true);
  134. }
  135. return val;
  136. };
  137. Database.prototype.removeListener = function(type) {
  138. const val = EventEmitter.prototype.removeListener.apply(this, arguments);
  139. if (supportedEvents.indexOf(type) >= 0 && !this._events[type]) {
  140. this.configure(type, false);
  141. }
  142. return val;
  143. };
  144. Database.prototype.removeAllListeners = function(type) {
  145. const val = EventEmitter.prototype.removeAllListeners.apply(this, arguments);
  146. if (supportedEvents.indexOf(type) >= 0) {
  147. this.configure(type, false);
  148. }
  149. return val;
  150. };
  151. // Save the stack trace over EIO callbacks.
  152. sqlite3.verbose = function() {
  153. if (!isVerbose) {
  154. const trace = require('./trace');
  155. [
  156. 'prepare',
  157. 'get',
  158. 'run',
  159. 'all',
  160. 'each',
  161. 'map',
  162. 'close',
  163. 'exec'
  164. ].forEach(function (name) {
  165. trace.extendTrace(Database.prototype, name);
  166. });
  167. [
  168. 'bind',
  169. 'get',
  170. 'run',
  171. 'all',
  172. 'each',
  173. 'map',
  174. 'reset',
  175. 'finalize',
  176. ].forEach(function (name) {
  177. trace.extendTrace(Statement.prototype, name);
  178. });
  179. isVerbose = true;
  180. }
  181. return sqlite3;
  182. };