better-sqlite-pool
Advanced tools
Comparing version 0.2.1 to 0.2.2
import { EventEmitter } from "events"; | ||
import Database = require("better-sqlite3"); | ||
import BetterSqlite3 = require("better-sqlite3"); | ||
export interface PoolConnection extends Database { | ||
export interface PoolConnection extends BetterSqlite3.Database { | ||
/** Wheter the connection is available and can be acquired. */ | ||
@@ -12,8 +12,27 @@ readonly available: boolean; | ||
export class Pool extends EventEmitter { | ||
export interface PoolOptions extends BetterSqlite3.Options { | ||
/** | ||
* The number of milliseconds to wait when executing queries on a locked | ||
* database, before throwing a SQLITE_BUSY error. Also, this option is used | ||
* to determine how long it'd be waited before throwing timeout error when | ||
* acquiring the connection. (default: 5000). | ||
*/ | ||
timeout?: number; | ||
/** | ||
* A function that gets called with every SQL string executed by the | ||
* database connection (default: `null`). | ||
*/ | ||
verbose?: (...args: any[]) => any; | ||
/** Max connections in the pool, default is `5`. */ | ||
max?: number; | ||
} | ||
export class Pool extends EventEmitter implements PoolOptions { | ||
readonly path: string; | ||
readonly memory: boolean; | ||
readonly fileMustExist: boolean; | ||
readonly timeout: number; | ||
readonly verbose: Function; | ||
readonly max: number; | ||
protected connections: { [n: string]: PoolConnection } | ||
protected connections: PoolConnection[]; | ||
@@ -30,12 +49,3 @@ /** | ||
*/ | ||
constructor(path: string, options?: number | boolean | { | ||
/** Default is `false`. */ | ||
readonly: boolean; | ||
/** Default is `false`. */ | ||
memory: boolean; | ||
/** Default is `false`. */ | ||
fileMustExist: boolean; | ||
/** Max connections in the pool, default is `5`. */ | ||
max: number; | ||
}); | ||
constructor(path: string, options?: number | boolean | PoolOptions); | ||
@@ -42,0 +52,0 @@ /** |
107
index.js
@@ -5,3 +5,4 @@ "use strict"; | ||
const EventEmitter = require("events").EventEmitter; | ||
const Database = require("better-sqlite3"); | ||
const BetterSqlite3 = require("better-sqlite3"); | ||
const pick = require("lodash/pick"); | ||
@@ -25,2 +26,4 @@ /** | ||
* - `max` Max connections in the pool, default is `5`. | ||
* - `timeout` | ||
* - `verbose` | ||
* | ||
@@ -32,10 +35,24 @@ * If this argument is set to a boolean, it's equivalent to `readonly`, | ||
*/ | ||
constructor(path, options = {}) { | ||
constructor(path, options) { | ||
super(); | ||
if (options === undefined || options === null) { | ||
options = {}; | ||
} else if (typeof options === "boolean") { | ||
options = { readonly: options }; | ||
} else if (typeof options === "number") { | ||
options = { max: options }; | ||
} | ||
this.path = path; | ||
this.readonly = typeof options === "boolean" ? options : (options.readonly || false); | ||
this.memory = options.memory || this.path === ":memory"; | ||
this.fileMustExist = options.fileMustExist || false; | ||
this.max = typeof options === "number" ? options : (options.max || 5); | ||
this.connections = {}; | ||
/** @type {BetterSqlite3.Database[]} */ | ||
this.connections = []; | ||
Object.assign(this, { | ||
readonly: false, | ||
memory: path === ":memory", | ||
fileMustExist: false, | ||
timeout: 5000, | ||
verbose: null, | ||
max: 5 | ||
}, options); | ||
} | ||
@@ -46,53 +63,47 @@ | ||
* @see https://github.com/JoshuaWise/better-sqlite3/wiki/API#class-database | ||
* @returns {Promise<Database>} | ||
* @returns {Promise<BetterSqlite3.Database>} | ||
*/ | ||
acquire() { | ||
var ids = Object.keys(this.connections), | ||
db = null, | ||
poolId = 0; | ||
for (let conn of this.connections) { | ||
if (conn.available && conn.open) { | ||
conn.available = false; | ||
for (let id of ids) { | ||
if (this.connections[id].available && this.connections[id].open) { | ||
poolId = id; | ||
db = this.connections[id]; | ||
db.available = false; | ||
break; | ||
return Promise.resolve(conn); | ||
} | ||
} | ||
if (db) { | ||
return new Promise(resolve => { | ||
resolve(db); | ||
}); | ||
} else { | ||
if (ids.length < this.max) { | ||
poolId = ids.length + 1; | ||
db = new Database(this.path, { | ||
memory: this.memory, | ||
readonly: this.readonly, | ||
fileMustExist: this.fileMustExist, | ||
}); | ||
if (this.connections.length < this.max) { | ||
let conn = new BetterSqlite3(this.path, pick(this, [ | ||
"memory", | ||
"readonly", | ||
"fileMustExist", | ||
"timeout", | ||
"verbose" | ||
])); | ||
db.available = false; | ||
db.release = () => { | ||
if (db.open && db.inTransaction) { | ||
db.exec("rollback"); | ||
} | ||
db.available = db.open && true; | ||
this.emit("release"); | ||
this.connections.push(conn); | ||
conn.available = false; | ||
conn.release = () => { | ||
if (conn.open && conn.inTransaction) | ||
conn.exec("rollback"); | ||
conn.available = conn.open && true; | ||
this.emit("release"); | ||
}; | ||
return Promise.resolve(conn); | ||
} else { | ||
return new Promise((resolve, reject) => { | ||
let handler = () => { | ||
clearTimeout(timer); | ||
resolve(this.acquire()); | ||
}; | ||
let timer = setTimeout(() => { | ||
this.removeListener("release", handler); | ||
reject(new Error("Timeout to acquire the connection.")); | ||
}, this.timeout); | ||
this.connections[poolId] = db; | ||
return new Promise(resolve => { | ||
resolve(db); | ||
}); | ||
} else { | ||
return new Promise(resolve => { | ||
this.once("release", () => { | ||
resolve(this.acquire()); | ||
}); | ||
}); | ||
} | ||
this.once("release", handler); | ||
}); | ||
} | ||
@@ -99,0 +110,0 @@ } |
{ | ||
"name": "better-sqlite-pool", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "A connection pool for better-sqlite3.", | ||
@@ -25,8 +25,12 @@ "main": "index.js", | ||
"dependencies": { | ||
"@types/better-sqlite3": "^5.2.2", | ||
"better-sqlite3": "^5.4.0" | ||
"better-sqlite3": "^5.4.0", | ||
"lodash": "^4.17.11" | ||
}, | ||
"engines": { | ||
"node": ">=8.0" | ||
}, | ||
"devDependencies": { | ||
"@types/better-sqlite3": "^5.2.2", | ||
"@types/lodash": "^4.14.122" | ||
} | ||
} |
@@ -51,2 +51,8 @@ # Better-SQLite-Pool | ||
- `max` Max connections in the pool, default is `5`. | ||
- `timeout` The number of milliseconds to wait when executing queries on a | ||
locked database, before throwing a SQLITE_BUSY error. Also, this option | ||
is used to determine how long it'd be waited before throwing timeout | ||
error when acquiring the connection. (default: 5000). | ||
- `verbose` A function that gets called with every SQL string executed by | ||
the database connection (default: `null`). | ||
@@ -56,8 +62,6 @@ If this argument is set to a `boolean`, it's equivalent to `readonly`, | ||
### `pool.acquire(): Promise<Database>` | ||
### `pool.acquire(): Promise<BetterSqlite3.Database>` | ||
**Acquires a connection from the pool.** | ||
The only argument passed to the callback of `Promise.then()` is the database connection acquired. | ||
### `pool.close()` | ||
@@ -81,1 +85,9 @@ | ||
Studio installed, install one with VC++ support, that will fix the problem. | ||
### `statement may fall through` errors | ||
These error will happen when compiling **better-sqlite3** with GCC 7+, which is | ||
issued in [Many "statement may fall through" while installing #3](https://github.com/hyurl/better-sqlite-pool/issues/3) | ||
and [Many "statement may fall through" while installing #239](https://github.com/JoshuaWise/better-sqlite3/issues/239), | ||
you can still run the driver though, if it's not so much important, just leave | ||
the error alone. |
12119
200
90
2
+ Addedlodash@^4.17.11
+ Addedlodash@4.17.21(transitive)
- Removed@types/better-sqlite3@^5.2.2
- Removed@types/better-sqlite3@5.4.3(transitive)
- Removed@types/integer@4.0.3(transitive)