Coder Social home page Coder Social logo

kriasoft / node-sqlite Goto Github PK

View Code? Open in Web Editor NEW
867.0 16.0 94.0 1.34 MB

SQLite client wrapper around sqlite3 for Node.js applications with SQL-based migrations API written in Typescript

License: MIT License

JavaScript 5.34% Shell 3.15% TypeScript 91.50%
nodejs sql sqlite database es7-async async migration migrations migrate db

node-sqlite's Introduction

SQLite Client for Node.js Apps

NPM version CircleCI built with typescript JavaScript Style Guide

A wrapper library written in Typescript with ZERO dependencies that adds ES6 promises and SQL-based migrations API to sqlite3 (docs).

note v4 of sqlite has breaking changes compared to v3! Please see CHANGELOG.md for more details.

Installation

Install sqlite3

Most people who use this library will use sqlite3 as the database driver.

Any library that conforms to the sqlite3 (API) should also work.

$ npm install sqlite3 --save

Install sqlite

# v4 of sqlite is targeted for nodejs 10 and on.
$ npm install sqlite --save

# If you need a legacy version for an older version of nodejs
# install v3 instead, and look at the v3 branch readme for usage details
$ npm install sqlite@3 --save

Usage

This module has the same API as the original sqlite3 library (docs), except that all its API methods return ES6 Promises and do not accept callback arguments (with the exception of each()).

Opening the database

Without caching

import sqlite3 from 'sqlite3'
import { open } from 'sqlite'

// this is a top-level await 
(async () => {
    // open the database
    const db = await open({
      filename: '/tmp/database.db',
      driver: sqlite3.Database
    })
})()

or

import sqlite3 from 'sqlite3'
import { open } from 'sqlite'

open({
  filename: '/tmp/database.db',
  driver: sqlite3.Database
}).then((db) => {
  // do your thing
})

or

import sqlite3 from 'sqlite3'
import { open } from 'sqlite'

// you would have to import / invoke this in another file
export async function openDb () {
  return open({
    filename: '/tmp/database.db',
    driver: sqlite3.Database
  })
}

With caching

If you want to enable the database object cache

import sqlite3 from 'sqlite3'
import { open } from 'sqlite'

(async () => {
    const db = await open({
      filename: '/tmp/database.db',
      driver: sqlite3.cached.Database
    })
})()

Enable verbose / debug mode

import sqlite3 from 'sqlite3'

sqlite3.verbose()

Tracing SQL errors

For more info, see this doc.

db.on('trace', (data) => {
  
})

With a custom driver

You can use an alternative library to sqlite3 as long as it conforms to the sqlite3 API.

For example, using sqlite3-offline-next:

import sqlite3Offline from 'sqlite3-offline-next'
import { open } from 'sqlite'

(async () => {
    const db = await open({
      filename: '/tmp/database.db',
      driver: sqlite3Offline.Database
    })
})()

Opening multiple databases

import sqlite3 from 'sqlite3'
import { open } from 'sqlite'

(async () => {
  const [db1, db2] = await Promise.all([
    open({
      filename: '/tmp/database.db',
      driver: sqlite3.Database
    }),
    open({
      filename: '/tmp/database2.db',
      driver: sqlite3.Database
    }),
  ])

  await db1.migrate({
    migrationsPath: '...'
  })

  await db2.migrate({
    migrationsPath: '...'
  })
})()

open config params

// db is an instance of `sqlite#Database`
// which is a wrapper around `sqlite3#Database`
const db = await open({
  /**
   * Valid values are filenames, ":memory:" for an anonymous in-memory
   * database and an empty string for an anonymous disk-based database.
   * Anonymous databases are not persisted and when closing the database
   * handle, their contents are lost.
   */
  filename: string

  /**
   * One or more of sqlite3.OPEN_READONLY, sqlite3.OPEN_READWRITE and
   * sqlite3.OPEN_CREATE. The default value is OPEN_READWRITE | OPEN_CREATE.
   */
  mode?: number

  /**
   * The database driver. Most will install `sqlite3` and use the `Database` class from it.
   * As long as the library you are using conforms to the `sqlite3` API, you can use it as
   * the driver.
   *
   * @example
   *
   * ```
   * import sqlite from 'sqlite3'
   *
   * const driver = sqlite.Database
   * ```
   */
  driver: any
})

Examples

  • See the src/**/__tests__ directory for more example usages
  • See the docs/ directory for full documentation.
  • Also visit the sqlite3 library API docs

Creating a table and inserting data

await db.exec('CREATE TABLE tbl (col TEXT)')
await db.exec('INSERT INTO tbl VALUES ("test")')

Getting a single row

const result = await db.get('SELECT col FROM tbl WHERE col = ?', 'test')

// { col: 'test' }
const result = await db.get('SELECT col FROM tbl WHERE col = ?', ['test'])

// { col: 'test' }
const result = await db.get('SELECT col FROM tbl WHERE col = :test', {
  ':test': 'test'
})

// { col: 'test' }

Getting many rows

const result = await db.all('SELECT col FROM tbl')

// [{ col: 'test' }]

Inserting rows

const result = await db.run(
  'INSERT INTO tbl (col) VALUES (?)',
  'foo'
)

/*
{
  // row ID of the inserted row
  lastID: 1,
  // instance of `sqlite#Statement`
  // which is a wrapper around `sqlite3#Statement`
  stmt: <Statement>
}
*/
const result = await db.run('INSERT INTO tbl(col) VALUES (:col)', {
  ':col': 'something'
})

Updating rows

const result = await db.run(
  'UPDATE tbl SET col = ? WHERE col = ?',
  'foo',
  'test'
)

/*
{
  // number of rows changed
  changes: 1,
  // instance of `sqlite#Statement`
  // which is a wrapper around `sqlite3#Statement`
  stmt: <Statement>
}
*/

Prepared statement

// stmt is an instance of `sqlite#Statement`
// which is a wrapper around `sqlite3#Statement`
const stmt = await db.prepare('SELECT col FROM tbl WHERE 1 = ? AND 5 = ?5')
await stmt.bind({ 1: 1, 5: 5 })
let result = await stmt.get()
// { col: 'some text' }
const stmt = await db.prepare(
  'SELECT col FROM tbl WHERE 13 = @thirteen ORDER BY col DESC'
)

const result = await stmt.all({ '@thirteen': 13 })

each()

each() is a bit different compared to the other operations due to its underlying implementation.

The function signature looks like this:

async each (sql, [...params], callback)

  • callback(err, row) is triggered when the database has a row to return
  • The promise resolves when all rows have returned with the number of rows returned.
try {
  // You need to wrap this in a try / catch for SQL parse / connection errors
  const rowsCount = await db.each(
    'SELECT col FROM tbl WHERE ROWID = ?',
    [2],
    (err, row) => {
      if (err) {
        // This would be if there is an error specific to the row result
        throw err
      }

      // row = { col: 'other thing' }
    }
  )
} catch (e) {
  throw e
}

// rowsCount = 1

Get the driver instance

Useful if you need to call methods that are not supported yet.

const rawDb = db.getDatabaseInstance()
const rawStatement = stmt.getStatementInstance()

Closing the database

await db.close()

ES6 tagged template strings

This module is compatible with sql-template-strings.

import SQL from 'sql-template-strings'

const book = 'harry potter';
const author = 'J. K. Rowling';

const data = await db.all(SQL`SELECT author FROM books WHERE name = ${book} AND author = ${author}`);

Migrations

This module comes with a lightweight migrations API that works with SQL-based migration files

With default configuration, you can create a migrations/ directory in your project with SQL files, and call the migrate() method to run the SQL in the directory against the database.

See this project's migrations/ folder for examples.

await db.migrate({    
    /**
    * If true, will force the migration API to rollback and re-apply the latest migration over
    * again each time when Node.js app launches.
    */
    force?: boolean
    /**
    * Migrations table name. Default is 'migrations'
    */
    table?: string
    /**
    * Path to the migrations folder. Default is `path.join(process.cwd(), 'migrations')`
    */
    migrationsPath?: string
})

Typescript tricks

Import interfaces from sqlite

import { ISqlite, IMigrate } from 'sqlite'

See the definitions for more details.

Specify typings for a specific database driver

// Assuming you have @types/sqlite3 installed
import sqlite3 from 'sqlite3'

// sqlite3.Database, sqlite3.Statement is the default if no explicit generic is specified
await open<sqlite3.Database, sqlite3.Statement>({
  filename: ':memory'
})

Use generics to get better typings on your rows

Most methods allow for the use of generics to specify the data type of your returned data. This allows your IDE to perform better autocomplete and the typescript compiler to perform better static type analysis.

Get example

interface Row {
  col: string
}

// result will be of type Row, allowing Typescript supported IDEs to autocomplete on the properties!
const result = await db.get<Row>('SELECT col FROM tbl WHERE col = ?', 'test')

All example

interface Row {
  col: string
}

// Result is an array of rows, you can now have array-autocompletion data
const result = await db.all<Row[]>('SELECT col FROM tbl')

result.each((row) => {
  // row should have type information now!
})

API Documentation

See the docs directory for full documentation.

Management Tools

  • Beekeeper Studio: Open Source SQL Editor and Database Manager
  • DB Browser for SQLite: Desktop-based browser.
  • datasette: Datasette is a tool for exploring and publishing data. Starts up a server that provides a web interface to your SQLite data.
  • SQLite Studio: A free, open source, multi-platform SQLite database manager written in C++, with use of Qt framework.
  • HeidiSQL: Full-featured database editor.
  • DBeaver: Full-featured multi-platform database tool and designer.

Alternative SQLite libraries

This library and the library it primarily supports, sqlite3, may not be the best library that fits your use-case. You might want to try these other SQLite libraries:

  • better-sqlite3: Totes itself as the fastest and simplest library for SQLite3 in Node.js.
  • Bun sqlite3: bun:sqlite is a high-performance builtin SQLite3 module for bun.js.
  • sql.js: SQLite compiled to Webassembly.
  • sqlite3-offline-next: Offers pre-compiled sqlite3 binaries if your machine cannot compile it. Should be mostly compatible with this library.

If you know of any others, feel free to open a PR to add them to the list.

References

License

The MIT License © 2020-present Kriasoft / Theo Gravity. All rights reserved.


Made with ♥ by Konstantin Tarkus (@koistya), Theo Gravity and contributors

node-sqlite's People

Contributors

airportyh avatar alexandercerutti avatar alpha0010 avatar andarist avatar ar1k avatar arlac77 avatar axelterizaki avatar blakeembrey avatar danielonodje avatar dependabot[bot] avatar dtrebbien avatar haxiomic avatar iamtraction avatar kevana avatar koistya avatar lguzzon avatar linusu avatar ltrlg avatar marvinroger avatar mike-north avatar notwoods avatar paulkiddle avatar qgustavor avatar simonselg avatar subhero24 avatar taichi avatar taumechanica avatar theogravity avatar timer avatar tracker1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-sqlite's Issues

BYO sqlite3 (support sqlite3-offline)

I like node-sqlite but I keep having trouble building sqlite in my Electron app. I'd like to try using sqlite3-offline but there's not a good way to use node-sqlite with anything other than the sqlite3 package.

I can submit a pull request, but before I do the work, I'd like to know what you think about making sqlite3 an optional dependency of this package. Or perhaps splitting this package into 2:

  1. This package (bundled with sqlite3) which depends on a new package:
  2. A package that implements all the promise-adding but doesn't depend on sqlite3

Fallback to build takes long time - with no progress indicator

Hi,

In my case (Ubuntu 17.04, node 8), during install, it could not find precompiled libraries and fell back to building it. However, the build takes a long time with no progress indicators. I was not aware of this, and hit ctrl-C. Then when running a test sql node program, the import worked ok, but did a core dump.

Perhaps some progress indicator while doing the build can be useful.

Error after installing sqlite and another package afterwards

When installing sqlite and installing another package afterwards you get his error:

npm ERR! path D:\Users\charl\Desktop\Desktop\General\Dektop 2\test\node_modules.staging\npmlog-3d453044
npm ERR! code ENOENT
npm ERR! errno -4058
npm ERR! syscall rename
npm ERR! enoent ENOENT: no such file or directory, rename 'D:\Users\charl\Desktop\Desktop\General\Dektop 2\test\node_modules.staging\npmlog-3d453044' -> 'D:\Users\charl\Desktop\Desktop\General\Dektop 2\test\node_modules\sqlite3\node_modules\node-pre-gyp\node_modu
les\npmlog'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\charl\AppData\Roaming\npm-cache_logs\2017-08-25T22_48_05_520Z-debug.log

When starting an app you will get the error: Cannot find module 'npmlog'

Installation fails with node10

npm install sqlite gives the following error:

../../nan/nan_maybe_43_inl.h:112:15: error: no member named 'ForceSet' in 'v8::Object'

Suggestion: tell about building

SQLite3 Node module can be built with an sqlite3.h and a libsqlite3.so. It's convenient to get the latest SQLite3 version (ex. the actual is 3.19.2, and I built the library with the amalgation C file).

I’ve just checked the same can be done with the promisified SQLite module:

npm install -g --build-from-source --sqlite=/<some-dir>/sqlite3 sqlite

It works.

This may be useful to users to tell about this option.

Transpiled version is not included in the npm package

Hey,

the field "main" in package.json points to lib/index.js, which does not exist in the npm package.

The field should be either changed to src/index.js (which is not good tho, because the babel require hook excludes files in the node_modules folder by default from transpiling) or the transpiled version should be included in the npm package.

Regards,
Simon

db.serialize missing

I am missing db.serialize from sqlite3. According to a previous issue (#20) db.serialize can be replaced by promise chaining, but I don't see how.

Consider this code:

const sqlite = require("sqlite");

main().catch(console.error);

async function main() {
    const db = await sqlite.open(":memory:");
    await db.exec("CREATE TABLE foo (name TEXT)");

    await Promise.all([alpha(db), beta(db)]);

    console.log(await db.all("SELECT name FROM foo"));
}

async function alpha(db) {
    await db.exec("BEGIN TRANSACTION");
    await db.exec("INSERT INTO foo VALUES ('alpha')");
    await db.exec("ROLLBACK TRANSACTION");
}

async function beta(db) {
    await db.exec("INSERT INTO foo VALUES ('beta')");
}

This will print [] and not [ { name: 'beta' } ] because the beta method will be included in alpha's transaction. Can I keep alpha and beta separate without db.serialize? In this contrived example I think I could just merge the three calls to db.exec into one but if there is other code between the calls to db.exec then that is not an option.

Drop the err parameter on the `each` callback

The .each() call gets a callback for each row, and in sqlite3 that is a node-style callback with err always set to null. With promises, it's weird to have err in a callback, especially since it's not used at all.

It would be nice if the signature instead was db.each(sql, params, function(row) {}).then(...).

Need documentation for migrate.

Hi,

I just started using this library and it's great. The only thing it's lacking is more documentation on the migrate function. Can you please document what each of its parameter mean and also how migration.sql files are read and what the Up/Down sections actually mean.

Thanks!
Alvaro

Open connection using async await?

I'm quite puzzled on how to use sqlite.open with just async and await?

Is there an easier way than doing this:

Promise.resolve()
  // First, try connect to the database
  .then(() => db.open('./database.sqlite', { Promise }))
  .catch(err => console.error(err.stack))
  // Finally, launch Node.js app
  .finally(() => app.listen(port));

I tried a few ways but it kept hanging (waiting) forever.

SQLITE_ERROR not being rejected?

Hi,
I'm wondering if this is a bug with either node-sql or possibly the underlying node-sqlite3 perhaps?

In experimenting with transactions on multiple connections I ran the following test in mocha, which appears to pass with no errors. I'm basically creating two database connections but trying to begin successive transactions on just one of them, in order to force an error (which is why I'm using db1 twice rather than db2). Worryingly, the code below appears to pass with no errors shown!

Sqlite naturally balks at this and if you were to trap the error on 'transactDatabases' on the Promise.all with a .catch, it would correctly show the following error:-

{ Error: SQLITE_ERROR: cannot start a transaction within a transaction at Error (native) errno: 1, code: 'SQLITE_ERROR' }

The issue is though that I can't seem to trap this error in mocha as the Promise.all() doesn't appear to be rejected. It should be sufficient in mocha for me to return the rejected transactDatabases promise I would have thought?

Is this an error coming from Sqlite that's not being caught by the javascript libraries? Or more likely, as I'm just starting out in Javascript, am I doing something very wrong here?

The full test code is shown below...

import sqlite from 'sqlite';

describe('Sqlite', () => {
  describe('Can instantiate multiple database connections', () => {
    it.only('Can handle multiple isolated transactions', () => {
      const openDatabases = Promise.resolve()
      .then(() => Promise.all([
        sqlite.open(':memory:', { Promise }),
        sqlite.open(':memory:', { Promise }),
      ]));

      const transactDatabases = openDatabases
      .then(([db1, db2]) => {
        Promise.all([
          db1.run('BEGIN IMMEDIATE TRANSACTION'),
          db1.run('BEGIN IMMEDIATE TRANSACTION'),
        ]);
      });
      return transactDatabases;
    });
  });
});

Thanks!

Derek

Template string query throwing `SQLITE_RANGE: column index out of range`

This query runs just fine, but of course uses unescaped parameter values.

await db.run(`INSERT INTO bookings (user_id, facility_id, start, end)
  SELECT user_id, facility_id, start, end
  FROM (SELECT ${user.id} as user_id,
               ${facilityId} as facility_id,
               '${start}' AS start,
               '${end}' AS end) AS t
  WHERE NOT EXISTS (SELECT *
                    FROM bookings
  WHERE facility_id=${facilityId} AND start BETWEEN '${start}' AND '${end}')`)

Using sql-template-strings the same query fails with Error: SQLITE_RANGE: column index out of range and not further info is given.

const SQL = require('sql-template-strings')

await db.run(SQL`INSERT INTO bookings (user_id, facility_id, start, end)
  SELECT user_id, facility_id, start, end
  FROM (SELECT ${user.id} as user_id,
               ${facilityId} as facility_id,
               '${start}' AS start,
               '${end}' AS end) AS t
  WHERE NOT EXISTS (SELECT *
                    FROM bookings
  WHERE facility_id=${facilityId} AND start BETWEEN '${start}' AND '${end}')`)

The extracted values are just fine and there are 7 of them. All seems correct. Is there a way to tickle more information out of sqlite3 driver to show whats wrong?

edit

This code also runs just fine:

INSERT INTO bookings (userId, facilityId, start, end, amount)
    SELECT userId, facilityId, start, end, amount
      FROM (SELECT ? as userId,
                ? as facilityId,
                ? AS start,
                ? AS end,
                ? AS amount
           ) AS t
      WHERE NOT EXISTS (
        SELECT *
        FROM bookings
        WHERE facilityId=? AND start BETWEEN ? AND ?
      )
  `, [
    user.id,
    facilityId,
    start,
    end,
    amount,
    facilityId,
    start,
    end,
  ]

while this does not:

const rows = await db.run(`
    INSERT INTO bookings (userId, facilityId, start, end, amount)
    SELECT userId, facilityId, start, end, amount
      FROM (SELECT $user as userId,
                $facility as facilityId,
                $start AS start,
                $end AS end,
                $amount AS amount
           ) AS t
      WHERE NOT EXISTS (
        SELECT *
        FROM bookings
        WHERE facilityId=$facility AND start BETWEEN $start AND $end
      )
  `, {
    user: user.id,
    facility: facilityId,
    start,
    end,
    amount,
  })

Add REGEXP support

Hello, is it possible to add the regexp() support out of the box?
Or if there is a way to add it from other source please provide some info.
SQLITE_ERROR: no such function: regexp

Thanks

unrecognized token "{"

I want to create a discord bot, I have a column in the table whose data type is JSON
and There is a problem I have when I update this column's data.

Code:

SQLite.open(path.join(__dirname, 'profile.sql')) // Read SQL file
.then(() => {
  console.log('Opened')
  SQLite.run(`CREATE TABLE IF NOT EXISTS profileSystem (id VARCHAR(30), credits BIGINT, lastDaily BIGINT, xp BIGINT, level BIGINT, rep BIGINT, lastRep BIGINT, info TEXT, inventory JSON, profileData JSON)`)
})
.catch(err => console.error(err))

Client.on('message', async msg => { // When Bot is recived message
  if(msg.author.bot) return; // If Message author is bot dont reply to it .

  SQLite.get(`SELECT * FROM profileSystem WHERE id = '${msg.author.id}'`).then(res => {

    var s;

    let xp = Math.floor(Math.random() * (5 - 1 + 1) + 1);

    if(!res) s = `INSERT INTO profileSystem VALUES ('${msg.author.id}', 200, 0, ${xp}, 0, 0, 0, "Type ${prefix}setinfo to set info", "{}", "{wallSrc: '/walls/p2.png'}")`

    if(res) 
      s = `UPDATE profileSystem SET xp = ${xp}, level = ${lvl} WHERE id = '${msg.author.id}'`

    SQLite.run(s);

  })
})

if(cmd == 'buy') {

    let res = await SQLite.get(`SELECT * FROM profileSystem WHERE id = '${msg.author.id}'`);

    let hisWalls = res.inventory;

    let json = JSON.parse(hisWalls);

    if(!json.walls) json = {
      walls: {}
    };

    json = JSON.stringify(json);


    SQLite.run(`UPDATE profileSystem SET inventory = "${json}" WHERE id = '${msg.author.id}'`)

Error:

Error: SQLITE_ERROR: unrecognized token: "{"

sqlite3 as peer dependency to allow custom binaries

Hi,

as sqlite3 is a binary module I would like to propose to make sqlite3 a peer dependency rather than a dependency.
The reason for this is, that not all combination of runtime environments, architectures and such are available as binaries and there are cases where a manual build from source is necessary. For example with nwjs.
When installed as a peer dependency we would have full control over version and binary (if properly defined in the package.json) and we could easily run the npm install sqlite3 --build-from-source ... command.
This would also allow other packages to use the same sqlite3 version, rather than having separate version, if these package also require it as a peer.

Cheers

location of migrations folder?

Documentation is not that clear for migrations. I've stumbled upon an error that I can't wrap my head around

I'm writing a node-red module in typescript, where I like to use the migrate feature, currently I have written it like this (is Bluebird btw a pre-requisite? It's used in the examples):

        this.dbPromise = Promise.resolve()
            .then(() => open(this.file))
            .then((db) => db.migrate({}));

however, when I start nodered, which includes my module with the code above, I get the following error:

(node:17) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: ENOENT: no such file or directory, scandir '/usr/src/node-red/migrations'

I have tried several locations for the migrations folder, but none seems to be right..

Database.run(sql) should accept object as params

I'm trying to do something like:

db.run('INSERT INTO foo(name) VALUES ($name);', {name: 'bob'});

But I'm getting this error: SQLITE_RANGE: bind or column index out of range

I think it's because prepareParams always returns an array.

Error while i'm creating tables

While i'm creating tables with sqlite, i get an error
View my code:

var sql = require('sqlite')
sql.open('./db.sqlite')
sql.run("CREATE TABLE IF NOT EXISTS users (id INTEGER, diner INTEGER)")

View the error:

TypeError: Cannot read property 'run' of null

I say it to a friend, and he says me that he receives the same

db.serialize() method?

Hi, I m trying to use db.serialize(), but I couldn't. From the source code also I see it is not handled.

It is not handled because we can achieve the same with promise chaining or any reason? Thanks.

Suggestion: tell about how Database#each is promisified

The SQLite module documentation refers to the SQLite3 module documentation, which documents Database#each. After the definition of the latter, it's hard to guess how it is promisified in the SQLite module. It's rather mandatory to separately document this.

Would be nice to be able to use Promises as values

E.g. to have this code working as expected:

Promise.resolve(
).then(() => db.open('test.sqlite', { Promise })
).then(() => db.run('DROP TABLE t')
).then(() => db.run('CREATE TABLE t (a, b, c)')
).then(() => db.run('INSERT INTO t VALUES (?, ?, ?)', [ 1, Promise.resolve('test'), 2 ])
).then(() => db.get('SELECT * FROM t')
).then(row => console.log(row));

I made a quick test and it should be as easy as wrapping params in a Promise.all call:

  run(sql) {
    const Promise = this.Promise;
    return Promise.all(prepareParams(arguments, { offset: 1 })
    ).then(params => {
      return new Promise((resolve, reject) => {
        this.driver.run(sql, params, function runExecResult(err) {
          if (err) {
            reject(err);
          } else {
            // Per https://github.com/mapbox/node-sqlite3/wiki/API#databaserunsql-param--callback
            // when run() succeeds, the `this' object is a driver statement object. Wrap it as a
            // Statement.
            resolve(new Statement(this, Promise));
          }
        });
      });
    });
  }

Maybe steer people away from using the global db

Using globals variables are a bad practice for a number of reasons. In this case specifically it can have strange consequences if a library makes use of sqlite. If the application, or another library, also does that. They will most likely try and write to the same database instead of their separate ones which can make all sort of things go wrong.

A great first step I think would be to change the readme to point people to capture the output from db.open instead of throwing it away and using the global db.

How about something like the following?

import sqlite from 'sqlite'
import express from 'express'

const app = express()
const dbPromise = sqlite.open('database.sqlite').then(db => db.migrate())

app.get('/post/:id', async (req, res, next) => {
  try {
    const db = await dbPromise

    const [post, categories] = await Promise.all([
      db.get('SELECT * FROM Post WHERE id = ?', req.params.id),
      db.all('SELECT * FROM Category')
    ])

    res.render('post', { post, categories })
  } catch (err) {
    next(err)
  }
})

app.listen(/* ... */)

Long term I would love it if the global db could be dropped in the next major version...

Error:% 1 is not a valid Win32 application

i keep reciving this after trying to run my discord bot:
C:\Users\AyoubMadrid\Desktop\Mayumi-San>node fix.js
module.js:598
return process.dlopen(module, path._makeLong(filename));
^

Error: %1 n�est pas une application Win32 valide.
\?\C:\Users\AyoubMadrid\Desktop\Mayumi-San\node_modules\sqlite3\lib\binding\node-v57-win32-x64\node_sqlite3.node
at Object.Module._extensions..node (module.js:598:18)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object. (C:\Users\AyoubMadrid\Desktop\Mayumi-San\node_modules\sqlite3\lib\sqlite3.js:4:15)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)

C:\Users\AyoubMadrid\Desktop\Mayumi-San>node fix.js
module.js:598
return process.dlopen(module, path._makeLong(filename));
^

Error: %1 n�est pas une application Win32 valide.
\?\C:\Users\AyoubMadrid\Desktop\Mayumi-San\node_modules\sqlite3\lib\binding\node-v57-win32-x64\node_sqlite3.node
at Object.Module._extensions..node (module.js:598:18)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object. (C:\Users\AyoubMadrid\Desktop\Mayumi-San\node_modules\sqlite3\lib\sqlite3.js:4:15)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)

Install of Babel needed?

When trying your sqlite package, I run into issues with Babel.
ReferenceError: babelHelpers is not definedCan you help?

More specific:
C:\Users\Johan\node_only\node-sqlite\node_modules\sqlite\legacy.js:39
babelHelpers.createClass(Statement, [{
^
ReferenceError: babelHelpers is not defined

On my windows, I see Node.js versin 4.4.7.
npm install -g babel-cli.
Same error applies.

TypeError: db.get is not a function

I get an error when I try to run a query.

Code:

const sqlite = require('sqlite');
const db = sqlite.open('./database.sqlite');

db.get(`SELECT * FROM database`).then((result) => {
	console.log(result);
});

What am I doing wrong ?

SyntaxError under Node 4.x

Although I am using Promises, it seems that this module has strict requirements on Node 6.x, because it fails quickly when run on Node 4/x:

./node_modules/sqlite/main.js:16
function prepareParams(args, { offset = 0, excludeLastArg = false } = {}) {
                             ^

SyntaxError: Unexpected token {

I would suggest to either set default parameter values using an ES5-compatible way (prefered, so that I can use it) or to state in the package.json that node-sqlite is strictly compatible with Node 6.x & beyond:

  "engineStrict" : true,
  "engines" : {
    "node" : ">=6"
   },

Run method should resolve with the statement object

When doing an insert/update using run(), I'm unable to get the status of the execution back as noted in:

https://github.com/mapbox/node-sqlite3/wiki/API#databaserunsql-param--callback

 The context of the function (the this object inside the function) is the statement object. 

The problem:
https://github.com/kriasoft/node-sqlite/blob/master/src/Database.js#L43

The callback is using the arrow function, so this is the reference to the class instance itself instead of the statement object

How to trace SQL errors?

I'm getting unhelpful error:

{ Error: SQLITE_RANGE: bind or column index out of range

 errno: 25, code: 'SQLITE_RANGE' }

How can I trace it? According to the documentation of node-sqlite3 I can attach a callback to trace event to see the SQL being sent to the DB, but your wrapper doesn't seem to have on method:

TypeError: db.on is not a function

A minor update to TypeScript definitions

With the current TypeScript definitions, it's not possible to declare a function with a parameter of type Database or Statement.

Please, update the file main.d.ts to export them as interfaces:

declare module 'sqlite' {
  export interface Statement {
    readonly sql: string;
    readonly lastID: number;
    readonly changes: number;

    bind(): Promise<Statement>;
    bind(...params: any[]): Promise<Statement>;

    reset(): Promise<Statement>;

    finalize(): Promise<void>;

    run(): Promise<Statement>;
    run(...params: any[]): Promise<Statement>;

    get(): Promise<any>;
    get(...params: any[]): Promise<any>;

    all(): Promise<any[]>;
    all(...params: any[]): Promise<any[]>;

    each(callback?: (err: Error, row: any) => void): Promise<number>;
    each(...params: any[]): Promise<number>;
  }

  export interface Database {
    close(): Promise<void>;

    run(sql: string): Promise<Statement>;
    run(sql: string, ...params: any[]): Promise<Statement>;

    get(sql: string): Promise<any>;
    get(sql: string, ...params: any[]): Promise<any>;

    all(sql: string): Promise<any[]>;
    all(sql: string, ...params: any[]): Promise<any[]>;

    exec(sql: string): Promise<Database>;

    each(sql: string, callback?: (err: Error, row: any) => void): Promise<number>;
    each(sql: string, ...params: any[]): Promise<number>;

    prepare(sql: string): Promise<Statement>;
    prepare(sql: string, ...params: any[]): Promise<Statement>;

    migrate(options: { force?: boolean, table?: string, migrationsPath?: string }): Promise<Database>;
  }

  export function open(filename: string, options?: { mode?: number, verbose?: boolean, promise?: typeof Promise }): Promise<Database>;
  export default { open }
}

Notice: I leave the last line export default { open } but it is invalid. There is actually no member default in the module. I think it should be removed.

Unclean builds

Don't know why the download of the pre-built binary didn't work (Ubuntu 14.04 system), but the build had lots of warnings and notes:

make: Entering directory `/data/info/prj/bookmark_count/node_modules/sqlite/node_modules/sqlite3/build'
ACTION deps_sqlite3_gyp_action_before_build_target_unpack_sqlite_dep Release/obj/gen/sqlite-autoconf-3090100/sqlite3.c
TOUCH Release/obj.target/deps/action_before_build.stamp
CC(target) Release/obj.target/sqlite3/gen/sqlite-autoconf-3090100/sqlite3.o
AR(target) Release/obj.target/deps/sqlite3.a
COPY Release/sqlite3.a
CXX(target) Release/obj.target/node_sqlite3/src/database.o
../src/database.cc: In static member function ‘static void node_sqlite3::Database::Work_BeginOpen(node_sqlite3::Database::Baton_)’:
../src/database.cc:143:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/database.cc: In static member function ‘static void node_sqlite3::Database::Work_BeginClose(node_sqlite3::Database::Baton_)’:
../src/database.cc:227:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/database.cc: In static member function ‘static void node_sqlite3::Database::Work_BeginExec(node_sqlite3::Database::Baton_)’:
../src/database.cc:505:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/database.cc: In static member function ‘static void node_sqlite3::Database::Work_BeginLoadExtension(node_sqlite3::Database::Baton_)’:
../src/database.cc:605:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
CXX(target) Release/obj.target/node_sqlite3/src/node_sqlite3.o
CXX(target) Release/obj.target/node_sqlite3/src/statement.o
../src/statement.cc: In static member function ‘static void node_sqlite3::Statement::Work_BeginPrepare(node_sqlite3::Database::Baton_)’:
../src/statement.cc:118:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
In file included from ../src/statement.cc:6:0:
../src/statement.cc: In static member function ‘static void node_sqlite3::Statement::Work_BeginBind(node_sqlite3::Statement::Baton_)’:
../src/macros.h:125:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/statement.cc:322:5: note: in expansion of macro ‘STATEMENT_BEGIN’
STATEMENT_BEGIN(Bind);
^
../src/statement.cc: In static member function ‘static void node_sqlite3::Statement::Work_BeginGet(node_sqlite3::Statement::Baton_)’:
../src/macros.h:125:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/statement.cc:370:5: note: in expansion of macro ‘STATEMENT_BEGIN’
STATEMENT_BEGIN(Get);
^
../src/statement.cc: In static member function ‘static void node_sqlite3::Statement::Work_BeginRun(node_sqlite3::Statement::Baton_)’:

../src/macros.h:125:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/statement.cc:438:5: note: in expansion of macro ‘STATEMENT_BEGIN’
STATEMENT_BEGIN(Run);
^
../src/statement.cc: In static member function ‘static void node_sqlite3::Statement::Work_BeginAll(node_sqlite3::Statement::Baton_)’:
../src/macros.h:125:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/statement.cc:504:5: note: in expansion of macro ‘STATEMENT_BEGIN’
STATEMENT_BEGIN(All);
^
../src/statement.cc: In static member function ‘static void node_sqlite3::Statement::Work_BeginEach(node_sqlite3::Statement::Baton_)’:
../src/macros.h:125:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/statement.cc:601:5: note: in expansion of macro ‘STATEMENT_BEGIN’
STATEMENT_BEGIN(Each);
^
../src/statement.cc: In static member function ‘static void node_sqlite3::Statement::Work_BeginReset(node_sqlite3::Statement::Baton*)’:
../src/macros.h:125:9: warning: unused variable ‘status’ [-Wunused-variable]
int status = uv_queue_work(uv_default_loop(),
^
../src/statement.cc:724:5: note: in expansion of macro ‘STATEMENT_BEGIN’
STATEMENT_BEGIN(Reset);
^
SOLINK_MODULE(target) Release/obj.target/node_sqlite3.node
COPY Release/node_sqlite3.node
COPY /data/info/prj/bookmark_count/node_modules/sqlite/node_modules/sqlite3/lib/binding/node-v46-linux-ia32/node_sqlite3.node
TOUCH Release/obj.target/action_after_build.stamp
make: Leaving directory `/data/info/prj/bookmark_count/node_modules/sqlite/node_modules/sqlite3/build'
[email protected] node_modules/sqlite
└── [email protected] ([email protected])

BUG: Database.migrate() removes useful lines from scripts

Description

If a migration script contains a line which starts with -- which is inside an actual string value, it will be considered as a comment and thus removed from the eventual script.

Steps to reproduce

Considering this migration script:

-- Up
CREATE TABLE whatever ( certificate TEXT );
INSERT INTO whatever ( certificate ) VALUES (
  '-----BEGIN CERTIFICATE-----
some contents
-----END CERTIFICATE-----');

-- Down
DROP TABLE whatever;

calling db.migrate() will fail due to a syntax error

Explanation

Calling db.migrate() will parse the up script, and will remove the line -----END CERTIFICATE-----'); because it starts with --.

Code which causes this problem: https://github.com/kriasoft/node-sqlite/blob/master/src/Database.js#L170

migration.up = up.replace(/^--.*?$/gm, '').trim();

string parameter with only numbers is coerced into number

This seems to be introduced by node-sqlite, because node-sqlite3 does not have the issue:

First with node-sqlite3:

$ node
> var sqlite3 = require('sqlite3').verbose()
undefined
> var db = new sqlite3.Database(':memory:');
undefined
db.run(`CREATE TABLE "testing"("id" STRING PRIMARY KEY, json JSON)`)
Database { open: true, filename: ':memory:', mode: 65542 }
> db.run(`INSERT OR REPLACE
...             INTO
...                 "testing"("id","json")
...             VALUES(?,?)`, [ '234234239874972349872342', '{}' ])
Database { open: true, filename: ':memory:', mode: 65542 }
> db.all("select * from testing",console.log)
Database { open: true, filename: ':memory:', mode: 65542 }
> null [ { id: '2340912837409871234098734', j: '{}'} ]

Notice that id is now a string

vs sqlite:

> s = require('sqlite')
Database { driver: null, Promise: [Function: Promise], open: [Function] }
> let d
undefined
> s.open(':memory:).then(db => d = db)
> d.all(`CREATE TABLE "testing"("id" STRING PRIMARY KEY, json JSON)`)
Promise {...
> d.all(`INSERT OR REPLACE
... 			INTO
... 				"testing"("id","json")
... 			VALUES(?,?)`, [ '234234239874972349872342', '{}' ])
Promise {...
> d.all(`select * from testing`).then(console.log)
Promise {...
> [ { id: 2.3423423987497237e+23, json: '{}' } ]

Feature: Support ES6 Tagged template literals

See: Tagged template literals

example:

var result = db.get`
  SELECT * 
  FROM demo
  WHERE id = ${this.id}
`;
var results = db.all(`
  ...
`)

For implementation...

function all(query, ...values) {
  if (Array.isArray(query)) {
    query = query.join('?');
  } else {
    values = values[0];
  }
  ... original implementation follows ...
}

Exception on INSERT inside loop when trying to retrieve lastID

I’m attempting to use the node-sqlite package. I need to bulk insert rows and get the autoincremented id back. It seems to work when I do one, but in a loop, it fails. Can you help with this or point me in the right direction? Thank you in advance for any help you might have to offer.

// forecastLocation.js
const sql = require('./database');

function ForecastLocation() {
}

ForecastLocation.save = async function (forecastLocations) {

try {
sql.sqlite.run('begin transaction');

for (let forecastLocation of forecastLocations) {
  let newDate = new Date();
  newDate = newDate.toISOString();
  let parameters = [forecastLocation.forecastId,
  forecastLocation.lat,
  forecastLocation.lon,
    newDate,
    newDate];

  try {          
      let result = await Promise.resolve(sql.sqlite.run(insertStmt, parameters));
      console.log(result); // contains lastID
  } catch (err) {
    console.log(err);
    throw (err);
  }
}

} catch (err) {
console.log(err);
} finally {
sql.sqlite.run('end');
}
}

// database.js
"use strict"
const path = require('path');
const Promise = require('bluebird');
const sqlite = require('sqlite/legacy');

function Database() {
}

Database.open = function() {
let filePath = path.join(__dirname, "../../../");
filePath = path.join(filePath, "resources/db/database-dev.sqlite");
return sqlite.open(filePath, { Promise });
}

Database.close = function() {
sqlite.close();
}

module.exports = {Database, sqlite};

// stack trace
Registered protocol succesfully
3277
://eca/
Statement {
stmt:
Statement {
sql: 'INSERT INTO ForecastLocations (forecastId, lat, lon, createdAt, updatedAt) VALUES (?,?,?,?,?)',
lastID: 1,
changes: 1 },
Promise:
{ [Function: Promise]
TypeError: [Function: TypeError],
RangeError: [Function: RangeError],
CancellationError: [Function: SubError],
TimeoutError: [Function: SubError],
OperationalError: [Function: OperationalError],
RejectionError: [Function: OperationalError],
AggregateError: [Function: SubError],
_peekContext: [Function],
onPossiblyUnhandledRejection: [Function],
onUnhandledRejectionHandled: [Function],
longStackTraces: [Function],
hasLongStackTraces: [Function],
config: [Function],
getNewLibraryCopy: [Function],
is: [Function],
fromCallback: [Function],
fromNode: [Function],
all: [Function],
cast: [Function],
fulfilled: [Function],
resolve: [Function],
rejected: [Function],
reject: [Function],
setScheduler: [Function],
pending: [Function],
defer: [Function],
method: [Function],
try: [Function],
attempt: [Function],
bind: [Function],
PromiseInspection: [Function: PromiseInspection],
join: [Function],
Promise: [Circular],
version: '3.5.0',
map: [Function],
using: [Function],
delay: [Function],
coroutine: { [Function] addYieldHandler: [Function] },
spawn: [Function],
promisify: [Function],
promisifyAll: [Function],
props: [Function],
race: [Function],
reduce: [Function],
settle: [Function],
some: [Function],
_SomePromiseArray: [Function: SomePromiseArray],
filter: [Function],
each: [Function],
mapSeries: [Function: PromiseMapSeries],
any: [Function],
noConflict: [Function: noConflict] } }
TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined
at Function._callee2$ (C:/git/onboard/onboard/electron-out/project/ember-electron/main/api/models/forecastLocation.j
s:68:7)
at tryCatch (C:\git\onboard\onboard\node_modules\regenerator-runtime\runtime.js:65:40)
at Generator.invoke [as _invoke] (C:\git\onboard\onboard\node_modules\regenerator-runtime\runtime.js:303:22)
at Generator.prototype.(anonymous function) [as next] (C:\git\onboard\onboard\node_modules\regenerator-runtime\runti
me.js:117:21)
at tryCatch (C:\git\onboard\onboard\node_modules\regenerator-runtime\runtime.js:65:40)
at invoke (C:\git\onboard\onboard\node_modules\regenerator-runtime\runtime.js:155:20)
at C:\git\onboard\onboard\node_modules\regenerator-runtime\runtime.js:165:13
(node:3052) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: forecast.getFore
castLocations is not a function
(node:3052) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are
not handled will terminate the Node.js process with a non-zero exit code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.