DbClient - do-/node-doix-db GitHub Wiki
DbClient
is an abstract class implementing some methods common to all database clients. Instances of its descendants are available in Job context as resources. By convention, the basic Job
's DbClient
should be visible as this.db
.
const {db} = this
await db.call ('CREATE TEMP TABLE log (id INTEGER PRIMARY KEY, dt DATETIME DEFAULT NOW (), message VARCHAR (255))').exec ()
await db.do ('INSERT INTO log (id, dt, message) VALUES (?, ?)', [1, 'Test']) // call + exec
// await db.insert ('log', {id: 1, message: 'Test'}) // same
await db.doAll ([
['UPDATE log SET message = ? WHERE id = ?', params: ['The test', 1]]
])
// await db.do ('UPDATE log SET message = ? WHERE id = ?', ['The test', 1])
// await db.update ('log', {id: 1, message: 'The test'}) // same
const object = await db.getObject ('SELECT * FROM log WHERE id = ?', [1]) // same
// const object = await db.getObject (['log', {filters: [['id', '=', 1](/do-/node-doix-db/wiki/'log',-{filters:-[['id',-'=',-1)}]]) // same
// const object = await db.getObject ('log', [1])
const dt = await db.getScalar ('SELECT dt FROM log WHERE id = ?', [1]) // same
// const dt = await db.getScalar (['log', {columns: ['dt'], filters: [['id', '=', 1](/do-/node-doix-db/wiki/'log',-{columns:-['dt'],-filters:-[['id',-'=',-1)}]])
const slice = await db.getArray (['log', {order: ['id'], limit: 10, offset: 0}](/do-/node-doix-db/wiki/'log',-{order:-['id'],-limit:-10,-offset:-0}))
const total = slice [Symbol.for ('count')]
// const slice = await db.getArray ('SELECT * FROM log ORDER BY id LIMIT ? OFFSET ?', [10, 0])
// const total = await db.getScalar ('SELECT COUNT(*) FROM log ORDER BY id', [])
const ids = await db.getArray ('SELECT id FROM log', [], {rowMode: 'scalar'})
// const ids = await db.getArray ([['log'], {columns: ['dt']}], [], {rowMode: 'scalar'}) // same
const oStream = await db.getStream ('SELECT * FROM log', [])
// const oStream = await db.getStream (['log'](/do-/node-doix-db/wiki/'log')) // same
const idStream = await db.getStream ('SELECT id FROM log', [], {rowMode: 'scalar'})
// const idStream = await db.getStream ([['log'], {columns: ['dt']}], [], {rowMode: 'scalar'}) // same
Methods
DB Interaction
In two first sections, all methods have the following parameters:
Name | Type | Description |
---|---|---|
q |
String or DbQuery | The query to be executed |
p |
Array | For a SQL string q , the list of parameters to be bound. For a DbQuery , ignored |
options |
Object | see DbCall |
General purpose
call (q, p, options)
This synchronous method creates and returns a new DbCall instance. No actual request is sent to the database, the DbCall
created is left as is for further manipulations. This is the base for all other DB interaction methods.
do (q, p, options)
This asynchronous method executes call (sql, p, options)
and returns the DbCall
instance after its .exec ()
is complete and 'finish'
is emitted. It's designed mostly for DML, DDL statements like 'INSERT', 'CREATE TABLE' and so on.
For a string valued q
, sql = q
. Other than that, q
may be a [sql, params]
array or a {sql, params}
object. In the latter case, p
is ignored.
options.maxRows
is forcibly set to 0
to communicate that no result data are expected.
doAll (statements, streamOptions)
This asynchronous method takes an Iterable (e. g. an array) or a readable stream of objects and executes do
with each of them.
The streamOptions
are passed to batch
(see below).
batch (streamOptions)
This synchronous method returns a writable stream ready to accept {sql, params}
objects and execute each sql
with the corresonding params
.
The streamOptions
are passed to the Writable constructor: highWaterMark
etc.
Data Fetching
Single Values
getObject (q, p, options)
This asynchronous method executes call (q, p, options)
and returns only the first record of the result set.
Here, q
and p
may also be the name of a table and the array of its primary key values.
options.minRows
and options.maxRows
are forcibly set to 1
.
For an empty result, options.notFound
is returned if it was set explicitly. Otherwise, an Error is thrown.
getScalar (q, p, options)
This asynchronous method executes call (q, p, options)
and returns only the first field of the first record of the result set.
options.minRows
and options.maxRows
are forcibly set to 1
, and options.rowMode
to 'scalar'
.
For an empty result, options.notFound
is returned, undefined
by default. Unlike getObject
, getScalar
never throw Errors when no data are found.
peek (view)
For a given DbView hosting a DbQueue, this asynchronous method returns the first record in queue.order
, or null
if the underlying SQL view is empty. This is a superposition of getObject
and genPeekSql
.
Result Sets
Objects returned by methods described in this section have the following non-enumerable properties (if applicable):
Name | Type | Description |
---|---|---|
Symbol.for ('call') |
DbCall | the call behind this result |
Symbol.for ('columns') |
[{name, type}] | result column definitions |
Symbol.for ('query') |
DbQuery | copy of q , if it was a DbQuery |
Symbol.for ('count') |
int | SELECT COUNT (*)... with LIMIT omitted |
So, for example, rs = getArray (sql)
returns a regular JS Array rs
, yet the source SQL is available via rs [Symbol.for ('call')].sql
.
getStream (q, p, options)
This asynchronous method executes call (q, p, options)
and returns the corresponding result set a Readable stream.
options.maxRows
is forcibly set to Infinity
to communicate that the stream result is expected.
The stream returned is always in object mode, but the nature of objects depends on options.rowMode
: other than default name-value POJOs, it may be flat Arrays of field values (rowMode: 'array'
) or arbitrary JS values representing the 1st column (rowMode: 'scalar'
).
In the latter case, due to a node.js streams limitation, NULLs are represented by special Symbol.for ('NULL')
values instead of plain null
s.
getArray (q, p, options)
This asynchronous method executes call (q, p, options)
and returns the corresponding result set an Array.
options.maxRows
is guaranteed to be a finite positive number, 1000
unless provided.
By default, records are represented by name-value POJOs, but this may be changed to flat Arrays of field values (rowMode: 'array'
) or arbitrary JS values representing the 1st column (rowMode: 'scalar'
).
If q
is a DbQuery instance with offset
option, an additional SELECT COUNT...
(query.toCountingQuery) query is executed and its result is published as the Symbol.for ('count')
property.
Data modification
In this section, the following parameter names are in use:
Name | Type | Description |
---|---|---|
tableName |
String | The name of a table |
record |
Object | A data record |
records |
[Object] | An array of data records |
recordStream |
Readable | An object mode readable of data records |
options |
Object | Extra parameters, mostly vendor dependent |
insert (tableName, record[s], options)
The convenience method invoking insertRecord
, insertArray
or insertStream
based on the type of the 2nd argument.
insertRecord (tableName, record, options)
This is a superposition of genInsertParamsSql and this.do (sql, params)
. Inserts a single record in the specified table. In the base implementation, returns the corresponding DbCall instance.
insertArray (tableName, records, options)
Insert an array of records in the specified table. In the base implementation, uses insertStream
.
insertStream (tableName, recordStream, {columns,...})
Pipes a readable object stream into the specified table. Based on the putObjectStream (tableName, columns, options)
method absent from the base implementation. For each backend, those methods return writable object streams emitting a non standard complete
event upon each successful operation. The column
option, if provided, must contain the array of column names to be written. If absent, this list is calculated from the first record read: in this case it must contain all necessary fields, or a data loss is possible. In the base implementation the return value is undefined
.
update (tableName, record, options)
This is a superposition of genUpdateParamsSql and this.do (sql, params)
.
The 1st argument is the name of a DbRelation (most probably DbTable) in a db.model.
The 2nd agrument is the data object (the record to be stored) that must contain:
- all primary key (
pk
) components; - all properties with known new values.
undefined
and unknown properties are silently ignored.
null
s for non-nullable
columns
mean reset to DEFAULT
values.
Other
createMigrationPlan ()
This synchronous method creates a new DbMigrationPlan instance bound to this database connection.
const plan = this.db.createMigrationPlan ()
createTempTable (tableOrName, options)
This asynchronous method creates a temporary table
by definition. options.onlyIfMissing
triggers IF NOT EXISTS
addition.
getCallLoggingEvents ()
Returns the logged events configuration for DbCall
instances:
{
start: {
level: 'info',
message: function () {return this.sql},
details: {},
},
finish: {
level: 'info',
elapsed: true,
}
}
toCsv ()
This synchronous method creates a new DbCsvPrinter with the given set of options.
myReadableObjectStream.pipe (db.toCsv () ({
table: db.model.find ('users'),
columns: ['uuid', 'label'],
// columns: {uuid: 'UUID!', label: 'VARCHAR (255)'}, // ad hoc definition
// NULL: '\\N',
})).pipe (myWritableBinaryStream)
Properties
Name | Type | Description |
---|---|---|
pool |
DbPool | what brought up this connection |
model |
DbModel | the database structure |
lang |
DbLang | the database language dialect |
count |
Number | The number of times call was invoked |
txn |
Object | Vendor dependent info about the transaction in progress: null by default and after successful COMMIT/ROLLBACK, it maybe just {} after BEGIN or may contain some information about isolation level, savepoints etc. |