UNPKG

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