Comparing version 0.100.3 to 0.101.0
@@ -39,2 +39,9 @@ (function() { | ||
this.Dbay_internal_error = class Dbay_internal_error extends this.Dbay_error { | ||
constructor(ref, message) { | ||
super(ref, message); | ||
} | ||
}; | ||
this.Dbay_schema_exists = class Dbay_schema_exists extends this.Dbay_error { | ||
@@ -41,0 +48,0 @@ constructor(ref, schema) { |
221
lib/main.js
(function() { | ||
'use strict'; | ||
var CND, E, PATH, SQL, badge, debug, echo, guy, help, info, isa, new_bsqlt3_connection, rpr, type_of, types, urge, validate, validate_list_of, warn, whisper; | ||
var CND, Dbay_query, Dbay_random, E, FS, H, PATH, SQL, badge, debug, echo, guy, help, info, isa, new_bsqlt3_connection, rpr, type_of, types, urge, validate, validate_list_of, warn, whisper; | ||
@@ -29,2 +29,4 @@ //########################################################################################################### | ||
FS = require('fs'); | ||
types = new (require('intertype')).Intertype(); | ||
@@ -42,14 +44,9 @@ | ||
//----------------------------------------------------------------------------------------------------------- | ||
types.declare('dbay_urlsafe_word', { | ||
tests: { | ||
"@isa.nonempty_text x": function(x) { | ||
return this.isa.nonempty_text(x); | ||
}, | ||
"/^[a-zA-Z0-9_]+$/.test x": function(x) { | ||
return /^[a-zA-Z0-9_]+$/.test(x); | ||
} | ||
} | ||
}); | ||
H = require('./helpers'); | ||
//........................................................................................................... | ||
({Dbay_random} = require('./random-mixin')); | ||
({Dbay_query} = require('./query-mixin')); | ||
//----------------------------------------------------------------------------------------------------------- | ||
@@ -61,13 +58,7 @@ types.declare('constructor_cfg', { | ||
}, | ||
"@isa_optional.boolean x.ram": function(x) { | ||
return this.isa_optional.boolean(x.ram); | ||
"@isa.nonempty_text x.path": function(x) { | ||
return this.isa.nonempty_text(x.path); | ||
}, | ||
"@isa_optional.nonempty_text x.url": function(x) { | ||
return this.isa_optional.nonempty_text(x.url); | ||
}, | ||
"@isa_optional.nonempty_text x.path": function(x) { | ||
return this.isa_optional.nonempty_text(x.path); | ||
}, | ||
"@isa_optional.dbay_urlsafe_word x.dbnick": function(x) { | ||
return this.isa_optional.dbay_urlsafe_word(x.dbnick); | ||
"@isa.boolean x.temporary": function(x) { | ||
return this.isa.boolean(x.temporary); | ||
} | ||
@@ -78,61 +69,7 @@ } | ||
//=========================================================================================================== | ||
this.Dbay_rnd = (function() { | ||
class Dbay_rnd { | ||
_initialize_prng() { | ||
var clasz, delta, ref, ref1, ref2, ref3, seed; | ||
clasz = this.constructor; | ||
if (clasz._rnd_int_cfg != null) { | ||
seed = (ref = (ref1 = clasz._rnd_int_cfg) != null ? ref1.seed : void 0) != null ? ref : 12.34; | ||
delta = (ref2 = (ref3 = clasz._rnd_int_cfg) != null ? ref3.delta : void 0) != null ? ref2 : 1; | ||
guy.props.def(this, '_rnd_int', { | ||
enumerable: false, | ||
value: CND.get_rnd_int(seed, delta) | ||
}); | ||
} else { | ||
guy.props.def(this, '_rnd_int', { | ||
enumerable: false, | ||
value: CND.random_integer.bind(CND) | ||
}); | ||
} | ||
return null; | ||
} | ||
//--------------------------------------------------------------------------------------------------------- | ||
_get_connection_url(dbnick = null) { | ||
/* TAINT rename `dbnick` to `dbnick` */ | ||
/* Given an optional `dbnick`, return an object with the `dbnick` and the `url` for a new SQLite | ||
connection. The url will look like `'file:your_name_here?mode=memory&cache=shared` so multiple | ||
connections to the same RAM DB can be opened. When `dbnick` is not given, a random dbnick like | ||
`_icql_6200294332` will be chosen (prefix `_icql_`, suffix ten decimal digits). For testing, setting | ||
class property `@_rnd_int_cfg` can be used to obtain repeatable series of random names. */ | ||
var n10, url; | ||
n10 = this._rnd_int(1_000_000_000, 9_999_999_999); | ||
if (dbnick == null) { | ||
dbnick = `_${n10}`; | ||
} | ||
url = `file:${dbnick}?mode=memory&cache=shared`; | ||
return {url, dbnick}; | ||
} | ||
}; | ||
//========================================================================================================= | ||
// RANDOM NUMBER GENERATION | ||
// seedable for testing purposes | ||
//--------------------------------------------------------------------------------------------------------- | ||
/* To obtain a class with a seedable PRNG that emits repeatable sequences, define class property | ||
`@_rnd_int_cfg: { seed, delta, }` where both seed and delta can be arbitrary finite numbers. **NOTE** | ||
very small `delta` values (like 1e-10) may cause adjacent numbers to be close together or even repeat. To | ||
use default values for both parameters, set `@_rnd_int_cfg: true`.*/ | ||
Dbay_rnd._rnd_int_cfg = null; | ||
return Dbay_rnd; | ||
}).call(this); | ||
//=========================================================================================================== | ||
this.Dbay = (function() { | ||
class Dbay extends this.Dbay_rnd { | ||
class Dbay extends Dbay_query(Dbay_random()) { | ||
//--------------------------------------------------------------------------------------------------------- | ||
static cast_sqlt_cfg(self) { | ||
/* Produce a configuration object for `better-sqlite3` from `self.cfg`. */ | ||
var R; | ||
@@ -147,27 +84,19 @@ R = guy.obj.pluck_with_fallback(self.cfg, null, 'readonly', 'timeout'); | ||
static cast_constructor_cfg(self) { | ||
var base, base1, dbnick, ref, url; | ||
// debug '^344476^', self | ||
// debug '^344476^', self.cfg | ||
if ((self.cfg.ram === false) && (self.cfg.path == null)) { | ||
throw new E.Dbay_cfg_error('^dba@1^', `missing argument \`path\`, got ${rpr(self.cfg)}`); | ||
} | ||
if ((base = self.cfg).ram == null) { | ||
base.ram = self.cfg.path == null; | ||
} | ||
if ((!self.cfg.ram) && (self.cfg.path != null) && (self.cfg.dbnick != null)) { | ||
throw new E.Dbay_cfg_error('^dba@1^', `only RAM DB can have both \`path\` and \`dbnick\`, got ${rpr(self.cfg)}`); | ||
} | ||
if (self.cfg.ram) { | ||
({dbnick, url} = self._get_connection_url((ref = self.cfg.dbnick) != null ? ref : null)); | ||
if ((base1 = self.cfg).dbnick == null) { | ||
base1.dbnick = dbnick; | ||
var R, clasz, filename; | ||
clasz = self.constructor; | ||
R = self.cfg; | ||
//....................................................................................................... | ||
if (R.path != null) { | ||
if (R.temporary == null) { | ||
R.temporary = false; | ||
} | ||
self.cfg.url = url; | ||
R.path = PATH.resolve(R.path); | ||
} else { | ||
self.cfg.url = null; | ||
if (R.temporary == null) { | ||
R.temporary = true; | ||
} | ||
filename = self._get_random_filename(); | ||
R.path = PATH.resolve(PATH.join(clasz.C.autolocation, filename)); | ||
} | ||
// self.cfg = guy.obj.nullify_undefined self.cfg | ||
self.sqlt_cfg = guy.lft.freeze(guy.obj.omit_nullish(this.cast_sqlt_cfg(self))); | ||
self.cfg = guy.lft.freeze(guy.obj.omit_nullish(self.cfg)); | ||
return null; | ||
return R; | ||
} | ||
@@ -177,6 +106,8 @@ | ||
static declare_types(self) { | ||
// debug '^133^', self.cfg, Object.isFrozen self.cfg | ||
this.cast_constructor_cfg(self); | ||
/* called from constructor via `guy.cfg.configure_with_types()` */ | ||
self.cfg = this.cast_constructor_cfg(self); | ||
self.sqlt_cfg = this.cast_sqlt_cfg(self); | ||
self.cfg = guy.lft.freeze(guy.obj.omit_nullish(self.cfg)); | ||
self.sqlt_cfg = guy.lft.freeze(guy.obj.omit_nullish(self.sqlt_cfg)); | ||
self.types.validate.constructor_cfg(self.cfg); | ||
// guy.props.def self, 'dba', { enumerable: false, value: self.cfg.dba, } | ||
return null; | ||
@@ -186,27 +117,74 @@ } | ||
//--------------------------------------------------------------------------------------------------------- | ||
_new_bsqlt3_connection() { | ||
var path_or_url; | ||
path_or_url = this.cfg.ram ? this.cfg.url : this.cfg.path; | ||
return new_bsqlt3_connection(path_or_url, this.sqlt_cfg); | ||
} | ||
//--------------------------------------------------------------------------------------------------------- | ||
constructor(cfg) { | ||
super(); | ||
this._initialize_prng(); | ||
guy.cfg.configure_with_types(this, cfg, types); | ||
guy.props.def(this, 'sqlt1', { | ||
enumerable: false, | ||
value: this._new_bsqlt3_connection() | ||
}); | ||
guy.props.def(this, 'sqlt2', { | ||
enumerable: false, | ||
value: this._new_bsqlt3_connection() | ||
}); | ||
this._register_schema('main', this.cfg.path, this.cfg.temporary); | ||
//....................................................................................................... | ||
if (!this.constructor._skip_sqlt) { | ||
guy.props.def(this, 'sqlt1', { | ||
enumerable: false, | ||
value: this._new_bsqlt3_connection() | ||
}); | ||
guy.props.def(this, 'sqlt2', { | ||
enumerable: false, | ||
value: this._new_bsqlt3_connection() | ||
}); | ||
} | ||
// @_compile_sql() | ||
// @_create_sql_functions() | ||
// @_create_db_structure() | ||
guy.process.on_exit(() => { | ||
return this.destroy(); | ||
}); | ||
return void 0; | ||
} | ||
//--------------------------------------------------------------------------------------------------------- | ||
_new_bsqlt3_connection() { | ||
return new_bsqlt3_connection(this.cfg.path, this.sqlt_cfg); | ||
} | ||
//--------------------------------------------------------------------------------------------------------- | ||
_register_schema(schema, path, temporary) { | ||
if (this._dbs == null) { | ||
/* Register a schema and descriptional properties, especially whether DB file is to be removed on | ||
process exit. */ | ||
guy.props.def(this, '_dbs', { | ||
enumerable: false, | ||
value: {} | ||
}); | ||
} | ||
this._dbs[schema] = {path, temporary}; | ||
return null; | ||
} | ||
//========================================================================================================= | ||
// CLEANUP ON DEMAND, ON PROCESS EXIT | ||
//--------------------------------------------------------------------------------------------------------- | ||
destroy() { | ||
var d, error, ref, schema; | ||
try { | ||
/* To be called on progress exit or explicitly by client code. Removes all DB files marked 'temporary' | ||
in `@_dbs`. */ | ||
this.sqlt1.close(); | ||
} catch (error1) { | ||
error = error1; | ||
warn('^dbay@1^', error.message); | ||
} | ||
try { | ||
this.sqlt2.close(); | ||
} catch (error1) { | ||
error = error1; | ||
warn('^dbay@1^', error.message); | ||
} | ||
ref = this._dbs; | ||
for (schema in ref) { | ||
d = ref[schema]; | ||
if (d.temporary) { | ||
H.unlink_file(d.path); | ||
} | ||
} | ||
return null; | ||
} | ||
}; | ||
@@ -216,2 +194,3 @@ | ||
Dbay.C = guy.lft.freeze({ | ||
autolocation: H.autolocation, | ||
defaults: { | ||
@@ -225,5 +204,3 @@ constructor_cfg: { | ||
overwrite: false, | ||
ram: null, | ||
path: null, | ||
dbnick: null | ||
path: null | ||
} | ||
@@ -230,0 +207,0 @@ } |
{ | ||
"name": "dbay", | ||
"version": "0.100.3", | ||
"version": "0.101.0", | ||
"description": "In-Process, In-Memory & File-Based Relational Data Processing with SQLite, BetterSQLite3", | ||
"main": "lib/main.js", | ||
"scripts": { | ||
"build": "coffee --map -o lib -c src", | ||
"test": "echo see 'https://github.com/loveencounterflow/hengist/tree/master/dev/dbay'", | ||
"preinstall": "./build-sqlite3" | ||
}, | ||
"repository": { | ||
@@ -24,11 +29,6 @@ "type": "git", | ||
"cnd": "9.2.2", | ||
"guy": "^2.2.0", | ||
"intertype": "7.6.7", | ||
"temp": "^0.9.4" | ||
}, | ||
"scripts": { | ||
"build": "coffee --map -o lib -c src", | ||
"test": "echo see 'https://github.com/loveencounterflow/hengist/tree/master/dev/dbay'", | ||
"preinstall": "./build-sqlite3" | ||
"exit-hook": "^2.2.1", | ||
"guy": "^2.3.0", | ||
"intertype": "7.6.7" | ||
} | ||
} | ||
} |
@@ -10,2 +10,5 @@ | ||
- [Takeaways](#takeaways) | ||
- [SQLite is Fast](#sqlite-is-fast) | ||
- [SQLite is Not Fast Except When It Is](#sqlite-is-not-fast-except-when-it-is) | ||
- [Top Runners](#top-runners) | ||
@@ -15,8 +18,81 @@ - [Upper League](#upper-league) | ||
- [Deplorables](#deplorables) | ||
- [To Do](#to-do) | ||
<!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
### Takeaways | ||
#### SQLite is Fast | ||
The (preliminary) benchmark results (see below; code found at | ||
[in-memory-sql.benchmarks.coffee](https://github.com/loveencounterflow/hengist/blob/master/dev/in-memory-sql/src/in-memory-sql.benchmarks.coffee), | ||
[in-memory-sql.benchmarks.js](https://github.com/loveencounterflow/hengist/blob/master/dev/in-memory-sql/lib/in-memory-sql.benchmarks.js)) | ||
demonstrate that | ||
* **SQLite can do RDBMS stuff faster than some of its competitors** (notably: PostgreSQL); | ||
* this is no doubt helped by the in-process nature of SQLite as opposed to the server/client architecture | ||
of more traditional RDBMSes. | ||
* **You can get top speed out of SQLite under NodeJS using | ||
[`better-sqlite3`](https://github.com/JoshuaWise/better-sqlite3)**, provided that | ||
* SQLite is **configured correctly** (recommended to always use `pragma journal_mode = WAL`), and | ||
* **explicit transactions (below marked `*_tx`) are used** to bundle many small actions (here: SQL | ||
`insert`s) into atomic commits. | ||
#### SQLite is Not Fast Except When It Is | ||
There are, confusingly, several 'operational modes' to run SQLite: | ||
* **(1)** The **classical way** is of course to pass in a file system path that SQLite will use to open an | ||
existing or create a new database file. | ||
* **(2)** One can **open a DB situated on a RAM disk** (read: Linux `ramfs` or `tmpfs`; also **`sh`**ared | ||
**`m`**emory). **Opening a DB file on a RAM disk has many advantages** over using any of they ways listed | ||
under (3), below, since a RAM disk is just a file system, meaning the file can be accessed by all the | ||
usual means. | ||
* **(3)** Last but not least there are no less than *three* competing, *almost* equivalent ways to obtain an | ||
**in-memory DB**: | ||
* **(3.1)** One can pass in the special string [`':memory:'` to obtain a so-called *in-memory DB* (without | ||
'shared cache')](https://www.sqlite.org/inmemorydb.html), | ||
* **(3.2)** or an empty string `''` that opens [a *temporary DB* (again without 'shared | ||
cache')](https://www.sqlite.org/inmemorydb.html#temp_db) (which is almost but not 100% the same thing as | ||
an in-memory DB). | ||
* **(3.3)** The third (and in theory preferable) way to open a DB that resides in RAM is using [a | ||
connection URL like with | ||
`file:xxx?mode=memory&cache=shared`](https://www.sqlite.org/sharedcache.html#inmemsharedcache) instead | ||
of a plain filename; since such an in-memory DB is identified via a name, several connections to the | ||
*same* in-memory DB may be made (albeit only from the same client process). | ||
* Having more than one connection to the same DB is necessary to enable user-defined functions (UDFs) to | ||
issue queries against the DB, but | ||
* the downside is that shared connections lacks feature-parity with [WAL | ||
mode](https://sqlite.org/wal.html) and that | ||
* [the 'shared connection' feature is not loved by the SQLite | ||
devs](https://sqlite.org/forum/info/871b9085849abd6e) (quoting drh: "It was a clever work-around [...] | ||
shared-cache is considered a mistake and a misfeature"). | ||
If the above litany is confusing for you that's because it is. Why *three* distinct, non-obvious ways to | ||
obtain an in-memory DB?—Other than "That's the accumulated results of over 20 years of development" there's | ||
probably no very good answer. | ||
However, after much experimenting, benchmarking and feture-testing, I feel confident to state that **you | ||
should probably forget about using SQLite in-memory DBs as outlined in point (3)**, above. The only | ||
exception to the rule would be when you wanted top performance (and who wouldn't), not worry about explicit | ||
transactions, do not need data durability (i.e. when the DB may become disposable on process exit), and do | ||
not plan on having to use more than a single connection (meaning you can not query data in that DB from | ||
within UDFs). In that case, feel free to pass in an empty string or `':memory:'` as path; but otherwise: | ||
**Always just use ordinary file system paths**. If you're on Linux, consider to use `/dev/shm` which is a | ||
read-to-use `tmpfs`, or use something like `sudo mount -t tmpfs -o size=512m none /mnt/ramdisk` to obtain a | ||
new RAM disk. On Linux systems that have a directory called `/dev/shm`, DBay will use that location to open | ||
DB files when no explicit `path` is passed in, and fall back to `/tmp` when `/dev/shm` is not found. You'll | ||
get to use [WAL mode](https://sqlite.org/wal.html) which is great because together with multiple connections | ||
it enables user-defined functions that can concurrently query rows from the same DB they deliver values to. | ||
What's more, benchmarks indicate that **what is slowing down work with an SQLite DB is not so much file | ||
system access *per se*, it's the implicit transactions that wrap each and every statement** in a pair of | ||
`begin transaction`, `commit` statements. **Curiously, slowdown-by-transaction is much more pronounced with | ||
RAM disks as opposed to SSD access**, as shown by the paltry `bsqlt_tmpfs 8.9%` result. I have no | ||
explanation for that performance cliff other than that maybe disk writes are better managed between hardware | ||
components and threads when using SSDs. | ||
### Top Runners | ||
@@ -63,3 +139,5 @@ | ||
### To Do | ||
* explain different benchmarks scenarios | ||
@@ -69,2 +147,1 @@ | ||
@@ -9,6 +9,5 @@ | ||
- [Using Defaults](#using-defaults) | ||
- [Automatic Location](#automatic-location) | ||
- [Randomly Chosen Filename](#randomly-chosen-filename) | ||
- [Using Parameters](#using-parameters) | ||
- [All Parameters in Systematic Order](#all-parameters-in-systematic-order) | ||
- [Valid Parameter Combinations](#valid-parameter-combinations) | ||
- [Invalid Parameter Combinations](#invalid-parameter-combinations) | ||
@@ -27,117 +26,32 @@ <!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
The `db` object will then have two properties `db.sqlt1` and `db.sqlt2` that are `better-sqlite3` | ||
connections to the same in-memory DB (a RAM DB in our terminology). This is achieved by passing an URL like | ||
`file:_6200294332?mode=memory&cache=shared` to `better-sqlite3` where the name (`_6200294332`) is a random | ||
10-digit number. | ||
connections to the same temporary DB in the ['automatic location'](#automatic-location). | ||
### Using Parameters | ||
### Automatic Location | ||
You can also call the constructor with a configuration object that may have one or more of the following | ||
fields: | ||
The so-called 'automatic location' is either | ||
* **`cfg.ram`** (`?boolean`): Specifies whether a RAM DB is to be opened. All DBay in-memory DBs are named | ||
so several connections to the same RAM DB can be opened (this is necessitated by a <del>shortcome</del> | ||
<ins>feature</ins> of `better-sqlite3` that prohibits any reads against the DB from within User-Defined | ||
Functions). | ||
* the directory `/dev/shm` on Linux systems that support **SH**ared **M**emory (a.k.a a RAM disk) | ||
* the OS's temporary directory as announced by `os.tmpdir()` | ||
* When neither **`cfg.path`** nor **`cfg.dbnick`** are given, an empty RAM DB will be opened. | ||
* When **`cfg.dbnick`** (but not **`cfg.path`**) is given, a | ||
* When **`cfg.path`** is given, an SQLite DB file will be (created if non-existant and) opened; then, | ||
the DB will be mirrored to RAM so now you have a RAM DB associated with a disk location. You can use | ||
`db.save()` any number of times to write changes to disk. DB contents will be lost should the | ||
process terminate after changes to the DB but before `db.save()` terminates. This mode of operation | ||
is called 'Eventual Persistency'. | ||
In either case, a [file with a random name](#randomly-chosen-filename) will be created in that location. | ||
* **`cfg.path`** (`?non-empty text`): Specifies which file system path to save the DB to. | ||
* When `path` is given but `ram` is not set (or `null` or `undefined`), `ram` will assume the value | ||
`false`. | ||
* When `path` is given | ||
* and `ram` is **`false`**, a file DB will be opened from or created at the location given. This DB | ||
will have Continuous Persistency, i.e. operate in the normal DB mode where all changes are reflected | ||
on disk and thus made durable with a high degree of safety against data losses. Otherwise, | ||
* when `ram` is `true`, a RAM DB will be opened. | ||
### Randomly Chosen Filename | ||
* **`cfg.dbnick`** (`?URL-safe word`): name given to a RAM DB. It will be used to construct a URL that | ||
will be passed to SQLite. There's little use in passing in `dbnick` explicitly; if one wishes to | ||
construct multiple `Dbay()` objects to the same RAM DB, one can always use the `cfg` object of the first | ||
instance: | ||
Format `dbay-NNNNNNNNNN.sqlite`, where `N` is a digit `[0-9]`. | ||
```coffee | ||
db1 = new Dbay { ram: true, } | ||
db2 = new Dbay db1.cfg | ||
``` | ||
### Using Parameters | ||
#### All Parameters in Systematic Order | ||
You can also call the constructor with a configuration object that may have one or more of the following | ||
fields: | ||
**Note** in the below tables, `in.*` parameters are those passed in when calling `new Dbay { ... }`; `out.*` | ||
parameters are those to be found under `db.cfg.*` in the newly constructed instance. Observe that | ||
* **`cfg.path`** (`?non-empty text`): Specifies which file system path to save the DB to; if the path given | ||
is relative, it will be resolved in reference to the current directory (`process.cwd()`). When not | ||
specified, `cfg.path` will be derived from [`Dbay.C.autolocation`](#automatic-location) and a [randomly | ||
chosen filename](#randomly-chosen-filename). | ||
* where `in.*` parameters are shown with `null` values here they can also be `undefined` or missing; | ||
* where `out.*` parameters are shown with `null` values they will be missing from `db.cfg`. This omission | ||
of `null` values is deemed advantageous for the human reader who will have less text to process when | ||
printing `db.cfg` for introspection, and fewer combinations of values have to be pondered. | ||
* For combinations that are unacceptable (cause errors), `out.*` parameters are left unspecified. | ||
* **`cfg.temporary`** (`?boolean`): Specifies whether DB file is to be removed when process exits or | ||
`db.destry()` is called explicitly. `cfg.temporary` defaults to `false` if `cfg.path` is given, and `true` | ||
otherwise (when a random filename is chosen). | ||
In addition to the `out.*` parameters listed, `db.cfg.url` will be set whenever `dbnick` is set. This URL | ||
will be of the form | ||
* `file:_6200294332?mode=memory&cache=shared` when generated, or | ||
* `file:your_db_name_here?mode=memory&cache=shared` where `dbnick` is given (as `'your_db_name_here'` in | ||
this example). | ||
| nr | in.ram | in.path | in.dbnick | out.ram | out.path | out.dbnick | out.persistency | out.error | same as | | ||
|----|---------|-------------|------------|---------|-------------|-----------------|-----------------|-----------|----------| | ||
| 1 | `null` | `null` | `null` | `true` | `null` | `'_6200294332'` | none | ——— | 1, 9 | | ||
| 2 | | | `'dbnick'` | `true` | `null` | `'dbnick'` | none | ——— | 2, 10 | | ||
| 3 | | `'db/path'` | `null` | `false` | `'db/path'` | `null` | continuous | ——— | 3, 7 | | ||
| 4 | | | `'dbnick'` | ——— | ——— | ——— | ——— | **E01** | 4, 8, 12 | | ||
| 5 | `false` | `null` | `null` | ——— | ——— | ——— | ——— | **E02** | 5, 6 | | ||
| 6 | | | `'dbnick'` | ——— | ——— | ——— | ——— | **E02** | 5, 6 | | ||
| 7 | | `'db/path'` | `null` | `false` | `'db/path'` | `null` | continuous | ——— | 3, 7 | | ||
| 8 | | | `'dbnick'` | ——— | ——— | ——— | ——— | **E01** | 4, 8, 12 | | ||
| 9 | `true` | `null` | `null` | `true` | `null` | `'_6200294332'` | none | ——— | 1, 9 | | ||
| 10 | | | `'dbnick'` | `true` | `null` | `'dbnick'` | none | ——— | 2, 10 | | ||
| 11 | | `'db/path'` | `null` | `true` | `'db/path'` | `'_6200294332'` | eventual | ——— | ——— | | ||
| 12 | | | `'dbnick'` | ——— | ——— | ——— | none | **E01** | 4, 8, 12 | | ||
#### Valid Parameter Combinations | ||
| nr | in.ram | in.path | in.dbnick | out.ram | out.path | out.dbnick | out.persistency | | ||
|-------|-----------------|-------------|------------|---------|-------------|-----------------|-----------------| | ||
| 1, 9 | `null`, `true` | `null` | `null` | `true` | `null` | `'_6200294332'` | none | | ||
| 2, 10 | `null`, `true` | `null` | `'dbnick'` | `true` | `null` | `'dbnick'` | none | | ||
| 11 | `true` | `'db/path'` | `null` | `true` | `'db/path'` | `'_6200294332'` | eventual | | ||
| 3, 7 | `null`, `false` | `'db/path'` | `null` | `false` | `'db/path'` | `null` | continuous | | ||
Resulting shapes of `db.cfg` when the above `in.*` parameters are applied; observe that additional | ||
properties may be present: | ||
| nr | | | ||
|-------|-------------------------------------------------------------------------------------------------| | ||
| 1, 9 | `{ ram: true, dbnick: '_6200294332', url: 'file:_6200294332?mode=memory&cache=shared' }` | | ||
| 2, 10 | `{ ram: true, dbnick: 'dbnick', url: 'file:dbnick?mode=memory&cache=shared' }` | | ||
| 11 | `{ ram: true, dbnick: 'dbnick', url: 'file:dbnick?mode=memory&cache=shared', path: 'db/path' }` | | ||
| 3, 7 | `{ ram: false, path: 'db/path' }` | | ||
| | | | ||
#### Invalid Parameter Combinations | ||
* When a `path` is given, `dbnick` must not be set. In the future, we may allow this `dbnick` to be used when | ||
`db.transfer_to_ram()` is called. | ||
* When `ram` is explicitly `false`, then `path` must be set. | ||
| nr | in.ram | in.path | in.dbnick | out.error | | ||
|----------|-------------------------|-----------------|--------------------|----------------------------------------------| | ||
| 4, 8, 12 | `null`, `false`, `true` | **`'db/path'`** | **`'dbnick'`** | **E01 cannot give both `path` and `dbnick`** | | ||
| 5, 6 | `false` | **`null`** | `null`, `'dbnick'` | **E02 missing argument `path`** | | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11876917
63
954
2
+ Addedexit-hook@^2.2.1
+ Addedexit-hook@2.2.1(transitive)
- Removedtemp@^0.9.4
- Removedbalanced-match@1.0.2(transitive)
- Removedbrace-expansion@1.1.11(transitive)
- Removedconcat-map@0.0.1(transitive)
- Removedfs.realpath@1.0.0(transitive)
- Removedglob@7.2.3(transitive)
- Removedinflight@1.0.6(transitive)
- Removedinherits@2.0.4(transitive)
- Removedminimatch@3.1.2(transitive)
- Removedminimist@1.2.8(transitive)
- Removedmkdirp@0.5.6(transitive)
- Removedonce@1.4.0(transitive)
- Removedpath-is-absolute@1.0.1(transitive)
- Removedrimraf@2.6.3(transitive)
- Removedtemp@0.9.4(transitive)
- Removedwrappy@1.0.2(transitive)
Updatedguy@^2.3.0