typedefs.js

'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
 */

9.0.0 (2021-08-18)

Full Changelog

Breaking Changes:

Features: