1 | # SQLite Client for Node.js Apps
|
2 |
|
3 | [![NPM version](https://img.shields.io/npm/v/sqlite.svg?style=flat-square)](https://www.npmjs.com/package/sqlite)
|
4 | [![CircleCI](https://circleci.com/gh/kriasoft/node-sqlite.svg?style=svg)](https://circleci.com/gh/kriasoft/node-sqlite)
|
5 | ![built with typescript](https://camo.githubusercontent.com/92e9f7b1209bab9e3e9cd8cdf62f072a624da461/68747470733a2f2f666c61742e62616467656e2e6e65742f62616467652f4275696c74253230576974682f547970655363726970742f626c7565)
|
6 | [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
|
7 |
|
8 | > A wrapper library written in Typescript with **ZERO** dependencies that adds ES6 promises
|
9 | > and SQL-based migrations API to [sqlite3](https://github.com/mapbox/node-sqlite3/) ([docs](https://github.com/mapbox/node-sqlite3/wiki)).
|
10 |
|
11 | **note** v4 of `sqlite` has breaking changes compared to v3! Please see `CHANGELOG.md` for more details.
|
12 |
|
13 |
|
14 |
|
15 | - [Installation](#installation)
|
16 | - [Install `sqlite3`](#install-sqlite3)
|
17 | - [Install `sqlite`](#install-sqlite)
|
18 | - [Usage](#usage)
|
19 | - [Opening the database](#opening-the-database)
|
20 | - [Without caching](#without-caching)
|
21 | - [With caching](#with-caching)
|
22 | - [Enable verbose / debug mode](#enable-verbose--debug-mode)
|
23 | - [Tracing SQL errors](#tracing-sql-errors)
|
24 | - [With a custom driver](#with-a-custom-driver)
|
25 | - [Opening multiple databases](#opening-multiple-databases)
|
26 | - [`open` config params](#open-config-params)
|
27 | - [Examples](#examples)
|
28 | - [Creating a table and inserting data](#creating-a-table-and-inserting-data)
|
29 | - [Getting a single row](#getting-a-single-row)
|
30 | - [Getting many rows](#getting-many-rows)
|
31 | - [Inserting rows](#inserting-rows)
|
32 | - [Updating rows](#updating-rows)
|
33 | - [Prepared statement](#prepared-statement)
|
34 | - [`each()`](#each)
|
35 | - [Get the driver instance](#get-the-driver-instance)
|
36 | - [Closing the database](#closing-the-database)
|
37 | - [ES6 tagged template strings](#es6-tagged-template-strings)
|
38 | - [Migrations](#migrations)
|
39 | - [Typescript tricks](#typescript-tricks)
|
40 | - [Import interfaces from sqlite](#import-interfaces-from-sqlite)
|
41 | - [Specify typings for a specific database driver](#specify-typings-for-a-specific-database-driver)
|
42 | - [Use generics to get better typings on your rows](#use-generics-to-get-better-typings-on-your-rows)
|
43 | - [Get example](#get-example)
|
44 | - [All example](#all-example)
|
45 | - [API Documentation](#api-documentation)
|
46 | - [Management Tools](#management-tools)
|
47 | - [Alternative SQLite libraries](#alternative-sqlite-libraries)
|
48 | - [References](#references)
|
49 | - [License](#license)
|
50 |
|
51 |
|
52 |
|
53 | ## Installation
|
54 |
|
55 | ### Install `sqlite3`
|
56 |
|
57 | Most people who use this library will use [sqlite3](https://github.com/mapbox/node-sqlite3/)
|
58 | as the database driver.
|
59 |
|
60 | Any library that conforms to the `sqlite3` ([API](https://github.com/mapbox/node-sqlite3/wiki/API))
|
61 | should also work.
|
62 |
|
63 | `$ npm install sqlite3 --save`
|
64 |
|
65 | ### Install `sqlite`
|
66 |
|
67 | ```sh
|
68 | # v4 of sqlite is targeted for nodejs 10 and on.
|
69 | $ npm install sqlite --save
|
70 |
|
71 | # If you need a legacy version for an older version of nodejs
|
72 | # install v3 instead, and look at the v3 branch readme for usage details
|
73 | $ npm install sqlite@3 --save
|
74 | ```
|
75 |
|
76 | ## Usage
|
77 |
|
78 | This module has the same API as the original `sqlite3` library ([docs](https://github.com/mapbox/node-sqlite3/wiki/API)),
|
79 | except that all its API methods return ES6 Promises and do not accept callback arguments (with the exception of `each()`).
|
80 |
|
81 | ### Opening the database
|
82 |
|
83 | #### Without caching
|
84 |
|
85 | ```typescript
|
86 | import sqlite3 from 'sqlite3'
|
87 | import { open } from 'sqlite'
|
88 |
|
89 | // this is a top-level await
|
90 | (async () => {
|
91 | // open the database
|
92 | const db = await open({
|
93 | filename: '/tmp/database.db',
|
94 | driver: sqlite3.Database
|
95 | })
|
96 | })()
|
97 | ```
|
98 | or
|
99 |
|
100 | ```typescript
|
101 | import sqlite3 from 'sqlite3'
|
102 | import { open } from 'sqlite'
|
103 |
|
104 | open({
|
105 | filename: '/tmp/database.db',
|
106 | driver: sqlite3.Database
|
107 | }).then((db) => {
|
108 | // do your thing
|
109 | })
|
110 | ```
|
111 |
|
112 | or
|
113 |
|
114 | ```typescript
|
115 | import sqlite3 from 'sqlite3'
|
116 | import { open } from 'sqlite'
|
117 |
|
118 | // you would have to import / invoke this in another file
|
119 | export async function openDb () {
|
120 | return open({
|
121 | filename: '/tmp/database.db',
|
122 | driver: sqlite3.Database
|
123 | })
|
124 | }
|
125 | ```
|
126 |
|
127 | #### With caching
|
128 |
|
129 | If you want to enable the [database object cache](https://github.com/mapbox/node-sqlite3/wiki/Caching)
|
130 |
|
131 | ```typescript
|
132 | import sqlite3 from 'sqlite3'
|
133 | import { open } from 'sqlite'
|
134 |
|
135 | (async () => {
|
136 | const db = await open({
|
137 | filename: '/tmp/database.db',
|
138 | driver: sqlite3.cached.Database
|
139 | })
|
140 | })()
|
141 | ```
|
142 |
|
143 | #### Enable verbose / debug mode
|
144 |
|
145 | ```typescript
|
146 | import sqlite3 from 'sqlite3'
|
147 |
|
148 | sqlite3.verbose()
|
149 | ```
|
150 |
|
151 | #### Tracing SQL errors
|
152 |
|
153 | For more info, see this [doc](https://github.com/mapbox/node-sqlite3/wiki/Debugging#databaseontrace-callback).
|
154 |
|
155 | ```typescript
|
156 | db.on('trace', (data) => {
|
157 |
|
158 | })
|
159 | ```
|
160 |
|
161 | #### With a custom driver
|
162 |
|
163 | You can use an alternative library to `sqlite3` as long as it conforms to the `sqlite3` [API](https://github.com/mapbox/node-sqlite3/wiki/API).
|
164 |
|
165 | For example, using `sqlite3-offline-next`:
|
166 |
|
167 | ```typescript
|
168 | import sqlite3Offline from 'sqlite3-offline-next'
|
169 | import { open } from 'sqlite'
|
170 |
|
171 | (async () => {
|
172 | const db = await open({
|
173 | filename: '/tmp/database.db',
|
174 | driver: sqlite3Offline.Database
|
175 | })
|
176 | })()
|
177 | ```
|
178 |
|
179 | #### Opening multiple databases
|
180 |
|
181 | ```typescript
|
182 | import sqlite3 from 'sqlite3'
|
183 | import { open } from 'sqlite'
|
184 |
|
185 | (async () => {
|
186 | const [db1, db2] = await Promise.all([
|
187 | open({
|
188 | filename: '/tmp/database.db',
|
189 | driver: sqlite3.Database
|
190 | }),
|
191 | open({
|
192 | filename: '/tmp/database2.db',
|
193 | driver: sqlite3.Database
|
194 | }),
|
195 | ])
|
196 |
|
197 | await db1.migrate({
|
198 | migrationsPath: '...'
|
199 | })
|
200 |
|
201 | await db2.migrate({
|
202 | migrationsPath: '...'
|
203 | })
|
204 | })()
|
205 | ```
|
206 |
|
207 | #### `open` config params
|
208 |
|
209 | ```typescript
|
210 |
|
211 | // db is an instance of `sqlite#Database`
|
212 | // which is a wrapper around `sqlite3#Database`
|
213 | const db = await open({
|
214 | /**
|
215 | * Valid values are filenames, ":memory:" for an anonymous in-memory
|
216 | * database and an empty string for an anonymous disk-based database.
|
217 | * Anonymous databases are not persisted and when closing the database
|
218 | * handle, their contents are lost.
|
219 | */
|
220 | filename: string
|
221 |
|
222 | /**
|
223 | * One or more of sqlite3.OPEN_READONLY, sqlite3.OPEN_READWRITE and
|
224 | * sqlite3.OPEN_CREATE. The default value is OPEN_READWRITE | OPEN_CREATE.
|
225 | */
|
226 | mode?: number
|
227 |
|
228 | /**
|
229 | * The database driver. Most will install `sqlite3` and use the `Database` class from it.
|
230 | * As long as the library you are using conforms to the `sqlite3` API, you can use it as
|
231 | * the driver.
|
232 | *
|
233 | * @example
|
234 | *
|
235 | * ```
|
236 | * import sqlite from 'sqlite3'
|
237 | *
|
238 | * const driver = sqlite.Database
|
239 | * ```
|
240 | */
|
241 | driver: any
|
242 | })
|
243 | ```
|
244 |
|
245 | ### Examples
|
246 |
|
247 | - See the `src/**/__tests__` directory for more example usages
|
248 | - See the `docs/` directory for full documentation.
|
249 | - Also visit the `sqlite3` library [API docs](https://github.com/mapbox/node-sqlite3/wiki/API)
|
250 |
|
251 | #### Creating a table and inserting data
|
252 |
|
253 | ```typescript
|
254 | await db.exec('CREATE TABLE tbl (col TEXT)')
|
255 | await db.exec('INSERT INTO tbl VALUES ("test")')
|
256 | ```
|
257 |
|
258 | #### Getting a single row
|
259 |
|
260 | ```typescript
|
261 | const result = await db.get('SELECT col FROM tbl WHERE col = ?', 'test')
|
262 |
|
263 | // { col: 'test' }
|
264 | ```
|
265 |
|
266 | ```typescript
|
267 | const result = await db.get('SELECT col FROM tbl WHERE col = ?', ['test'])
|
268 |
|
269 | // { col: 'test' }
|
270 | ```
|
271 |
|
272 | ```typescript
|
273 | const result = await db.get('SELECT col FROM tbl WHERE col = :test', {
|
274 | ':test': 'test'
|
275 | })
|
276 |
|
277 | // { col: 'test' }
|
278 | ```
|
279 |
|
280 | #### Getting many rows
|
281 |
|
282 | ```typescript
|
283 | const result = await db.all('SELECT col FROM tbl')
|
284 |
|
285 | // [{ col: 'test' }]
|
286 | ```
|
287 |
|
288 | #### Inserting rows
|
289 |
|
290 | ```typescript
|
291 | const result = await db.run(
|
292 | 'INSERT INTO tbl (col) VALUES (?)',
|
293 | 'foo'
|
294 | )
|
295 |
|
296 | /*
|
297 | {
|
298 | // row ID of the inserted row
|
299 | lastID: 1,
|
300 | // instance of `sqlite#Statement`
|
301 | // which is a wrapper around `sqlite3#Statement`
|
302 | stmt: <Statement>
|
303 | }
|
304 | */
|
305 | ```
|
306 |
|
307 | ```typescript
|
308 | const result = await db.run('INSERT INTO tbl(col) VALUES (:col)', {
|
309 | ':col': 'something'
|
310 | })
|
311 | ```
|
312 |
|
313 | #### Updating rows
|
314 |
|
315 | ```typescript
|
316 | const result = await db.run(
|
317 | 'UPDATE tbl SET col = ? WHERE col = ?',
|
318 | 'foo',
|
319 | 'test'
|
320 | )
|
321 |
|
322 | /*
|
323 | {
|
324 | // number of rows changed
|
325 | changes: 1,
|
326 | // instance of `sqlite#Statement`
|
327 | // which is a wrapper around `sqlite3#Statement`
|
328 | stmt: <Statement>
|
329 | }
|
330 | */
|
331 | ```
|
332 |
|
333 | #### Prepared statement
|
334 |
|
335 | ```typescript
|
336 | // stmt is an instance of `sqlite#Statement`
|
337 | // which is a wrapper around `sqlite3#Statement`
|
338 | const stmt = await db.prepare('SELECT col FROM tbl WHERE 1 = ? AND 5 = ?5')
|
339 | await stmt.bind({ 1: 1, 5: 5 })
|
340 | let result = await stmt.get()
|
341 | // { col: 'some text' }
|
342 | ```
|
343 |
|
344 | ```typescript
|
345 | const stmt = await db.prepare(
|
346 | 'SELECT col FROM tbl WHERE 13 = @thirteen ORDER BY col DESC'
|
347 | )
|
348 |
|
349 | const result = await stmt.all({ '@thirteen': 13 })
|
350 | ```
|
351 |
|
352 | #### `each()`
|
353 |
|
354 | `each()` is a bit different compared to the other operations due to its underlying [implementation](https://github.com/TryGhost/node-sqlite3/wiki/API#databaseeachsql-param--callback-complete).
|
355 |
|
356 | The function signature looks like this:
|
357 |
|
358 | `async each (sql, [...params], callback)`
|
359 |
|
360 | - `callback(err, row)` is triggered when the database has a row to return
|
361 | - The promise resolves when all rows have returned with the number of rows returned.
|
362 |
|
363 | ```typescript
|
364 | try {
|
365 | // You need to wrap this in a try / catch for SQL parse / connection errors
|
366 | const rowsCount = await db.each(
|
367 | 'SELECT col FROM tbl WHERE ROWID = ?',
|
368 | [2],
|
369 | (err, row) => {
|
370 | if (err) {
|
371 | // This would be if there is an error specific to the row result
|
372 | throw err
|
373 | }
|
374 |
|
375 | // row = { col: 'other thing' }
|
376 | }
|
377 | )
|
378 | } catch (e) {
|
379 | throw e
|
380 | }
|
381 |
|
382 | // rowsCount = 1
|
383 | ```
|
384 |
|
385 | #### Get the driver instance
|
386 |
|
387 | Useful if you need to call methods that are not supported yet.
|
388 |
|
389 | ```typescript
|
390 | const rawDb = db.getDatabaseInstance()
|
391 | const rawStatement = stmt.getStatementInstance()
|
392 | ```
|
393 |
|
394 | #### Closing the database
|
395 |
|
396 | ```typescript
|
397 | await db.close()
|
398 | ```
|
399 |
|
400 | ### ES6 tagged template strings
|
401 |
|
402 | This module is compatible with [sql-template-strings](https://www.npmjs.com/package/sql-template-strings).
|
403 |
|
404 | ```js
|
405 | import SQL from 'sql-template-strings'
|
406 |
|
407 | const book = 'harry potter';
|
408 | const author = 'J. K. Rowling';
|
409 |
|
410 | const data = await db.all(SQL`SELECT author FROM books WHERE name = ${book} AND author = ${author}`);
|
411 | ```
|
412 |
|
413 | ### Migrations
|
414 |
|
415 | This module comes with a lightweight migrations API that works with [SQL-based migration files](https://github.com/kriasoft/node-sqlite/tree/master/migrations)
|
416 |
|
417 | With default configuration, you can create a `migrations/` directory in your project with SQL files,
|
418 | and call the `migrate()` method to run the SQL in the directory against the database.
|
419 |
|
420 | See this project's `migrations/` folder for examples.
|
421 |
|
422 | ```typescript
|
423 | await db.migrate({
|
424 | /**
|
425 | * If true, will force the migration API to rollback and re-apply the latest migration over
|
426 | * again each time when Node.js app launches.
|
427 | */
|
428 | force?: boolean
|
429 | /**
|
430 | * Migrations table name. Default is 'migrations'
|
431 | */
|
432 | table?: string
|
433 | /**
|
434 | * Path to the migrations folder. Default is `path.join(process.cwd(), 'migrations')`
|
435 | */
|
436 | migrationsPath?: string
|
437 | })
|
438 | ```
|
439 |
|
440 | ## Typescript tricks
|
441 |
|
442 | ### Import interfaces from sqlite
|
443 |
|
444 | `import { ISqlite, IMigrate } from 'sqlite'`
|
445 |
|
446 | See the definitions for more details.
|
447 |
|
448 | ### Specify typings for a specific database driver
|
449 |
|
450 | ```typescript
|
451 | // Assuming you have @types/sqlite3 installed
|
452 | import sqlite3 from 'sqlite3'
|
453 |
|
454 | // sqlite3.Database, sqlite3.Statement is the default if no explicit generic is specified
|
455 | await open<sqlite3.Database, sqlite3.Statement>({
|
456 | filename: ':memory'
|
457 | })
|
458 | ```
|
459 |
|
460 | ### Use generics to get better typings on your rows
|
461 |
|
462 | Most methods allow for the use of [generics](https://www.typescriptlang.org/docs/handbook/generics.html)
|
463 | to specify the data type of your returned data. This allows your IDE to perform better autocomplete
|
464 | and the typescript compiler to perform better static type analysis.
|
465 |
|
466 | #### Get example
|
467 |
|
468 | ```typescript
|
469 |
|
470 | interface Row {
|
471 | col: string
|
472 | }
|
473 |
|
474 | // result will be of type Row, allowing Typescript supported IDEs to autocomplete on the properties!
|
475 | const result = await db.get<Row>('SELECT col FROM tbl WHERE col = ?', 'test')
|
476 | ```
|
477 |
|
478 | #### All example
|
479 |
|
480 | ```typescript
|
481 | interface Row {
|
482 | col: string
|
483 | }
|
484 |
|
485 | // Result is an array of rows, you can now have array-autocompletion data
|
486 | const result = await db.all<Row[]>('SELECT col FROM tbl')
|
487 |
|
488 | result.each((row) => {
|
489 | // row should have type information now!
|
490 | })
|
491 | ```
|
492 |
|
493 | ## API Documentation
|
494 |
|
495 | See the [`docs`](docs/globals.md) directory for full documentation.
|
496 |
|
497 | ## Management Tools
|
498 |
|
499 | - [Beekeeper Studio](https://www.beekeeperstudio.io/): Open Source SQL Editor and Database Manager
|
500 | - [DB Browser for SQLite](https://github.com/sqlitebrowser/sqlitebrowser): Desktop-based browser.
|
501 | - [datasette](https://github.com/simonw/datasette): Datasette is a tool for exploring and publishing
|
502 | data. Starts up a server that provides a web interface to your SQLite data.
|
503 | - [SQLite Studio](https://github.com/pawelsalawa/sqlitestudio): A free, open source, multi-platform SQLite database manager written in C++, with use of Qt framework.
|
504 | - [HeidiSQL](https://www.heidisql.com/): Full-featured database editor.
|
505 | - [DBeaver](https://dbeaver.io/): Full-featured multi-platform database tool and designer.
|
506 |
|
507 | ## Alternative SQLite libraries
|
508 |
|
509 | This library and the library it primarily supports, `sqlite3`, may not be the best library that
|
510 | fits your use-case. You might want to try these other SQLite libraries:
|
511 |
|
512 | - [better-sqlite3](https://github.com/JoshuaWise/better-sqlite3): Totes itself as the fastest and
|
513 | simplest library for SQLite3 in Node.js.
|
514 | - [Bun sqlite3](https://github.com/Jarred-Sumner/bun#bunsqlite-sqlite3-module): `bun:sqlite` is a high-performance builtin SQLite3 module for `bun.js`.
|
515 | - [sql.js](https://github.com/sql-js/sql.js): SQLite compiled to Webassembly.
|
516 | - [sqlite3-offline-next](https://github.com/nicolaiort/sqlite3-offline-next): Offers pre-compiled `sqlite3`
|
517 | binaries if your machine cannot compile it. Should be mostly compatible with this library.
|
518 |
|
519 | If you know of any others, feel free to open a PR to add them to the list.
|
520 |
|
521 | ## References
|
522 |
|
523 | * [Using SQLite with Node.js for Rapid Prototyping](https://medium.com/@tarkus/node-js-and-sqlite-for-rapid-prototyping-bc9cf1f26f10) on Medium.com
|
524 | * [SQLite Documentation](https://www.sqlite.org/docs.html), e.g. [SQL Syntax](https://www.sqlite.org/lang.html), [Data Types](https://www.sqlite.org/datatype3.html) etc. on SQLite.org
|
525 | * ES6 tagged [sql-template-strings](https://www.npmjs.com/package/sql-template-strings).
|
526 |
|
527 | ## License
|
528 |
|
529 | The MIT License © 2020-present Kriasoft / Theo Gravity. All rights reserved.
|
530 |
|
531 | ---
|
532 | Made with ♥ by [Konstantin Tarkus](https://github.com/koistya) ([@koistya](https://twitter.com/koistya)), [Theo Gravity](https://github.com/theogravity) and [contributors](https://github.com/kriasoft/node-sqlite/graphs/contributors)
|