@depup/better-sqlite3-helper 3.1.7-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/FUNDING.yml ADDED
@@ -0,0 +1 @@
1
+ ko_fi: kautode
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Markus Madeja
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @depup/better-sqlite3-helper
2
+
3
+ > Dependency-bumped version of [better-sqlite3-helper](https://www.npmjs.com/package/better-sqlite3-helper)
4
+
5
+ Generated by [DepUp](https://github.com/depup/npm) -- all production
6
+ dependencies bumped to latest versions.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @depup/better-sqlite3-helper
12
+ ```
13
+
14
+ | Field | Value |
15
+ |-------|-------|
16
+ | Original | [better-sqlite3-helper](https://www.npmjs.com/package/better-sqlite3-helper) @ 3.1.7 |
17
+ | Processed | 2026-03-19 |
18
+ | Smoke test | passed |
19
+ | Deps updated | 1 |
20
+
21
+ ## Dependency Changes
22
+
23
+ | Dependency | From | To |
24
+ |------------|------|-----|
25
+ | better-sqlite3 | ^9.2.0 | ^12.8.0 |
26
+
27
+ ---
28
+
29
+ Source: https://github.com/depup/npm | Original: https://www.npmjs.com/package/better-sqlite3-helper
30
+
31
+ License inherited from the original package.
package/changes.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "bumped": {
3
+ "better-sqlite3": {
4
+ "from": "^9.2.0",
5
+ "to": "^12.8.0"
6
+ }
7
+ },
8
+ "timestamp": "2026-03-19T03:03:51.793Z",
9
+ "totalUpdated": 1
10
+ }
package/index.d.ts ADDED
@@ -0,0 +1,302 @@
1
+ import BetterSqlite3 = require("better-sqlite3");
2
+ declare namespace BetterSqlite3Helper {
3
+ type MigrationOptions = {
4
+ /** Whether to set to 'last' to automatically reapply the last migration-file. Default: false */
5
+ force?: "last" | false;
6
+ /** The name of the database table that is used to keep track. Default: 'migration' */
7
+ table?: string;
8
+ /** The path of the migration files. Default: './migrations' */
9
+ migrationsPath?: string;
10
+ /** Or an array of migration strings */
11
+ migrations?: string[];
12
+ };
13
+
14
+ type DBOptions = {
15
+ /** Path to sqlite database file. Default: './data/sqlite3.db' */
16
+ path?: string;
17
+ /** Whether to create a db only in memory. Default: false */
18
+ memory?: boolean;
19
+ /** Whether to open database readonly. Default: false */
20
+ readonly?: boolean;
21
+ /** Whether to throw error if database not exists. Default: false */
22
+ fileMustExist?: boolean;
23
+ /** Whether to automatically enable 'PRAGMA journal_mode = WAL'. Default: true */
24
+ WAL?: boolean;
25
+ /** Migration options. Disable completely by setting `migrate: false` */
26
+ migrate?: MigrationOptions | false;
27
+ };
28
+
29
+ type DataObject = { [key: string]: any };
30
+
31
+ /**
32
+ * Specifies a where clause.
33
+ *
34
+ * - Either a string containing the value to use as ID that will be translated to ['id = ?', id]
35
+ * - Or an array with a string and the replacements for ? after that. F.e. ['id > ? && name = ?', id, name].
36
+ * - Or an object with key values. F.e. {id: params.id}. Or simply an ID that will be translated to ['id = ?', id]
37
+ */
38
+ type WhereClause = string | any[] | DataObject;
39
+
40
+ type VariableArgFunction = (...params: any[]) => any;
41
+ type ArgumentTypes<F extends VariableArgFunction> = F extends (
42
+ ...args: infer A
43
+ ) => any
44
+ ? A
45
+ : never;
46
+
47
+ interface Transaction<F extends VariableArgFunction> {
48
+ (...params: ArgumentTypes<F>): any;
49
+ default(...params: ArgumentTypes<F>): any;
50
+ deferred(...params: ArgumentTypes<F>): any;
51
+ immediate(...params: ArgumentTypes<F>): any;
52
+ exclusive(...params: ArgumentTypes<F>): any;
53
+ }
54
+
55
+ interface DBInstance {
56
+ memory: boolean;
57
+ readonly: boolean;
58
+ name: string;
59
+ open: boolean;
60
+ inTransaction: boolean;
61
+
62
+ connection(): BetterSqlite3.Database;
63
+
64
+ prepare(sql: string): BetterSqlite3.Statement;
65
+
66
+ transaction<F extends VariableArgFunction>(fn: F): Transaction<F>;
67
+
68
+ exec(sqls: string): this;
69
+ pragma(string: string, options?: BetterSqlite3.PragmaOptions): any;
70
+ checkpoint(databaseName?: string): this;
71
+ function(name: string, cb: (...params: any[]) => any): this;
72
+ function(
73
+ name: string,
74
+ options: BetterSqlite3.RegistrationOptions,
75
+ cb: (...params: any[]) => any
76
+ ): this;
77
+ aggregate(name: string, options: BetterSqlite3.AggregateOptions): this;
78
+ loadExtension(path: string): this;
79
+ close(): this;
80
+ defaultSafeIntegers(toggleState?: boolean): this;
81
+
82
+ /**
83
+ * Executes the prepared statement. When execution completes it returns an info object describing any changes made. The info object has two properties:
84
+ *
85
+ * info.changes: The total number of rows that were inserted, updated, or deleted by this operation. Changes made by foreign key actions or trigger programs do not count.
86
+ * info.lastInsertRowid: The rowid of the last row inserted into the database (ignoring those caused by trigger programs). If the current statement did not insert any rows into the database, this number should be completely ignored.
87
+ *
88
+ * If execution of the statement fails, an Error is thrown.
89
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#runbindparameters---object
90
+ *
91
+ * @param {Object} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
92
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#binding-parameters
93
+ * @returns {Object}
94
+ */
95
+ run(query: string, ...bindParameters: any[]): BetterSqlite3.RunResult;
96
+
97
+ /**
98
+ * Returns all values of a query
99
+ * @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#allbindparameters---array-of-rows
100
+ *
101
+ * @param {Object} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
102
+ * @param {any} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#binding-parameters
103
+ * @returns {array}
104
+ */
105
+ query<RowData = DataObject>(
106
+ query: string,
107
+ ...bindParameters: any[]
108
+ ): RowData[];
109
+
110
+ /**
111
+ * Similar to .query(), but instead of returning every row together, an iterator is returned so you can retrieve the rows one by one.
112
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#iteratebindparameters---iterator
113
+ *
114
+ * @param {Object} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
115
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#binding-parameters
116
+ * @returns {Iterator}
117
+ */
118
+ queryIterate<RowData = DataObject>(
119
+ query: string,
120
+ ...bindParameters: any[]
121
+ ): Iterable<RowData>;
122
+
123
+ /**
124
+ * Returns the values of the first row of the query-result
125
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#getbindparameters---row
126
+ *
127
+ * @param {Object} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
128
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
129
+ * @returns {Object|undefined}
130
+ */
131
+ queryFirstRow<RowData = DataObject>(
132
+ query: string,
133
+ ...bindParameters: any[]
134
+ ): RowData | undefined;
135
+
136
+ /**
137
+ * Returns the values of the first row of the query-result
138
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#getbindparameters---row
139
+ * It returns always an object and thus can be used with destructuring assignment
140
+ *
141
+ * @example const {id, name} = DB().queryFirstRowObject(sql)
142
+ * @param {Object} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
143
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
144
+ * @returns {Object}
145
+ */
146
+ queryFirstRowObject<RowData = DataObject>(
147
+ query: string,
148
+ ...bindParameters: any[]
149
+ ): RowData | Object;
150
+
151
+ /**
152
+ * Returns the value of the first column in the first row of the query-result
153
+ *
154
+ * @param {Object} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
155
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
156
+ * @returns {*}
157
+ */
158
+ queryFirstCell<CellType = any>(
159
+ query: string,
160
+ ...bindParameters: any[]
161
+ ): CellType | undefined;
162
+
163
+ /**
164
+ * Returns an Array that only contains the values of the specified column
165
+ *
166
+ * @param {String} column Name of the column
167
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
168
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
169
+ * @returns {Array}
170
+ */
171
+ queryColumn<ColumnType = any>(
172
+ column: string,
173
+ query: string,
174
+ ...bindParameters: any[]
175
+ ): ColumnType[];
176
+
177
+ /**
178
+ * Returns a Object that get it key-value-combination from the result of the query
179
+ *
180
+ * @param {String} key Name of the column that values should be the key
181
+ * @param {String} column Name of the column that values should be the value for the object
182
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
183
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
184
+ * @returns {object}
185
+ */
186
+ queryKeyAndColumn<ValueColumnType = any>(
187
+ key: string,
188
+ column: string,
189
+ query: string,
190
+ ...bindParameters: any[]
191
+ ): { [key: string]: ValueColumnType };
192
+
193
+ /**
194
+ * Create an update statement; create more complex one with exec yourself.
195
+ *
196
+ * @param {String} table required. Name of the table
197
+ * @param {Object} data A Object of data to set. Key is the name of the column. Value 'undefined' is filtered
198
+ * @param {String|Array|Object} where required. array with a string and the replacements for ? after that. F.e. ['id > ? && name = ?', id, name]. Or an object with key values. F.e. {id: params.id}.
199
+ * @param {undefined|Array} whiteList optional List of columns that can only be updated with "data"
200
+ * @returns {Integer} Number of changed rows
201
+ */
202
+ update<RowData = DataObject>(
203
+ table: string,
204
+ data: Partial<RowData>,
205
+ where: WhereClause,
206
+ whiteList?: string[]
207
+ ): number;
208
+
209
+ /**
210
+ * Create an update statement; create more complex one with exec yourself.
211
+ *
212
+ * @param {String} table Name of the table
213
+ * @param {Object} data a Object of data to set. Key is the name of the column. Value 'undefined' is filtered
214
+ * @param {String|Array|Object} where required. array with a string and the replacements for ? after that. F.e. ['id > ? && name = ?', id, name]. Or an object with key values. F.e. {id: params.id}.
215
+ * @param {undefined|Array} whiteBlackList optional List of columns that can not be updated with "data" (blacklist)
216
+ * @returns {Integer} Number of changed rows
217
+ */
218
+ updateWithBlackList<RowData = DataObject>(
219
+ table: string,
220
+ data: Partial<RowData>,
221
+ where: WhereClause,
222
+ blackList?: string[]
223
+ ): number;
224
+
225
+ /**
226
+ * Create an insert statement; create more complex one with exec yourself.
227
+ *
228
+ * @param {String} table Name of the table
229
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
230
+ * @param {undefined|Array} whiteList optional List of columns that only can be updated with "data"
231
+ * @returns {Integer} Last inserted row id
232
+ */
233
+ insert<RowData = DataObject>(
234
+ table: string,
235
+ data: Partial<RowData> | Partial<RowData>[],
236
+ whiteList?: string[]
237
+ ): number;
238
+
239
+ /**
240
+ * Create an insert statement; create more complex one with exec yourself.
241
+ *
242
+ * @param {String} table Name of the table
243
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
244
+ * @param {undefined|Array} whiteBlackList optional List of columns that can not be updated with "data" (blacklist)
245
+ * @returns {Integer} Last inserted row id
246
+ */
247
+ insertWithBlackList<RowData = DataObject>(
248
+ table: string,
249
+ data: Partial<RowData> | Partial<RowData>[],
250
+ blackList?: string[]
251
+ ): number;
252
+
253
+ /**
254
+ * Create an replace statement; create more complex one with exec yourself.
255
+ *
256
+ * @param {String} table Name of the table
257
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
258
+ * @param {undefined|Array} whiteList optional List of columns that only can be updated with "data"
259
+ * @returns {Integer} Last inserted row id
260
+ */
261
+ replace<RowData = DataObject>(
262
+ table: string,
263
+ data: Partial<RowData> | Partial<RowData>[],
264
+ whiteList?: string[]
265
+ ): number;
266
+
267
+ /**
268
+ * Create an replace statement; create more complex one with exec yourself.
269
+ *
270
+ * @param {String} table Name of the table
271
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
272
+ * @param {undefined|Array} whiteBlackList optional List of columns that can not be updated with "data" (blacklist)
273
+ * @returns {Integer} Last inserted row id
274
+ */
275
+ replaceWithBlackList<RowData = DataObject>(
276
+ table: string,
277
+ data: Partial<RowData> | Partial<RowData>[],
278
+ blackList?: string[]
279
+ ): number;
280
+
281
+ /**
282
+ * Create a delete statement; create more complex one with exec yourself.
283
+ *
284
+ * @param {String} table required. Name of the table
285
+ * @param {String|Array|Object} where required. array with a string and the replacements for ? after that. F.e. ['id > ? && name = ?', id, name]. Or an object with key values. F.e. {id: params.id}.
286
+ * @returns {Integer} Number of changed rows
287
+ */
288
+ delete(
289
+ table: string,
290
+ where: WhereClause,
291
+ ): number;
292
+
293
+ /**
294
+ * Migrates database schema to the latest version
295
+ */
296
+ migrate(options?: MigrationOptions): this;
297
+ }
298
+ }
299
+
300
+ export default function DB(
301
+ options?: BetterSqlite3Helper.DBOptions
302
+ ): BetterSqlite3Helper.DBInstance;
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@depup/better-sqlite3-helper",
3
+ "version": "3.1.7-depup.0",
4
+ "description": "A wrapper library that eases the work with better-sqlite3 with some new functions and a migration-system (with updated dependencies)",
5
+ "main": "src/database.js",
6
+ "scripts": {
7
+ "test": "cross-env NODE_ENV=test ./node_modules/mocha/bin/_mocha --ui bdd --recursive ./test"
8
+ },
9
+ "author": "Markus Madeja",
10
+ "repository": "Kauto/better-sqlite3-helper",
11
+ "homepage": "http://intergenies.com/programs/nodejs/better-sqlite3-helper",
12
+ "license": "MIT",
13
+ "keywords": [
14
+ "better-sqlite3-helper",
15
+ "depup",
16
+ "updated-dependencies",
17
+ "security",
18
+ "latest",
19
+ "patched",
20
+ "sqlite3",
21
+ "sqlite",
22
+ "sql",
23
+ "database",
24
+ "save",
25
+ "custom",
26
+ "helper",
27
+ "better-sqlite3"
28
+ ],
29
+ "dependencies": {
30
+ "better-sqlite3": "^12.8.0",
31
+ "mkdirp": "^3.0.1"
32
+ },
33
+ "devDependencies": {
34
+ "@types/better-sqlite3": "^7.6.8",
35
+ "chai": "^4.3.10",
36
+ "cross-env": "^7.0.3",
37
+ "eslint": "^8.55.0",
38
+ "eslint-config-standard": "^17.1.0",
39
+ "eslint-plugin-import": "^2.29.0",
40
+ "eslint-plugin-node": "^11.1.0",
41
+ "eslint-plugin-promise": "^6.1.1",
42
+ "mocha": "^10.2.0"
43
+ },
44
+ "peerDependencies": {
45
+ "@types/better-sqlite3": "^7.6.3"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@types/better-sqlite3": {
49
+ "optional": true
50
+ }
51
+ },
52
+ "optionalDependencies": {
53
+ "app-root-path": "^3.0.0"
54
+ },
55
+ "depup": {
56
+ "changes": {
57
+ "better-sqlite3": {
58
+ "from": "^9.2.0",
59
+ "to": "^12.8.0"
60
+ }
61
+ },
62
+ "depsUpdated": 1,
63
+ "originalPackage": "better-sqlite3-helper",
64
+ "originalVersion": "3.1.7",
65
+ "processedAt": "2026-03-19T03:03:59.009Z",
66
+ "smokeTest": "passed"
67
+ }
68
+ }
@@ -0,0 +1,750 @@
1
+ const Database = require('better-sqlite3')
2
+ const path = require('path')
3
+ const fs = require('fs')
4
+ const mkdirp = require('mkdirp')
5
+
6
+ let rootDir = process.env.APP_ROOT || '.'
7
+ try {
8
+ rootDir = require('app-root-path').path
9
+ } catch (e) {}
10
+
11
+ if (rootDir === '.') {
12
+ try {
13
+ const electron = require('electron')
14
+ rootDir = (electron.app || electron.remote.app).getPath('userData')
15
+ } catch (e) {}
16
+ }
17
+
18
+
19
+ const dbFile = path.resolve(rootDir, './data/sqlite3.db')
20
+
21
+ let instance = null
22
+
23
+ /**
24
+ * Class to control database-connections
25
+ *
26
+ * @returns {DB}
27
+ * @constructor
28
+ */
29
+ function DB (options = {}) {
30
+ if (!(this instanceof DB)) {
31
+ instance = instance || new DB(...arguments)
32
+ return instance
33
+ }
34
+ this.options = Object.assign(
35
+ {
36
+ path: dbFile,
37
+ migrate: true,
38
+ readonly: false,
39
+ fileMustExist: false,
40
+ WAL: true
41
+ },
42
+ options
43
+ )
44
+
45
+ /**
46
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#properties
47
+ */
48
+ Object.defineProperty(this, 'open', {
49
+ get: function () {
50
+ return this.connection().open
51
+ }
52
+ })
53
+ Object.defineProperty(this, 'inTransaction', {
54
+ get: function () {
55
+ return this.connection().inTransaction
56
+ }
57
+ })
58
+ Object.defineProperty(this, 'name', {
59
+ get: function () {
60
+ return this.connection().name
61
+ }
62
+ })
63
+ Object.defineProperty(this, 'readonly', {
64
+ get: function () {
65
+ return this.connection().readonly
66
+ }
67
+ })
68
+ /**
69
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#transactionfunction---function
70
+ */
71
+ Object.defineProperty(this, 'transaction', {
72
+ get: function () {
73
+ let conn = this.connection();
74
+ return conn.transaction.bind(conn);
75
+ }
76
+ })
77
+ }
78
+
79
+ /**
80
+ * Will (create and) return the Better-Sqlite3-Database-Object
81
+ * @returns {Database}
82
+ */
83
+ DB.prototype.connection = function () {
84
+ if (this.db) {
85
+ return this.db
86
+ }
87
+ try {
88
+ // create path if it doesn't exists
89
+ mkdirp.sync(path.dirname(this.options.path))
90
+ this.db = new Database(this.options.path, {
91
+ readonly: this.options.readonly,
92
+ fileMustExist: this.options.fileMustExist
93
+ })
94
+ } catch (e) {
95
+ this.db = undefined
96
+ throw e
97
+ }
98
+ if (this.options.WAL) {
99
+ this.db.pragma('journal_mode = WAL')
100
+ }
101
+ if (this.options.migrate) {
102
+ this.migrate(
103
+ typeof this.options.migrate === 'object' ? this.options.migrate : {}
104
+ )
105
+ }
106
+ return this.db
107
+ }
108
+
109
+ /**
110
+ * Creates a new prepared Statement from the given SQL string.
111
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#preparestring---statement
112
+ *
113
+ * @param {String} sql the sql
114
+ * @returns {Statement}
115
+ */
116
+ DB.prototype.prepare = function (sql) {
117
+ return this.connection().prepare(sql)
118
+ }
119
+
120
+ /**
121
+ * Executes the given SQL string. Unlike prepared statements, this can execute strings that contain multiple SQL statements.
122
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#execstring---this
123
+ *
124
+ * @param {String} sqls the sql(s)
125
+ * @returns {this}
126
+ */
127
+ DB.prototype.exec = function (sqls) {
128
+ this.connection().exec(sqls)
129
+ return this
130
+ }
131
+
132
+ /**
133
+ * Executes the given PRAGMA and returns its result.
134
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#pragmastring-options---results
135
+ *
136
+ * @param {String} string the statement
137
+ * @param {Object} options the options
138
+ * @returns {Array|String|Integer} Result
139
+ */
140
+ DB.prototype.pragma = function (string, options = {}) {
141
+ return this.connection().pragma(string, options)
142
+ }
143
+
144
+ /**
145
+ * Runs a WAL mode checkpoint on all attached databases.
146
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#checkpointdatabasename---this
147
+ *
148
+ * @param {String} databaseName Name of the Database
149
+ * @returns {this}
150
+ */
151
+ DB.prototype.checkpoint = function (...args) {
152
+ this.connection().pragma('wal_checkpoint(RESTART)')
153
+ return this
154
+ }
155
+
156
+ /**
157
+ * By default, integers returned from the database (including the info.lastInsertRowid property) are normal JavaScript numbers.
158
+ * You can change this default as you please.
159
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/integer.md#getting-integers-from-the-database
160
+ *
161
+ * @param {Boolean} bool enable safe Integers
162
+ * @returns {this}
163
+ */
164
+ DB.prototype.defaultSafeIntegers = function (toggleState = true) {
165
+ this.connection().defaultSafeIntegers(toggleState)
166
+ return this
167
+ }
168
+
169
+ /**
170
+ * Loads a compiled SQLite3 extension and applies it to the current database connection.
171
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#loadextensionpath---this
172
+ *
173
+ * @param {String} path Path of the extention
174
+ * @returns {this}
175
+ */
176
+ DB.prototype.loadExtension = function (...args) {
177
+ this.connection().loadExtension(...args)
178
+ return this
179
+ }
180
+
181
+ /**
182
+ * Registers a user-defined function so that it can be used by SQL statements.
183
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#functionname-options-function---this
184
+ *
185
+ * @param {String} name
186
+ * @param {Object} options
187
+ * @param {function} callback
188
+ * @returns {this}
189
+ */
190
+ DB.prototype.function = function (...args) {
191
+ this.connection().function(...args)
192
+ return this
193
+ }
194
+
195
+ /**
196
+ * Registers a user-defined aggregate function.
197
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#aggregatename-options---this
198
+ *
199
+ * @param {String} name
200
+ * @param {Object} options
201
+ * @returns {this}
202
+ */
203
+ DB.prototype.aggregate = function (...args) {
204
+ this.connection().aggregate(...args)
205
+ return this
206
+ }
207
+
208
+ /**
209
+ * Initiates a backup of the database, returning a promise for when the backup is complete.
210
+ * No destination name creates a `sqlite3-bak-${Date.now()}.db`-File in the default data directory.
211
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#backupdestination-options---promise
212
+ *
213
+ * @param {String} destination Path of the extention
214
+ * @param {Object} options the options
215
+ * @returns {Promise}
216
+ */
217
+ DB.prototype.backup = function (destination, options = {}) {
218
+ return this.connection().backup(
219
+ destination || path.resolve(rootDir, `./data/sqlite3-bak-${Date.now()}.db`),
220
+ options
221
+ )
222
+ }
223
+
224
+ /**
225
+ * Closes the database connection.
226
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#close---this
227
+ *
228
+ * @returns {this}
229
+ */
230
+ DB.prototype.close = function () {
231
+ if (this.db) {
232
+ this.db.close()
233
+ this.db = undefined
234
+ if (this === instance) instance = null
235
+ }
236
+ return this
237
+ }
238
+
239
+ /**
240
+ * Executes the prepared statement. When execution completes it returns an info object describing any changes made. The info object has two properties:
241
+ *
242
+ * info.changes: The total number of rows that were inserted, updated, or deleted by this operation. Changes made by foreign key actions or trigger programs do not count.
243
+ * info.lastInsertRowid: The rowid of the last row inserted into the database (ignoring those caused by trigger programs). If the current statement did not insert any rows into the database, this number should be completely ignored.
244
+ *
245
+ * If execution of the statement fails, an Error is thrown.
246
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#runbindparameters---object
247
+ *
248
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
249
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#binding-parameters
250
+ * @returns {*}
251
+ */
252
+ DB.prototype.run = function (query, ...bindParameters) {
253
+ return this.connection()
254
+ .prepare(query)
255
+ .run(...bindParameters)
256
+ }
257
+
258
+ /**
259
+ * Returns all values of a query
260
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#allbindparameters---array-of-rows
261
+ *
262
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
263
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#binding-parameters
264
+ * @returns {Array}
265
+ */
266
+ DB.prototype.query = function (query, ...bindParameters) {
267
+ return this.connection()
268
+ .prepare(query)
269
+ .all(...bindParameters)
270
+ }
271
+
272
+ /**
273
+ * Similar to .query(), but instead of returning every row together, an iterator is returned so you can retrieve the rows one by one.
274
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#iteratebindparameters---iterator
275
+ *
276
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
277
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#binding-parameters
278
+ * @returns {Iterator}
279
+ */
280
+ DB.prototype.queryIterate = function (query, ...bindParameters) {
281
+ return this.connection()
282
+ .prepare(query)
283
+ .iterate(...bindParameters)
284
+ }
285
+
286
+ /**
287
+ * Returns the values of the first row of the query-result
288
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#getbindparameters---row
289
+ *
290
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
291
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
292
+ * @returns {Object|undefined}
293
+ */
294
+ DB.prototype.queryFirstRow = function (query, ...bindParameters) {
295
+ return this.connection()
296
+ .prepare(query)
297
+ .get(...bindParameters)
298
+ }
299
+
300
+ /**
301
+ * Returns the values of the first row of the query-result
302
+ * @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#getbindparameters---row
303
+ * It returns always an object and thus can be used with destructuring assignment
304
+ *
305
+ * @example const {id, name} = DB().queryFirstRowObject(sql)
306
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
307
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
308
+ * @returns {Object}
309
+ */
310
+ DB.prototype.queryFirstRowObject = function (query, ...bindParameters) {
311
+ return (
312
+ this.connection()
313
+ .prepare(query)
314
+ .get(...bindParameters) || {}
315
+ )
316
+ }
317
+
318
+ /**
319
+ * Returns the value of the first column in the first row of the query-result
320
+ *
321
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
322
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
323
+ * @returns {*}
324
+ */
325
+ DB.prototype.queryFirstCell = function (query, ...bindParameters) {
326
+ return this.connection()
327
+ .prepare(query)
328
+ .pluck(true)
329
+ .get(...bindParameters)
330
+ }
331
+
332
+ /**
333
+ * Returns an Array that only contains the values of the specified column
334
+ *
335
+ * @param {String} column Name of the column
336
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
337
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
338
+ * @returns {Array}
339
+ */
340
+ DB.prototype.queryColumn = function (column, query, ...bindParameters) {
341
+ return this.query(query, ...bindParameters).map(v => v[column])
342
+ }
343
+
344
+ /**
345
+ * Returns a Object that get it key-value-combination from the result of the query
346
+ *
347
+ * @param {String} key Name of the column that values should be the key
348
+ * @param {String} column Name of the column that values should be the value for the object
349
+ * @param {String} query the SQL-Query that should be run. Can contain placeholders for bind parameters.
350
+ * @param {*} bindParameters You can specify bind parameters @see https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/api.md#binding-parameters
351
+ * @returns {object}
352
+ */
353
+ DB.prototype.queryKeyAndColumn = function (
354
+ key,
355
+ column,
356
+ query,
357
+ ...bindParameters
358
+ ) {
359
+ return this.query(query, ...bindParameters).reduce((cur, v) => {
360
+ cur[v[key]] = v[column]
361
+ return cur
362
+ }, {})
363
+ }
364
+
365
+ /**
366
+ * Create an update statement; create more complex one with exec yourself.
367
+ *
368
+ * @param {String} table required. Name of the table
369
+ * @param {Object} data A Object of data to set. Key is the name of the column. Value 'undefined' is filtered
370
+ * @param {String|Array|Object} where required. array with a string and the replacements for ? after that. F.e. ['id > ? && name = ?', id, name]. Or an object with key values. F.e. {id: params.id}. Or simply an ID that will be translated to ['id = ?', id]
371
+ * @param {undefined|Array} whiteList optional List of columns that can only be updated with "data"
372
+ * @returns {Integer} Number of changed rows
373
+ */
374
+ DB.prototype.update = function (table, data, where, whiteList) {
375
+ if (!where) {
376
+ throw new Error('Where is missing for the update command of DB()')
377
+ }
378
+ if (!table) {
379
+ throw new Error('Table is missing for the update command of DB()')
380
+ }
381
+ if (typeof data !== 'object' || !Object.keys(data).length) {
382
+ return 0
383
+ }
384
+
385
+ // Build start of where query
386
+ let sql = `UPDATE \`${table}\` SET `
387
+ let parameter = []
388
+
389
+ // Build data part of the query
390
+ const setStringBuilder = []
391
+ for (const keyOfData in data) {
392
+ const value = data[keyOfData]
393
+ // don't set undefined and only values in an optional whitelist
394
+ if (value !== undefined && (!whiteList || whiteList.includes(keyOfData))) {
395
+ parameter.push(value)
396
+ setStringBuilder.push(`\`${keyOfData}\` = ?`)
397
+ }
398
+ }
399
+ if (!setStringBuilder.length) {
400
+ // nothing to update
401
+ return 0
402
+ }
403
+ sql += setStringBuilder.join(', ')
404
+
405
+ // Build where part of query
406
+ sql += ' WHERE '
407
+ if (Array.isArray(where)) {
408
+ const [whereTerm, ...whereParameter] = where
409
+ sql += whereTerm
410
+ parameter = [...parameter, ...whereParameter]
411
+ } else if (typeof where === 'object') {
412
+ const whereStringBuilder = []
413
+ for (const keyOfWhere in where) {
414
+ const value = where[keyOfWhere]
415
+ if (value !== undefined) {
416
+ parameter.push(value)
417
+ whereStringBuilder.push(`\`${keyOfWhere}\` = ?`)
418
+ }
419
+ }
420
+ if (!whereStringBuilder.length) {
421
+ throw new Error(
422
+ 'Where is not constructed for the update command of DB()'
423
+ )
424
+ }
425
+ sql += whereStringBuilder.join(' AND ')
426
+ } else {
427
+ sql += 'id = ?'
428
+ parameter.push(where)
429
+ }
430
+
431
+ return this.run(sql, ...parameter).changes
432
+ }
433
+
434
+ /**
435
+ * Create an update statement; create more complex one with exec yourself.
436
+ *
437
+ * @param {String} table Name of the table
438
+ * @param {Object} data a Object of data to set. Key is the name of the column. Value 'undefined' is filtered
439
+ * @param {String|Array|Object} where required. array with a string and the replacements for ? after that. F.e. ['id > ? && name = ?', id, name]. Or an object with key values. F.e. {id: params.id}. Or simply an ID that will be translated to ['id = ?', id]
440
+ * @param {undefined|Array} whiteBlackList optional List of columns that can not be updated with "data" (blacklist)
441
+ * @returns {Integer} Number of changed rows
442
+ */
443
+ DB.prototype.updateWithBlackList = function (table, data, where, blackList) {
444
+ return this.update(
445
+ table,
446
+ data,
447
+ where,
448
+ createWhiteListByBlackList.bind(this)(table, blackList)
449
+ )
450
+ }
451
+
452
+ /**
453
+ * Create an insert statement; create more complex one with exec yourself.
454
+ *
455
+ * @param {String} table Name of the table
456
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
457
+ * @param {undefined|Array} whiteList optional List of columns that only can be updated with "data"
458
+ * @returns {Integer} Last inserted row id
459
+ */
460
+ DB.prototype.insert = function (table, data, whiteList) {
461
+ return this.run(
462
+ ...createInsertOrReplaceStatement('INSERT', table, data, whiteList)
463
+ ).lastInsertRowid
464
+ }
465
+
466
+ /**
467
+ * Create an insert statement; create more complex one with exec yourself.
468
+ *
469
+ * @param {String} table Name of the table
470
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
471
+ * @param {undefined|Array} whiteBlackList optional List of columns that can not be updated with "data" (blacklist)
472
+ * @returns {Integer} Last inserted row id
473
+ */
474
+ DB.prototype.insertWithBlackList = function (table, data, blackList) {
475
+ return this.insert(
476
+ table,
477
+ data,
478
+ createWhiteListByBlackList.bind(this)(table, blackList)
479
+ )
480
+ }
481
+
482
+ /**
483
+ * Create an replace statement; create more complex one with exec yourself.
484
+ *
485
+ * @param {String} table Name of the table
486
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
487
+ * @param {undefined|Array} whiteList optional List of columns that only can be updated with "data"
488
+ * @returns {Integer} Last inserted row id
489
+ */
490
+ DB.prototype.replace = function (table, data, whiteList) {
491
+ return this.run(
492
+ ...createInsertOrReplaceStatement('REPLACE', table, data, whiteList)
493
+ ).lastInsertRowid
494
+ }
495
+
496
+ /**
497
+ * Create an replace statement; create more complex one with exec yourself.
498
+ *
499
+ * @param {String} table Name of the table
500
+ * @param {Object|Array} data a Object of data to set. Key is the name of the column. Can be an array of objects.
501
+ * @param {undefined|Array} whiteBlackList optional List of columns that can not be updated with "data" (blacklist)
502
+ * @returns {Integer} Last inserted row id
503
+ */
504
+ DB.prototype.replaceWithBlackList = function (table, data, blackList) {
505
+ return this.replace(
506
+ table,
507
+ data,
508
+ createWhiteListByBlackList.bind(this)(table, blackList)
509
+ )
510
+ }
511
+
512
+ /**
513
+ * Create a delete statement; create more complex one with exec yourself.
514
+ *
515
+ * @param {String} table required. Name of the table
516
+ * @param {String|Array|Object} where required. array with a string and the replacements for ? after that. F.e. ['id > ? && name = ?', id, name]. Or an object with key values. F.e. {id: params.id}. Or simply an ID that will be translated to ['id = ?', id]
517
+ * @returns {Integer} Number of changed rows
518
+ */
519
+ DB.prototype.delete = function (table, where) {
520
+ if (!where) {
521
+ throw new Error('Where is missing for the delete command of DB()')
522
+ }
523
+ if (!table) {
524
+ throw new Error('Table is missing for the delete command of DB()')
525
+ }
526
+
527
+ // Build start of where query
528
+ let sql = `DELETE FROM \`${table}\` WHERE `
529
+ let parameter = []
530
+
531
+ // Build where part of query
532
+ if (Array.isArray(where)) {
533
+ const [whereTerm, ...whereParameter] = where
534
+ sql += whereTerm
535
+ parameter = whereParameter
536
+ } else if (typeof where === 'object') {
537
+ const whereStringBuilder = []
538
+ for (const keyOfWhere in where) {
539
+ const value = where[keyOfWhere]
540
+ if (value !== undefined) {
541
+ parameter.push(value)
542
+ whereStringBuilder.push(`\`${keyOfWhere}\` = ?`)
543
+ }
544
+ }
545
+ if (!whereStringBuilder.length) {
546
+ throw new Error(
547
+ 'Where is not constructed for the delete command of DB()'
548
+ )
549
+ }
550
+ sql += whereStringBuilder.join(' AND ')
551
+ } else {
552
+ sql += 'id = ?'
553
+ parameter.push(where)
554
+ }
555
+ return this.run(sql, ...parameter).changes
556
+ }
557
+
558
+ /**
559
+ * Internal function to create a whitelist from a blacklist
560
+ *
561
+ * @param {String} table
562
+ * @param {Array} blackList
563
+ * @returns {Array} a whitelist
564
+ */
565
+ function createWhiteListByBlackList (table, blackList) {
566
+ let whiteList
567
+ if (Array.isArray(blackList)) {
568
+ // get all avaible columns
569
+ whiteList = this.queryColumn('name', `PRAGMA table_info('${table}')`)
570
+ // get only those not in the whiteBlackList
571
+ whiteList = whiteList.filter(v => !blackList.includes(v))
572
+ }
573
+ return whiteList
574
+ }
575
+
576
+ /**
577
+ * Internal function to create the insert or replace statement
578
+ *
579
+ * @param {String} insertOrReplace
580
+ * @param {String} table
581
+ * @param {*} data
582
+ * @param {undefined|Array} whiteList
583
+ * @returns {Array} sql and all parameters
584
+ */
585
+ function createInsertOrReplaceStatement (
586
+ insertOrReplace,
587
+ table,
588
+ data,
589
+ whiteList
590
+ ) {
591
+ if (!table) {
592
+ throw new Error(
593
+ `Table is missing for the ${insertOrReplace} command of DB()`
594
+ )
595
+ }
596
+ if (!Array.isArray(data)) {
597
+ data = [data]
598
+ }
599
+ if (typeof data[0] !== 'object') {
600
+ throw new Error('data does not contain a object')
601
+ }
602
+
603
+ let fields = Object.keys(data[0])
604
+
605
+ if (Array.isArray(whiteList)) {
606
+ fields = fields.filter(v => whiteList.includes(v))
607
+ }
608
+
609
+ // Build start of where query
610
+ let sql = `${insertOrReplace} INTO \`${table}\` (\`${fields.join(
611
+ '`,`'
612
+ )}\`) VALUES `
613
+ const parameter = []
614
+ let addComma = false
615
+
616
+ data.forEach(rowData => {
617
+ addComma && (sql += ',')
618
+ sql +=
619
+ '(' + Array.from({ length: fields.length }, () => '?').join(',') + ')'
620
+ fields.forEach(field => parameter.push(rowData[field]))
621
+ addComma = true
622
+ })
623
+ return [sql, ...parameter]
624
+ }
625
+
626
+ /**
627
+ * Migrates database schema to the latest version
628
+ *
629
+ * @param {Object} options
630
+ */
631
+ DB.prototype.migrate = function ({
632
+ force,
633
+ table = 'migrations',
634
+ migrationsPath = './migrations',
635
+ migrations = undefined
636
+ } = {}) {
637
+ if (!Array.isArray(migrations)) {
638
+ const location = path.resolve(rootDir, migrationsPath)
639
+
640
+ // Get the list of migration files, for example:
641
+ // { id: 1, name: 'initial', filename: '001-initial.sql' }
642
+ // { id: 2, name: 'feature', fielname: '002-feature.sql' }
643
+ const migrationFiles = fs
644
+ .readdirSync(location)
645
+ .map(x => x.match(/^(\d+).(.*?)\.sql$/))
646
+ .filter(x => x !== null)
647
+ .map(x => ({ id: Number(x[1]), name: x[2], filename: x[0] }))
648
+ .sort((a, b) => Math.sign(a.id - b.id))
649
+
650
+ if (!migrationFiles.length) {
651
+ // No migration files found
652
+ return
653
+ }
654
+
655
+ // Ge the list of migrations, for example:
656
+ // { id: 1, name: 'initial', filename: '001-initial.sql', up: ..., down: ... }
657
+ // { id: 2, name: 'feature', fielname: '002-feature.sql', up: ..., down: ... }
658
+ migrationFiles.map(migration => {
659
+ const filename = path.join(location, migration.filename)
660
+ migration.data = fs.readFileSync(filename, 'utf-8')
661
+ })
662
+ migrations = migrationFiles
663
+ } else {
664
+ migrations = migrations.map((migration, index) => {
665
+ return typeof migration === 'string' ? {
666
+ id: index + 1,
667
+ filename: index,
668
+ name: `array[${index}]`,
669
+ data: migration
670
+ } : migration
671
+ })
672
+ }
673
+
674
+ migrations.map(migration => {
675
+ const [up, down] = migration.data.split(/^\s*--\s+?down\b/im)
676
+ if (!down) {
677
+ const message = `The ${migration.filename} file does not contain '-- Down' separator.`
678
+ throw new Error(message)
679
+ } else {
680
+ migration.up = up.replace(/^-- .*?$/gm, '').trim() // Remove comments
681
+ migration.down = down.trim() // and trim whitespaces
682
+ }
683
+ })
684
+
685
+ // Create a database table for migrations meta data if it doesn't exist
686
+ this.exec(`CREATE TABLE IF NOT EXISTS "${table}" (
687
+ id INTEGER PRIMARY KEY,
688
+ name TEXT NOT NULL,
689
+ up TEXT NOT NULL,
690
+ down TEXT NOT NULL
691
+ )`)
692
+
693
+ // Get the list of already applied migrations
694
+ let dbMigrations = this.query(
695
+ `SELECT id, name, up, down FROM "${table}" ORDER BY id ASC`
696
+ )
697
+
698
+ // Undo migrations that exist only in the database but not in files,
699
+ // also undo the last migration if the `force` option was set to `last`.
700
+ const lastMigration = migrations[migrations.length - 1]
701
+ for (const migration of dbMigrations
702
+ .slice()
703
+ .sort((a, b) => Math.sign(b.id - a.id))) {
704
+ const isForceLastMigration = (force === 'last' && migration.id === lastMigration.id)
705
+ if (
706
+ !migrations.some(x => x.id === migration.id) || isForceLastMigration
707
+ ) {
708
+ this.exec('BEGIN')
709
+ try {
710
+ this.exec(isForceLastMigration ? lastMigration.down : migration.down)
711
+ this.run(`DELETE FROM "${table}" WHERE id = ?`, migration.id)
712
+ this.exec('COMMIT')
713
+ dbMigrations = dbMigrations.filter(x => x.id !== migration.id)
714
+ } catch (err) {
715
+ this.exec('ROLLBACK')
716
+ throw err
717
+ }
718
+ } else {
719
+ break
720
+ }
721
+ }
722
+
723
+ // Apply pending migrations
724
+ const lastMigrationId = dbMigrations.length
725
+ ? dbMigrations[dbMigrations.length - 1].id
726
+ : 0
727
+ for (const migration of migrations) {
728
+ if (migration.id > lastMigrationId) {
729
+ this.exec('BEGIN')
730
+ try {
731
+ this.exec(migration.up)
732
+ this.run(
733
+ `INSERT INTO "${table}" (id, name, up, down) VALUES (?, ?, ?, ?)`,
734
+ migration.id,
735
+ migration.name,
736
+ migration.up,
737
+ migration.down
738
+ )
739
+ this.exec('COMMIT')
740
+ } catch (err) {
741
+ this.exec('ROLLBACK')
742
+ throw err
743
+ }
744
+ }
745
+ }
746
+
747
+ return this
748
+ }
749
+
750
+ module.exports = DB