• Stars
    star
    209
  • Rank 182,214 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 11 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

sqlite for node.js without gyp problems

dblite

Build Status

Deprecated

This module served me well to date but it's overly complicated for very little real-world gain or reasons to be so.

Please consider sqlite-tag-spawned as modern, safe, as fast as this module is, alternative, as I am not planning to improve much in here from now on, thank you!


a zero hassle wrapper for sqlite

var dblite = require('dblite'),
    db = dblite('file.name');

// Asynchronous, fast, and ...
db.query('SELECT * FROM table', function(err, rows) {
  // ... that easy!
});

More in the related blogpost and here too :-)

Updates

Version 0.7.5 forces -noheader flag if there is no explicit -header flag so that no matter what, headers will not be used.

This will eventually overwrite the .sqliterc but will make the library behavior more consistent across platforms.

Please check issue 35 to know more.


Previously, in sqlite3 version 3.8.6 you need a "new line agnostic" version of dblite, used in dblite version 0.6.0.

This breaks compatibility with older version of the database cli but this problem should have been fixed in 0.7.0.

// old version
var dblite = require('dblite');

// 3.8.6 version
var dblite = require('dblite').withSQLite('3.8.6+');

// new version, same as old one
var dblite = require('dblite');

It seems that sqlite3 version 3.8.8+ introduced a new line \n on Windows machines too so the whole initialization is now performed asynchronously and through features detection.

This should fix the annoying EOL problem "forevar"

The What And The Why

I've created dblite module because there's still not a simple and straight forward or standard way to have sqlite in node.js without requiring to re-compile, re-build, download sources a part or install dependencies instead of simply apt-get install sqlite3 or pacman -S sqlite3 in your *nix system.

dblite has been created with portability, simplicity, and reasonable performance for embedded Hardware such ARM boards, Raspberry Pi, Arduino Yun, Atmel MIPS CPUs or Linino boards in mind.

Generally speaking all linux based distributions like Arch Linux, where is not always that easy to node-gyp a module and add dependencies that work, can now use this battle tested wrap and perform basic to advanced sqlite operations.

Bootstrap

To install dblite simply npm install dblite then in node:

var dblite = require('dblite'),
    db = dblite('/folder/to/file.sqlite');

// ready to go, i.e.
db.query('.databases');
db.query(
  'SELECT * FROM users WHERE pass = ?',
  [pass],
  function (err, rows) {
    var user = rows.length && rows[0];
  }
);

By default the dblite function uses sqlite3 as executable. If you need to change the path simply update dblite.bin = "/usr/local/bin/sqlite3"; before invoking the function.

API

Right now a created EventEmitter db instance has 3 extra methods: .query(), .lastRowID(), and .close().

The .lastRowID(table, callback(rowid)) helper simplifies a common operation with SQL tables after inserts, handful as shortcut for the following query: SELECT ROWID FROM ``table`` ORDER BY ROWID DESC LIMIT 1.

The method .close() does exactly what it suggests: it closes the database connection. Please note that it is not possible to perform other operations once it has been closed.

Being an EventEmitter instance, the database variable will be notified with the close listener, if any.

Understanding The .query() Method

The main role in this module is played by the db.query() method, a method rich in overloads all with perfect and natural meaning.

The amount of parameters goes from one to four, left to right, where left is the input going through the right which is the eventual output.

All parameters are optionals except the SQL one.

db.query() Possible Combinations

db.query(SQL)
db.query(SQL, callback:Function)
db.query(SQL, params:Array|Object)
db.query(SQL, fields:Array|Object)
db.query(SQL, params:Array|Object, callback:Function)
db.query(SQL, fields:Array|Object, callback:Function)
db.query(SQL, params:Array|Object, fields:Array|Object)
db.query(SQL, params:Array|Object, fields:Array|Object, callback:Function)

All above combinations are tested properly in this file together with many other tests able to make dblite robust enough and ready to be used.

Please note how params is always before fields and/or callback if fields is missing, just as reminder that order is left to right accordingly with what we are trying to do.

Following detailed explanation per each parameter.

The SQL:string

This string accepts any query understood by SQLite plus it accepts all commands that regular SQLite shell would accept such .databases, .tables, .show and all others passing through the specified info listener, if any, using just the console as fallback otherwise.

var dblite = require('dblite'),
    db = dblite('./db.sqlite');

// will call the implicit `info` console.log
db.query('.show');
/* will console.log something like:

     echo: off
  explain: off
  headers: off
     mode: csv
nullvalue: ""
   output: stdout
separator: ","
    stats: off
    width:
*/

// normal query
db.query('CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, value TEXT)');
db.query('INSERT INTO test VALUES(null, ?)', ['some text']);
db.query('SELECT * FROM test');
// will implicitly log the following
// [ [ '1', 'some text' ] ]
Warning!

This library heavily relies on strings and it normalizes them through special escaping which aim is to make passed data safe and secure which should be goal #1 of each db oriented API.

Please do not pass datamanually like INSERT INTO table VALUES (null, '[email protected]') and always use, specially for any field that contains strings, the provided API: INSERT INTO table VALUES (null, '@email') and {emaiL: '[email protected]'}. These kind of operations are described in the following paragraphs.

The params:Array|Object

If the SQL string contains special chars such ?, :key, $key, or @key properties, these will be replaced accordingly with the params Array or Object that, in this case, MUST be present.

// params as Array
db.query('SELECT * FROM test WHERE id = ?', [1]);

// params as Object
db.query('SELECT * FROM test WHERE id = :id', {id:1});
// same as
db.query('SELECT * FROM test WHERE id = $id', {id:1});
// same as
db.query('SELECT * FROM test WHERE id = @id', {id:1});

The fields:Array|Object

By default, results are returned as an Array where all rows are the outer Array and each single row is another Array.

db.query('SELECT * FROM test');
// will log something like:
[
  [ '1', 'some text' ],     // row1
  [ '2', 'something else' ] // rowN
]

If we specify a fields parameter we can have each row represented by an object, instead of an array.

// same query using fields as Array
db.query('SELECT * FROM test', ['key', 'value']);
// will log something like:
[
  {key: '1', value: 'some text'},     // row1
  {key: '2', value: 'something else'} // rowN
]

Parsing Through The fields:Object

SQLite Datatypes are different from JavaScript plus SQLite works via affinity. This module also parses sqlite3 output which is always a string and as string every result will always be returned unless we specify fields parameter as object, suggesting validation per each field.

// same query using fields as Object
db.query('SELECT * FROM test', {
  key: Number,
  value: String
});
// note the key as integer!
[
  {key: 1, value: 'some text'},     // row1
  {key: 2, value: 'something else'} // rowN
]

More complex validators/transformers can be passed without problems:

// same query using fields as Object
db.query('SELECT * FROM `table.users`', {
  id: Number,
  name: String,
  adult: Boolean,
  skills: JSON.parse,
  birthday: Date,
  cube: function (fieldValue) {
    return fieldValue * 3;
  }
});

The params:Array|Object AND The fields:Array|Object

Not a surprise we can combine both params, using the left to right order input to output so params first!

// same query using params AND fields
db.query('SELECT * FROM test WHERE id = :id', {
  id: 1
},{
  key: Number,
  value: String
});

// same as...
db.query('SELECT * FROM test WHERE id = ?', [1], ['key', 'value']);
// same as...
db.query('SELECT * FROM test WHERE id = ?', [1], {
  key: Number,
  value: String
});
// same as...
db.query('SELECT * FROM test WHERE id = :id', {
  id: 1
}, [
  'key', 'value'
]);

The callback:Function

When a SELECT or a PRAGMA SQL is executed the module puts itself in a waiting for results state.

Update - Starting from 0.4.0 the callback will be invoked with err and data if the callback length is greater than one. function(err, data){} VS function(data){}. However, latter mode will keep working in order to not break backward compatibility. Update - Starting from 0.3.3 every other SQL statement will invoke the callback after the operation has been completed.

As soon as results are fully pushed to the output the module parses this result, if any, and send it to the specified callback.

The callback is always the last specified parameter, if any, or the implicit equivalent of console.log.bind(console). Latter case is simply helpful to operate directly via node console and see results without bothering writing a callback each .query() call.

Extra Bonus: JSON Serialization With fields:Array|Object

If one field value is not scalar (boolean, number, string, null) JSON.stringify is performed in order to save data. This helps lazy developers that don't want to pre parse every field and let dblite do the magic.

// test has two fields, id and value
db.query('INSERT INTO test VALUES(?, ?)', [
  123,
  {name: 'dblite', rate: 'awesome'} // value serialized
]);

// use the fields to parse back the object
db.query('SELECT * FROM test WHERE id = ?', [123], {
  id: Number,
  value: JSON.parse // value unserialized
}, function (err, rows) {
  var record = rows[0];
  console.log(record.id); // 123
  console.log(record.value.name); // "dblite"
  console.log(record.value.rate); // "awesome""
});

Automatic Fields Through Headers

Since version 0.3.0 it is possible to enable automatic fields parsing either through initialization (suggested) or at runtime.

var dblite = require('dblite'),
    // passing extra argument at creation
    db = dblite('file.name', '-header');

db.query('SELECT * FROM table', function(err, rows) {
  rows[0]; // {header0: value0, headerN: valueN}
});

// at runtime
db
  .query('.headers ON')
  .query('SELECT * FROM table', function(err, rows) {
    rows[0]; // {header0: value0, headerN: valueN}
  })
  .query('.headers OFF')
;

In version 0.3.2 a smarter approach for combined headers/fields is used where the right key order is granted by headers but it's possible to validate known fields too.

var db = require('dblite')('file.name', '-header');

db.query('SELECT 1 as one, 2 as two', {two:Number}, function(err, rows) {
  rows[0]; // {one: "1", two: 2} // note "1" as String
});

In this way these two options can be supplementary when and if necessary.

Handling Infos And Errors - Listeners

The EventEmitter will notify any listener attached to info, error, or close accordingly with the current status.

db.on('info', function (data) {
  // show data returned by special syntax
  // such: .databases .tables .show and others
  console.log(data);
  // by default, it does the same
});

db.on('error', function (err) {
  // same as `info` but for errors
  console.error(err.toString());
  // by default, it does the same
});

db.on('close', function (code) {
  // by default, it logs "bye bye"
  // invoked once the database has been closed
  // and every statement in the queue executed
  // the code is the exit code returned via SQLite3
  // usually 0 if everything was OK
  console.log('safe to get out of here ^_^_');
});

Please note that error is invoked only if the callback is not handling it already via double argument.

The close event ensures that all operations have been successfully performed and your app is ready to exit or move next.

Please note that after invoking db.close() any other query will be ignored and the instance will be put in a waiting to complete state which will invoke the close listener once operations have been completed.

Raspberry Pi Performance

This is the output generated after a make test call in this repo folder within Arch Linux for RPi.

npm test

> [email protected] test /home/dblite
> node test/.test.js

/home/dblite/dblite.test.sqlite
------------------------------
main
passes: 1, fails: 0, errors: 0
------------------------------
create table if not exists
passes: 1, fails: 0, errors: 0
------------------------------
100 sequential inserts
100 records in 3.067 seconds
passes: 1, fails: 0, errors: 0
------------------------------
1 transaction with 100 inserts
200 records in 0.178 seconds
passes: 1, fails: 0, errors: 0
------------------------------
auto escape
passes: 1, fails: 0, errors: 0
------------------------------
auto field
fetched 201 rows as objects in 0.029 seconds
passes: 1, fails: 0, errors: 0
------------------------------
auto parsing field
fetched 201 rows as normalized objects in 0.038 seconds
passes: 1, fails: 0, errors: 0
------------------------------
many selects at once
different selects in 0.608 seconds
passes: 1, fails: 0, errors: 0
------------------------------
db.query() arguments
[ [ '1' ] ]
[ [ '2' ] ]
[ { id: 1 } ]
[ { id: 2 } ]
passes: 5, fails: 0, errors: 0
------------------------------
utf-8
¥ · £ · € · $ · ¢ · ₡ · ₢ · ₣ · ₤ · ₥ · ₦ · ₧ · ₨ · ₩ · ₪ · ₫ · ₭ · ₮ · ₯ · ₹
passes: 1, fails: 0, errors: 0
------------------------------
erease file
passes: 1, fails: 0, errors: 0

------------------------------
          15 Passes
------------------------------

If an SD card can do this good, I guess any other environment should not have problems here ;-)

F.A.Q.

Here a list of probably common Q&A about this module. Please do not hesitate to ask me more, if necessary, thanks.

  • How Does It Work? dblite uses a spawned version of the sqlite3 executable. It could theoretically work with any other SQL like database but it's tested with sqlite3-shell only

  • Does It Spawn Per Each Query? this is a quick one: NO! dblite spawns once per each database file where usually there is only one database file opened per time.

  • How About Memory And Performance? Accordingly with node manual:

    These child Nodes are still whole new instances of V8. Assume at least 30ms startup and 10mb memory for each new Node. That is, you cannot create many thousands of them.

    Since dblite spawns only once, there is a little overhead during the database initialization but that's pretty much it, the amount of RAM increases with the amount of data we save or retrieve from the database. The above Raspberry Pi Benchmark should ensure that with most common operation, and using transactions where possible, latency and RAM aren't a real issue.

  • Why Not The Native One? I had some difficulty installing this node-sqlite3 module due node-gyp incompatibilities with some ARM based device in both Debian and ArchLinux. Since I really needed an sqlite manager for the next version of polpetta which aim is to have a complete, lightweight, and super fast web server in many embedded hardware such RPi, Cubieboard, and others, and since I needed something able to work with multiple core too, I've decided to try this road wrapping the native, easy to install and update, sqlite3 shell client and do everything I need. So far, so good I would say ;-)

  • Isn't params and fields an ambiguous choice? At the very beginning I wasn't sure myself if that would have worked as API choice but later on I've changed my mind. First of all, it's very easy to spot special chars in the SQL statement. If present, params is mandatory and used, as easy as that. Secondly, if an object has functions as value, it's obviously a fields object, 'cause params cannot contains functions since these are not compatible with JSON serialization, neither meaningful for the database. The only case where fields might be confused with params is when no params has been specified, and fields is an Array. In this case I believe you are the same one that wrote the SQL too and know upfront if there are fields to retrieve from params or not so this is actually a non real-world problem and as soon as you try this API you'll realize it feels intuitive and right.

  • Are Transactions Supported? ... YES, transactions are supported simply performing multiple queries as you would do in sqlite3 shell:

  db.query('BEGIN TRANSACTION');
  for(var i = 0; i < 100; i++) {
    db.query('INSERT INTO table VALUES(?, ?)', [null, Math.random()]);
  }
  db.query('COMMIT');

The test file has a transaction with 100 records in it, have a look.

  • Can I Connect To A :memory: Database? well, you can do anything you would do with sqlite3 shell so YES
var db = dblite(':memory:'); // that's it!

License

The usual Mit Style, thinking about the WTFPL though ... stay tuned for updates.

Copyright (C) 2013 by WebReflection

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

More Repositories

1

hyperHTML

A Fast & Light Virtual DOM Alternative
HTML
3,028
star
2

linkedom

A triple-linked lists based DOM implementation.
HTML
1,156
star
3

document-register-element

A stand-alone working lightweight version of the W3C Custom Elements specification
JavaScript
1,131
star
4

dom4

Modern DOM functionalities for every browser
JavaScript
929
star
5

flatted

A fast and minimal circular JSON parser.
JavaScript
893
star
6

url-search-params

Simple polyfill for URLSearchParams standard
JavaScript
765
star
7

uhtml

A micro HTML/SVG render
JavaScript
707
star
8

lighterhtml

The hyperHTML strength & experience without its complexity 🎉
JavaScript
702
star
9

JSONH

Homogeneous Collection Compressor
JavaScript
618
star
10

circular-json

JSON does not handle circular references. Now it does
JavaScript
599
star
11

viperHTML

Isomorphic hyperHTML
JavaScript
318
star
12

heresy

React-like Custom Elements via V1 API builtin extends.
JavaScript
271
star
13

es6-collections

Map, WeakMap, and Set fast/simple shim for Harmony collections
JavaScript
253
star
14

neverland

React like Hooks for lighterhtml
JavaScript
241
star
15

wicked-elements

Components for the DOM as you've never seen before
JavaScript
235
star
16

eddy

Event Driven JS
JavaScript
211
star
17

domdiff

Diffing the DOM without virtual DOM
JavaScript
197
star
18

hyperHTML-Element

An extensible class to define hyperHTML based Custom Elements.
JavaScript
195
star
19

benja

Bootable Electron Node JS Application
194
star
20

uce

µhtml based Custom Elements
JavaScript
183
star
21

usignal

A blend of @preact/signals-core and solid-js basic reactivity API
JavaScript
176
star
22

highlighted-code

A textarea builtin extend to automatically provide code highlights based on one of the languages available via highlight.js
HTML
172
star
23

restyle

JavaScript
167
star
24

testardo

a browser and OS agnostic web driver for mobile and desktop
JavaScript
166
star
25

sqlite-worker

A simple, and persistent, SQLite database for Web and Workers.
JavaScript
159
star
26

augmentor

Extensible, general purpose, React like hooks for the masses.
JavaScript
135
star
27

uhooks

micro hooks: a minimalistic client/server hooks' implementation
JavaScript
127
star
28

polpetta

Polpetta, any folder is served spiced
JavaScript
125
star
29

basicHTML

A NodeJS based, standard oriented, HTML implementation.
JavaScript
123
star
30

udomdiff

An essential diffing algorithm for µhtml.
JavaScript
117
star
31

pocket.io

A minimalistic version of socket.io that weights about 1K instead of 60K.
JavaScript
112
star
32

caller-of

The tiniest yet most powerful JS utility ever :D
HTML
102
star
33

uland

A µhtml take at neverland
JavaScript
101
star
34

uce-template

A Vue 3 inspired Custom Elements toolless alternative.
JavaScript
100
star
35

json.hpack

JSON Homogeneous Collections Packer
C#
95
star
36

html-escaper

A module to escape/unescape common problematic entities done the right way.
JavaScript
95
star
37

wru

essential unit test framework
JavaScript
95
star
38

udomsay

A stricter, signals driven, ESX based library
JavaScript
95
star
39

db

JavaScript
94
star
40

import.js

A dynamic import() polyfill
JavaScript
93
star
41

regular-elements

Custom Elements made available for any node, and through CSS selectors
JavaScript
91
star
42

proxy-pants

Secured and reliable Proxy based utilities for more or less common tasks.
JavaScript
90
star
43

ucompress

A micro, all-in-one, compressor for common Web files.
JavaScript
90
star
44

archibold.io

archibold.io
Shell
85
star
45

jsgtk

A simplified approach to GJS for Node.JS and JavaScript developers.
JavaScript
85
star
46

heresy-ssr

🔥 heresy 🔥 Server Side Rendering
JavaScript
84
star
47

hypersimple

The easiest way to use hyperHTML
JavaScript
83
star
48

asbundle

A minimalistic JS bundler
JavaScript
77
star
49

introspected

Introspection for serializable arrays and JSON friendly objects.
HTML
77
star
50

node-gtk

GNOME Gtk+ bindings for NodeJS
C++
74
star
51

i18n-utils

The i18n tag function utilitities
JavaScript
73
star
52

viper-news

viperHTML version of the Hacker News app.
JavaScript
72
star
53

ucdn

A µcompress based CDN utility, compatible with both Express and native http module
JavaScript
67
star
54

electroff

A cross browser, electron-less helper, for IoT projects and standalone applications.
JavaScript
64
star
55

builtin-elements

A zero friction custom elements like primitive.
JavaScript
62
star
56

nonchalance

The easiest way to augment DOM builtin elements.
JavaScript
61
star
57

universal-mixin

A mixin usable for both generic objects and decorators.
JavaScript
59
star
58

attachshadow

An iframe based Shadow DOM poorlyfill
JavaScript
59
star
59

ucontent

An SSR HTML content generator.
JavaScript
58
star
60

dom-augmentor

Same as augmentor but with DOM oriented useEffect handling via dropEffect.
JavaScript
56
star
61

ascjs

ES2015 to CommonJS import/export transformer
JavaScript
55
star
62

geo2city

Basic offline reverse geocode
JavaScript
53
star
63

vanilla-elements

A Minimalistic Custom Elements Helper.
JavaScript
51
star
64

wrist

Minimalistic utility for generic one/two ways data bindings.
HTML
51
star
65

screenfit

A cross platform, cross WebView, solution to fit 100% any Web page.
HTML
50
star
66

html-parsed-element

A base custom element class with a reliable `parsedCallback` method.
HTML
50
star
67

sqlite-tag

Template literal tag based sqlite3 queries.
JavaScript
49
star
68

jsdon

A DOM serializer based on LinkeDOM idea
HTML
48
star
69

echomd

A terminal oriented MD like syntax
JavaScript
48
star
70

dom-class

A lightweight, cross browser, simplification of WebComponents.
JavaScript
46
star
71

cloner

Cloning ES5+ objects in a shallow or deep way
JavaScript
46
star
72

css-proxied-vars

The easiest way to set, read, or update, CSS variables per each element.
JavaScript
46
star
73

event-target

The EventTarget Class Polyfill.
HTML
46
star
74

hn

Isomorphic Hacker News
JavaScript
45
star
75

proxied-worker

A tiny utility to asynchronously drive a namespace exposed through a Worker.
JavaScript
45
star
76

Database

Web SQL Storage Made Easy
JavaScript
44
star
77

promise

Abortable and Resolvable Promises.
JavaScript
43
star
78

poorlyfills

Simplified, partial, and poor ES6 collections polyfills, targeting IE9+ and older mobile browsers.
HTML
43
star
79

babel-plugin-transform-builtin-classes

A fix for the infamous Babel #4480 bug.
JavaScript
43
star
80

redefine

lightweight utility for smart object properties definition
JavaScript
42
star
81

bidi-sse

Bidirectional Server-sent Events
JavaScript
42
star
82

nativeHTML

coming soon
JavaScript
42
star
83

domtagger

The hyperHTML's template literal parser
JavaScript
41
star
84

hooked-elements

wickedElements 🧙 with render hooks
JavaScript
41
star
85

classtrophobic

Breaking JS Class Constrains
HTML
41
star
86

a-route

Express like routing as Custom Element or standalone
JavaScript
40
star
87

header-snippets

A collection of snippets to put in your header.
HTML
40
star
88

life-diary

your albums, your journey, your data
JavaScript
40
star
89

static.email

The easiest way to send emails on the Web
JavaScript
39
star
90

lazytag

Lazy loading Custom Elements and their styles without even thinking about it.
JavaScript
38
star
91

es-class

ECMAScript 3 to 6 compatible Class definition
JavaScript
38
star
92

tiny-cdn

A tiny static files serving handler
JavaScript
37
star
93

broadcast

Notification channel for the past, the present, and the future.
JavaScript
37
star
94

p-cool

Pretty Cool Elements
JavaScript
36
star
95

monthly

A simplified way to show a calendar month in any console.
HTML
36
star
96

jsx2tag

Enable JSX for Template Literal Tags based projects.
JavaScript
36
star
97

consolemd

Bringing echomd to console.
JavaScript
36
star
98

common-js

CommonJS + module.import() for any Browser
JavaScript
35
star
99

qsa-observer

handle elements lifecycle through CSS selectors
JavaScript
35
star
100

create-viperhtml-app

A basic viperHTML + hyperHTML setup
JavaScript
35
star