'use strict';
const Stream = require('stream');
const exported = Object.freeze({
/**
* Module key used for the object namespace on errors and logging
*/
MOD_KEY: 'sqler',
/**
* Namespace on a `Manager` where SQL functions will be added
*/
NS: 'db',
/**
* Valid CRUD operation names
*/
CRUD_TYPES: Object.freeze(['CREATE', 'READ', 'UPDATE', 'DELETE']),
/**
* `RegExp` for capturing named bind parameter names within SQL
*/
POS_BINDS_REGEXP: /(?<!:):(\w+)(?=([^'\\]*(\\.|'([^'\\]*\\.)*[^'\\]*'))*[^']*$)/g,
/**
* `RegExp` for removing invalid chars from prepared function directory names
*/
FUNC_NAME_DIR_REGEXP: /[^0-9a-zA-Z]/g,
/**
* `RegExp` for removing invalid chars from prepared function file names
*/
FUNC_NAME_FILE_REGEXP: /[^0-9a-zA-Z\.]/g,
/**
* Separator for prepared function names (also used as the dir/filename replacement)
*/
FUNC_NAME_SEPARATOR: '_',
/**
* Event name that is emitted when a stream has prepared a statement.
* Listeners will receive a single argument that contains the {@link SQLERExecResults}.
*/
EVENT_STREAM_STATEMENT_PREPARED: 'sqler_stream_statement_prepared',
/**
* Event name that is emitted when a stream has unprepared a statement.
* Listeners will receive a single argument that contains the {@link SQLERExecResults}.
*/
EVENT_STREAM_STATEMENT_UPREPARED: 'sqler_stream_statement_unprepared',
/**
* Event name that is emitted when a stream has finished execution for a series of reads or writes included in a batch.
* Listeners will receive a single `Object[]` argument that contains the _raw_ results returned by each of the dialect SQL read or write executions.
*/
EVENT_STREAM_BATCH: 'sqler_stream_batch',
/**
* Event name that is emitted when a stream has committed a transaction.
* Listeners will receive a single `String` argument that contains the transaction ID returned by each of the dialect SQL read or write executions.
*/
EVENT_STREAM_COMMIT: 'sqler_stream_commit',
/**
* Event name that is emitted when a stream has rolled back a transaction.
* Listeners will receive a single `String` argument that contains the transaction ID returned by each of the dialect SQL read or write executions.
*/
EVENT_STREAM_ROLLBACK: 'sqler_stream_rollback',
/**
* Event name that is emitted when a stream has released or closed the connection used by the read or write stream (__managed by individual dialect implementations__).
* Listeners will __not__ receive any arguments.
*/
EVENT_STREAM_RELEASE: 'sqler_stream_release'
});
module.exports = exported;
/**
* Global type definitions used by `sqler`
* @namespace typedefs
*/
/**
* The `cache` client responsible for regulating the frequency in which a SQL file is read by a {@link Manager}.
* @typedef {Object} SQLERCache
* @property {Function} start An `async function()` that starts caching. This could be a `noop` or could start any background processing and/or capture of cached keys (depending on the type of
* implementation).
* @property {Function} stop An `async function()` that stops caching. This could be a `noop` or could stop any background processing and/or capture of cached keys (depending on the type of
* implementation).
* @property {Function} get An `async function(key)` that gets a corresponding SQL statement from cache using the specified _key_ to uniquily identify the SQL source (typically generated by a {@link Manager}).
* The returned _object_ will contain the following values when present (otherwise, returns _null_):
* - `item` - The cached SQL statement
* - `stored` - The timestamp indicating the time when the SQL statement was stored in cache
* - `ttl` - The timestamp indicating the remaining time left before the SQL statement will be removed from cache
* @property {Function} set An `async function(key, sql, ttlOverride)` that sets a SQL statement in cache, overriding the _time-to-live__ (in milliseconds) that may have been set by a {@link Manager}.
* @property {Function} drop An `async function(key)` that removes the specified key from cache
* @example
* // cache options can be different depending on the needs of the implementing cache
* const cacheOpts = {
* "expiresIn": 60000
* };
* // simple interval cache for illustration purposes
* const bank = { store: {}, handles: {} };
* const cache = {
* start: async () => {
* let cached, calTtl;
* for (let key in bank.handles) {
* clearInterval(bank.handles[key]);
* cached = bank.store.hasOwnProperty(key) ? bank.store[key] : null;
* calTtl = !cached|| isNaN(cached.ttl) ? cacheOpts.expiresIn : cached.ttl;
* bank.handles[key] = setInterval(() => delete bank.store[key], calTtl);
* }
* },
* stop: async () => {
* for (let key in bank.handles) {
* clearInterval(bank.handles[key]);
* }
* },
* get: async key => {
* const cached = bank.store.hasOwnProperty(key) ? bank.store[key] : null;
* if (cached) cached.ttl = Date.now() - cached.stored;
* return Promise.resolve(cached ? JSON.parse(JSON.stringify(cached)) : cached);
* },
* set: async (key, val, ttl) => {
* if (bank.handles[key]) clearInterval(bank.handles[key]);
* const calTtl = !ttl || isNaN(ttl) ? cacheOpts.expiresIn : ttl;
* bank.store[key] = { item: val, stored: Date.now(), ttl: calTtl };
* bank.handles[key] = setInterval(sql => delete bank.store[key], calTtl);
* return Promise.resolve();
* },
* drop: async () => {
* if (bank.handles[key]) {
* clearInterval(bank.handles[key]);
* delete bank.handles[key];
* }
* if (bank.store[key]) delete bank.store[key];
* }
* };
*
* // manager configuration
* const conf = {
* // other required conf options here
* "db": {
* "connections": [
* {
* // other required connection conf options here
* }
* ]
* }
* };
*
* const mgr = new Manager(conf, cache);
* await mgr.init();
* // use the manager to execute SQL files that will
* // be refreshed/re-read every 60 seconds
* // can also set the cache after Manager.init()
* const setCacheResults = await mgr.setCache(cache);
* @memberof typedefs
*/
/**
* Private options for global {@link Manager} use
* @typedef {Object} SQLERPrivateOptions
* @property {String} [username] The username to connect to the database
* @property {String} [password] The password to connect to the database
* @property {String} [host] The host to connect to for the database
* @property {String} [port] The port to connect to for the database (when not included in the host)
* @property {String} [protocol] The protocol to use when connecting to the database
* @property {String} [privatePath] The private path set by an originating {@link Manager} constructor (when not already set) that may be used by an implementing {@link Dialect} for private data use
* (e.g. `TNS` files, etc.)
* @memberof typedefs
*/
/**
* Configuration options for {@link Manager} use
* @typedef {Object} SQLERConfigurationOptions
* @property {String} [mainPath] Root directory starting point to look for SQL files (defaults to `require.main` path or `process.cwd()`)
* @property {String} [privatePath] Current working directory where generated files will be located (if any, defaults to `process.cwd()`)
* @property {Boolean} [debug] Truthy to turn on debugging
* @property {SQLERUniversalOptions} univ The {@link SQLERUniversalOptions}
* @property {Object} db The _public_ facing database configuration
* @property {Object} db.dialects An object that contains {@link Dialect} implementation details where each property name matches a dialect name and the value contains either the module class or a string
* that points to a {@link Dialect} implementation for the given dialect (e.g. `{ dialects: { 'oracle': 'sqler-oracle' } }`). When using a directory path the dialect path will be prefixed with
* `process.cwd()` before loading.
* @property {SQLERConnectionOptions[]} db.connections The connections options that will be used.
* @memberof typedefs
*/
/**
* The universal configuration that, for security and sharing purposes, remains external to an application
* @typedef {Object} SQLERUniversalOptions
* @property {Object} db The database options that contain _private_ sensitive configuration. Each property should correspond to a {@link SQLERPrivateOptions} instance and the property name should
* be linked to a {@link SQLERConnectionOptions} `id` within `conf.db.connections`. Each {@link SQLERPrivateOptions} instance will be used to connect to the underlying database
* (e.g. `{ db: myConnId: { host: "someDbhost.example.com", username: "someUser", password: "somePass" } }`)
* @memberof typedefs
*/
/**
* Options for connections used by {@link Manager}
* @typedef {Object} SQLERConnectionOptions
* @property {String} id Identifies the connection within a {@link SQLERPrivateOptions}
* @property {String} dialect The database dialect (e.g. mysql, mssql, oracle, etc.)
* @property {String} name The name given to the database used as the property name on the {@link Manager} to access generated SQL functions (e.g. `name = 'example'` would result in a SQL function
* connection container `manager.db.example`). The _name_ will also be used as the _cwd_ relative directory used when no dir is defined
* @property {String} [dir=name] The alternative dir where `*.sql` files will be found relative to `mainPath` passed into a {@link Manager} constructor. The directory path will be used as the basis
* for generating SQL statements from discovered SQL files. Each will be made accessible in the manager by name followed by an object for each name separated by period(s)
* within the file name with the last entry as the executable {@link SQLERPreparedFunction}. For example, a connection named "conn1" and a SQL file named "user.team.details.sql" will be accessible within the manager
* as "mgr.db.conn1.user.team.details()". But when `dir` is set to "myDir" the SQL files will be loaded from the "myDir" directory (relative to `mainPath`) instead of the default directory that matches the connection
* name "conn1".
* @property {Float} [version] A version that can be used for version substitutions within an SQL statement
* @property {String} [service] The service name defined by the underlying database (may be required depending on the implementing {@link Dialect}
* @property {Object} [binds] The global object that contains bind variable values that will be included in all SQL calls made under the connection for parameter `binds` if not overridden
* by individual "binds" passed into the {@link SQLERPreparedFunction}
* @property {Object} [substitutes] Key/value pairs that define global/static substitutions that will be made in prepared statements by replacing occurances of keys with corresponding values
* @property {String} [host] The database host override for a value specified in {@link SQLERPrivateOptions}
* @property {String} [port] The database port override for a value specified in {@link SQLERPrivateOptions}
* @property {String} [protocol] The database protocol override for a value specified in {@link SQLERPrivateOptions}
* @property {(Function | Boolean)} [dateFormatter] A `function(date)` that will be used to format bound dates into string values for {@link SQLERPreparedFunction} calls. Set to a truthy value to
* perform `date.toISOString()`. __Gets overridden by the same option set on {@link SQLERExecOptions}__.
* @property {Object} [driverOptions] Options passed directly into the {@link Dialect} driver
* @property {(Boolean | String[])} [log] When _logging_ is turned on for a given {@link Manager}, the specified tags will prefix the log output. Explicity set to `false` to disable
* connection _log_ level logging even if it is turned on via the {@link Manager}.
* @property {(Boolean | String[])} [logError] When _logging_ is turned on for a given {@link Manager}, the specified tags will prefix the error log output. Explicity set to `false` to disable
* connection _error_ level logging even if it is turned on via the {@link Manager}.
* @property {Object} [pool] The connection pool options (__overrides any `driverOptions` that may pertain the pool__)
* @property {Number} [pool.max] The maximum number of connections in the pool. When `pool.min` and `pool.max` are the same, `pool.increment` should typically be set to _zero_.
* (__overrides any `driverOptions` that may pertain the pool max__)
* @property {Number} [pool.min] The minumum number of connections in the pool. When `pool.min` and `pool.max` are the same, `pool.increment` should typically be set to _zero_.
* (__overrides any `driverOptions` that may pertain the pool min__)
* @property {Number} [pool.idle] The maximum time, in milliseconds, that a connection can be idle before being released (__overrides any `driverOptions` that may pertain the pool idle__)
* @property {Number} [pool.increment] The number of connections that are opened whenever a connection request exceeds the number of currently open connections.
* When `pool.min` and `pool.max` are the same, `pool.increment` should typically be set to _zero_.
* (__overrides any `driverOptions` that may pertain the pool increment__)
* @property {Number} [pool.timeout] The number of milliseconds that a connection request should wait in the queue before the request is terminated
* (__overrides any `driverOptions` that may pertain the pool timeout__)
* @property {String} [pool.alias] __When supported__, the alias of this pool in the connection pool cache (__overrides any `driverOptions` that may pertain the pool alias__)
* @memberof typedefs
*/
/**
* Options that are passed to generated {@link SQLERPreparedFunction}.
* __NOTE: Either `transaction.commit` or `trnasaction.rollback` must be invoked when `autoCommit` is _falsy_ and a valid `transactionId` is supplied to ensue underlying connections are
* completed and closed.__
* @typedef {Object} SQLERExecOptions
* @property {String} [name] A name to assign to the execution.
* @property {String} [type] The type of CRUD operation that is being executed (i.e. `CREATE`, `READ`, `UPDATE`, `DELETE`). __Mandatory only when the
* generated/prepared SQL function was generated from a SQL file that was not prefixed with a valid CRUD type.__
* @property {Number} [stream] A value `stream >= 0`, indicates that the execution will be streamed (ideal for large reads/writes). The resulting `rows` will contain either a
* [`stream.Readable[]`](https://nodejs.org/api/stream.html#stream_class_stream_readable) or a [`stream.Writable[]`](https://nodejs.org/api/stream.html#stream_class_stream_writable)
* (depending upon the `type`) instead of the default `Object[]` rows. When supported by the dialect, streams will be __batched__ using the indicated stream count as the batch size (a value of `0` is the
* same as a value of `1`).
* @property {Object} [binds={}] The key/value pair of binding parameters that will be bound in the SQL statement.
* @property {Boolean} [autoCommit=true] Truthy to perform a commits the transaction at the end of the prepared function execution. __NOTE: When falsy the underlying connection will remain open
* until the returned {@link SQLERExecResults} `commit` or `rollback` is called.__ [See AutoCommit](https://en.wikipedia.org/wiki/Autocommit) for more details.
* @property {String} [transactionId] A transaction ID returned from a prior call to `const tx = await manager.db.myConnectionName.beginTransaction(); options.transactionId = tx.id` that will be used when
* executing the {@link SQLERPreparedFunction}. The generated `transactionId` helps to isolate executions to a single open connection in order to prevent inadvertently making changes on database
* connections used by other transactions that may also be in progress. The `transactionId` is ignored when there is no transaction in progress with the specified `transactionId`.
* @property {Boolean} [prepareStatement] Truthy to generate or use an existing prepared statement for the SQL being executed via the {@link SQLERPreparedFunction}.
* Prepared statements _may_ help optimize SQL that is executed many times across the same connection with similar or different bind values.
* __Care must be taken not to drain the connection pool since the connection remains open until the SQL executions have completed and `unprepare` has been called on the {@link SQLERExecResults}.__
* returned from the {@link SQLERPreparedFunction} call.
* @property {(Function | Boolean)} [dateFormatter] A `function(date)` that will be used to format bound dates into string values for {@link SQLERPreparedFunction} calls. Set to a truthy value to
* perform `date.toISOString()`. __Overrides the same option set on {@link SQLERConnectionOptions}__.
* @property {Number} numOfPreparedFuncs The total number of {@link SQLERPreparedFunction}(s) that reside within the manager
* @property {Object} [driverOptions] Options that may override the {@link SQLERConnectionOptions} for `driverOptions` that may be passed into the {@link Manager} constructor
* @memberof typedefs
*/
// TODO : @property {String} [locale] The [BCP 47 language tag](https://tools.ietf.org/html/bcp47) locale that will be used for formatting dates contained in the `opts` bind variable values (when present)
/**
* Internally generated metadata that is passed into {@link Dialect.exec} by a {@link Manager} for determining SQL sources.
* @typedef {Object} SQLERExecMeta
* @property {String} name The composed name given to a given SQL file
* @property {String} path The path to the SQL file
* @memberof typedefs
*/
/**
* Options for handling any errors that occur during execution.
* @typedef {Object} SQLERExecErrorOptions
* @property {Function} [handler] A `function(error)` that will handle any errors thrown. The errors should contain a `sqler` property containing
* @property {Boolean} [includeBindValues] Truthy to include the bind parameter values `error.sqler`.
* @property {Boolean} [returnErrors] Truthy to return any errors that may occur. Otherwise, throw any errors that may occur.
* @memberof typedefs
*/
/**
* Prepared functions are auto-generated `async` functions that execute an SQL statement from an SQL file source.
* @async
* @callback SQLERPreparedFunction
* @param {SQLERExecOptions} [opts] The SQL execution options
* @param {String[]} [frags] Consists of any fragment segment names present in the SQL being executed that will be included in the final SQL statement. Any fragments present
* in the SQL source will be excluded from the final SQL statement when there is no matching fragment name.
* @param {(SQLERExecErrorOptions | Boolean)} [errorOpts] Either the error handling options or a boolean flag indicating that any errors that occur during execution should be returned in
* the {@link SQLERExecResults} rather then being thrown.
* @returns {SQLERExecResults} The execution results
* @memberof typedefs
*/
/**
* Results returned from invoking a {@link SQLERPreparedFunction}.
* @typedef {Object} SQLERExecResults
* @property {(Object[] | Stream.Readable[] | Stream.Writable[])} [rows] The execution array of model objects representing each row or `undefined` when executing a non-read SQL statement.
* When streaming the resulting `rows` will contain either a [`stream.Readable[]`](https://nodejs.org/api/stream.html#stream_class_stream_readable) or a
* [`stream.Writable[]`](https://nodejs.org/api/stream.html#stream_class_stream_writable) instead of the default `Object[]` rows.
* @property {Function} [unprepare] A no-argument _async_ function that unprepares an outstanding prepared statement. Will not be available when the {@link SQLERPreparedFunction} is called
* when the specified `prepareStatement` is _falsy_ on the {@link SQLERExecOptions} passed into the {@link SQLERPreparedFunction}. When a prepared statement is used in conjunction with a
* {@link SQLERTransaction} `transactionId` on the {@link SQLERExecOptions}, `unprepare` will be implicitly called when `transaction.commit` or `transaction.rollback` are called (of course,
* `unprepare` can still be explicitly called as well).
* __NOTE: A call to `unprepare` must be invoked when a `prepareStatement` is _truthy_ to ensue underlying statements and/or connections are completed and closed.__
* @property {Error} [error] Any caught error that occurred when a {@link SQLERPreparedFunction} was invoked with the `errorOpts` flag set to a _truthy_ value.
* @property {Object} raw The raw results from the execution (driver-specific execution results).
* @memberof typedefs
*/
/**
* Function that commits an outstanding transaction.
* @callback SQLERTransactionCommit
* @param {Boolean} [isRelease] When truthy, releases the connection back to the connection pool after a _commit_ has been performed.
* It's essential that connections be released back into the connection pool to ensure that there are enough available connections for other independent executions that use the same pool.
* @async
* @memberof typedefs
*/
/**
* Function that rolls back an outstanding transaction.
* @callback SQLERTransactionRollback
* @param {Boolean} [isRelease] When truthy, releases the connection back to the connection pool after a _rollback_ has been performed.
* It's essential that connections be released back into the connection pool to ensure that there are enough available connections for other independent executions that use the same pool.
* @async
* @memberof typedefs
*/
/**
* Transaction that symbolizes a unit of work performed within a {@link Manager} connection.
* @typedef {Object} SQLERTransaction
* @property {String} id The unique identifier for the transaction.
* @property {SQLERTransactionCommit} commit Rolls back the outstanding transaction.
* @property {SQLERTransactionRollback} rollback Commits the outstanding transaction.
* @property {Object} state The state of the transaction
* @property {Number} state.committed True when the transaction has been committed.
* @property {Number} state.rolledback True when the transaction has been rolledback.
* @property {Number} state.pending The number of pending SQL statements executed within the scope of the given transaction that have not been committed or rolledback.
* @property {Boolean} state.isReleased Truthy when the transaction has been released.
* @memberof typedefs
*/
/**
* Options for a {@link SQLERTransaction} that can be passed into a `manager.connectionName.beginTransaction(transactionDriverOptions)` function.
* @typedef {Object} SQLERTransactionOptions
* @memberof typedefs
*/
/**
* Options for operational methods on a {@link Manager} (e.g. {@link Manager.init}, {@link Manager.state}, {@link Manager.close}, etc.).
* @typedef {Object} SQLEROperationOptions
* @property {Object} [connections] An object that contains connection names as properties. Each optionally containing an object with `errorOpts` and/or `executeInSeries`
* that will override any global options set directly on the {@link SQLEROperationOptions}. For example, `opts.connections.myConnection.executeInseries` would override
* `opts.executeInSeries` for the connection named `myConnection`, but would use `opts.executeInSeries` for any other connections that ae not overridden.
* @property {Boolean} [executeInSeries] Set to truthy to execute the operation in series, otherwise executes operation in parallel.
* @property {(SQLERExecErrorOptions | Boolean)} [errorOpts] Set to truthy to return any errors. Otherise throw any errors as they are encountered. options can also be set instead.
* @memberof typedefs
*/
/**
* Results returned from invoking an operational method on a {@link Manager} (e.g. {@link Manager.init}, {@link Manager.state}, {@link Manager.close}, etc.).
* @typedef {Object} SQLEROperationResults
* @property {Object} result An object that contains a property name that matches each connection that was processed (the property value is the number of operations processed per connection).
* @property {Error[]} errors Any errors that may have occurred on the operational methods. Should only be populated when {@link SQLEROperationOptions} are used with a truthy value set on
* `errorOpts`. Each will contain meta properties set by [Asynchro](https://ugate.github.io/asynchro).
* @memberof typedefs
*/
/**
* Options that are used during initialization
* @typedef {Object} SQLERInitOptions
* @property {Number} numOfPreparedFuncs The total number of {@link SQLERPreparedFunction}(s) registered on the {@link Dialect}
* @memberof typedefs
*/
/**
* The current state of the managed {@link Dialect}
* @typedef {Object} SQLERState
* @property {Number} pending The number of transactions that are pending `commit` or `roolback` plus any prepared statements that are pending
* `unprepare`.
* @property {Object} [connections] The connection state
* @property {Number} [connections.count] The number of connections
* @property {Number} [connections.inUse] The number of connections that are in use
* @memberof typedefs
*/
/**
* A validation for validating interpolation used by a {@link SQLERInterpolateFunction}
* @callback SQLERInterpolateValidationFunction
* @param {String[]} srcPropNames Property path(s) to the value being validated (e.g. `source.my.path = 123` would equate to
* a invocation to `validator(['my','path'], 123)`).
* @param {*} srcPropValue The value being validated for interpolation
* @returns {Boolean} Flag indicating whether or not to include the interpolated property/value
* @memberof typedefs
*/
/**
* Interpolates values from a _source_ object to a _destination_ object.
* When a value is a string surrounded by `${}`, it will be assumed to be a interpolated property that resides on _another_ property on the `source`
* or an interpolated property on the `interpolator`.
* For example `source.someProp = '${SOME_VALUE}'` will be interpreted as `dest.someProp = dest.SOME_VALUE` when the `interpolator` is omitted and
* `dest.someProp = interpolator.SOME_VALUE` when an `interpolator` is specified.
* __Typically only used by implementing {@link Dialect} constructors within a {@link SQLERTrack}.__
* @callback SQLERInterpolateFunction
* @param {Object} dest The destination where the sources will be set (also the interpolated source when `interpolator` is omitted).
* @param {Object} source The source of the values to interpolate (e.g. {@link SQLERConnectionOptions}, {@link SQLERExecOptions}, etc.).
* @param {Object} [interpolator=dest] An alternative source to use for extracting interpolated values from.
* @param {SQLERInterpolateValidationFunction} [validator] A validation function for each property/value being interpolated to determine
* if it will be interolated.
* @param {Boolean} [onlyInterpolated] Truthy to indicate that the only values that will be set from the `source`/`interpolator` will be values that
* have been interpolated. __NOTE: Truthy values will not prevent `source`/`interpolator` objects from getting set on `dest`, just non-interpoalted
* property values will be skipped__ (i.e. property values that do not contain `${}` interpolation designations).
* @returns {Object} The passed destination
* @memberof typedefs
*/
/**
* Converts a SQL statement that contains named bind parameters into a SQL statement that contains unnamed/positional bind parameters (using `?`).
* Each bound parameter is pushed to the array in the position that corresponds to the position within the SQL statement.
* @callback SQLERPositionalBindsFunction
* @param {String} sql The SQL statement that contains the bind parameters
* @param {Object} bindsObject An object that contains the bind parameters as property names/values
* @param {Array} bindsArray The array that will be populated with the bind parameters
* @param {(String | Function)} [placeholder=?] Either a string value that will be used for the postional placeholder or a `function(name, index)` that
* returns a value that will be used as the positional placeholder.
* @returns {String} The converted SQL statement
* @throws {Error} Thrown when a bound parameter is not within the orgiginating SQL statement
* @memberof typedefs
*/
/**
* Expands _bind_ variables that contain an array of values when they appear in the SQL statement. For example, an SQL statement with a section that contains
* `IN (:someParam)` and _binds_ of `{ someParam: [1,2,3] }` would become `IN (:someParam, :someParam1, :someParam2)` with _binds_ of `{ someParam: 1, someParam1: 2, SomeParam2: 3 }`
* @callback SQLERBindExpansionFunction
* @param {String} sql The SQL to defragement
* @param {Object} [binds] An object that contains the SQL parameterized `binds` that will be used for parameterized array composition
* @returns {String} The defragmented SQL
* @memberof typedefs
*/
/**
* Processes a read batch of streamed objects for a particular dialect implementation.
* @async
* @callback SQLERStreamReader
* @param {Object[]} batch The batch of streamed objects based upon a predefined `stream` batch size in {@link SQLERExecOptions}.
* @returns {*} A value that will be emitted on a readable stream.
* @memberof typedefs
*/
/**
* Writes a batch of streamed objects for a particular dialect implementation and returns the raw results.
* @async
* @callback SQLERStreamWritter
* @param {Object[]} batch The batch of streamed objects based upon a predefined `stream` batch size in {@link SQLERExecOptions}.
* @returns {*} The _raw_ batch execution results from the dialect execution and will be emitted on a writable stream.
* @memberof typedefs
*/
/**
* Function that internally handles the specified {@link SQLERExecOptions} `stream` batch size and emits a batch event when the batch size
* threshold has been reached on a specified [`stream.Readable`](https://nodejs.org/api/stream.html#stream_class_stream_readable).
* @callback SQLERStreamReadableProcessor
* @param {SQLERExecOptions} opts The execution options
* @param {Stream.Readable} readStream The readable stream that will produce the SQL results
* @param {SQLERStreamReader} [reader] The function that will process the batch read
* @returns {Stream.Readable} The readable stream that was passed
* @memberof typedefs
*/
/**
* Function that will generate a {@link Stream.Writable} that internally handles the specified {@link SQLERExecOptions} `stream` batch size and emits
* a batch event when the batch size threshold has been reached.
* @callback SQLERStreamWritable
* @param {SQLERExecOptions} opts The execution options
* @param {SQLERStreamWritter} writter The function that will process the batch write
* @returns {Stream.Writable} The writable stream that will handle the `sqler` internals
* @memberof typedefs
*/
/**
* A tracking mechanism that is shared between all {@link Dialect} implementations for a given {@link Manager}. A track provides a means to share
* data, etc. from one {@link Dialect} to another. Properties can also be _added_ by a {@link Dialect} for use in other {@link Dialect}s.
* __Typically only used by implementing {@link Dialect} constructors.__
* @typedef {Object} SQLERTrack
* @property {SQLERInterpolateFunction} interpolate An interpolation function that can be used by {@link Dialect} implementations to interpolate
* configuration option values from underlying drivers within a {@link Dialect} (immutable). The convenience of doing so negates the need for an
* application that uses a {@link Manager} to import/require a database driver just to access driver constants, etc.
* @property {SQLERPositionalBindsFunction} positionalBinds A function that will convert an SQL statement with named binds into positional binds.
* @property {SQLERBindExpansionFunction} bindExpansions A function that takes an SQL statement with named binds and expands the bind variables
* into an array of values when they appear in the SQL statement
* @property {SQLERStreamReadableProcessor} readable A function that uses a specified readable stream for batching large number of read executions.
* @property {SQLERStreamWritable} writable A function that will generate a writable stream for batching large number of write executions.
* @memberof typedefs
*/