UNPKG

lupdo

Version:

Database Abstraction Layer for Node js

215 lines (176 loc) 8.24 kB
# Available Drivers - [lupdo-mysql](https://www.npmjs.com/package/lupdo-mysql) - [lupdo-sqlite](https://www.npmjs.com/package/lupdo-sqlite) - [lupdo-postgres](https://www.npmjs.com/package/lupdo-postgres) - [lupdo-mssql](https://www.npmjs.com/package/lupdo-mssql) ## WRITE CUSTOM DRIVER Custom Lupdo Driver must implements a sql syntax; only string can be used to perform query against a database. Please follow this rules if you can: - supports all Lupdo validBindings - number - string - bigint - Buffer - Date - boolean - null - BaseTypedBinding - (number|string|bigint|Buffer|Date|boolean|null|BaseTypedBinding)[] - supports the syntax of named parameters `:key` and the syntax of numeric parameters `?`, adds documentation for other syntax types. - **date** from database should be returned as javascript `String`. - **time** from database should be returned as javascript `String`. - **bigint** from database should be returned as javascript `String`. - **decimal** from database should be returned as javascript `String`. - **numeric int** from database shold be returned as javascript `Number`. - **numeric float** from database should be returned as javascript `String`. - **boolean** should be returned as javascript `Boolean`. - **json** should be always returned as `String` not an `Object`. - **array** should be returned as Javascript `Array` and value of array should respect rules above. - you should only expose custom Driver APIs if necessary to integrate basic database functionality. - you should override/suppress third party configuration if they can change lupdo core behaviour based on unsecure parameter of createConnection (see example). - you are free to add ATTRIBUTES if necessary _please prefix all attributes with unique driver name_. - you must avoid to override any core funtionality, you can open a discussion or propose a pull-request. - import or require of the library must automatically register the driver within Lupdo. - driver should export a function `create{driver}Pdo` that return a new instance of Pdo for the driver to improve options typing. - you can create a new version of existing driver using another thirdy party library, you should avoid to implements duplicated version with same third party driver, instead try to improve the existing one. - you can add a new type parameter to be used on `TypedBinding` and implement `TypedBindingOptions` for all `TypeBinding`, please document all options and the new accepted type. > **Note** > As soon as it will be stable, Lupdo will accept [Temporal](https://tc39.es/proposal-temporal/docs/) as validBindings. ## FULL EXAMPLE ```ts import { ATTR_DEBUG, DEBUG_ENABLED, Pdo, PdoConnection, PdoConnectionI, PdoDriver, PdoRawConnection, PdoRawConnectionI } from 'lupdo'; import PdoAffectingData from 'lupdo/dist/typings/types/pdo-affecting-data'; import PdoAttributes from 'lupdo/dist/typings/types/pdo-attributes'; import PdoColumnData from 'lupdo/dist/typings/types/pdo-column-data'; import { DriverOptions } from 'lupdo/dist/typings/types/pdo-driver'; import { PoolConnection, PoolOptions } from 'lupdo/dist/typings/types/pdo-pool'; import { ValidBindingsSingle } from 'lupdo/dist/typings/types/pdo-prepared-statement'; import PdoRowData from 'lupdo/dist/typings/types/pdo-raw-data'; interface ThirdPartyConnectionOptions extends DriverOptions { [key: string]: any; } class ThirdPartyConnectionToDB implements PoolConnection { // __lupdo_xxx property are used internally from lupdo // should be defined like this __lupdo_uuid = ''; __lupdo_killed = false; constructor(public options: ThirdPartyConnectionOptions) {} } class ThirdPartyStatement {} // FakeConnection should be used only to set session variables on the connection before it gets used. class FakeConnection extends PdoConnection { constructor(public readonly connection: ThirdPartyConnectionToDB) { super(); } async query(sql: string): Promise<void> { // execute third party query } } class FakeRawConnection extends PdoRawConnection { protected async doBeginTransaction(connection: ThirdPartyConnectionToDB): Promise<void> { // exec third party connection begin transaction } protected async doCommit(connection: ThirdPartyConnectionToDB): Promise<void> { // exec third party connection commit } protected async doRollback(connection: ThirdPartyConnectionToDB): Promise<void> { // exec third party connection rollback } protected async getStatement(sql: string, connection: ThirdPartyConnectionToDB): Promise<ThirdPartyStatement> { // return third party connection statement return new ThirdPartyStatement(); } protected async executeStatement( statement: ThirdPartyStatement, bindings: string[] | { [key: string]: string }, connection: ThirdPartyConnectionToDB ): Promise<[string, PdoAffectingData, PdoRowData[], PdoColumnData[]]> { // return adapted data from third party statement execution // sql returned must be sql string propagated to the driver return [sql, {}, [], []]; } protected async closeStatement( statement: ThirdPartyStatement, connection: ThirdPartyConnectionToDB ): Promise<void> { // close third party statement } protected async doQuery( connection: ThirdPartyConnectionToDB, sql: string ): Promise<[PdoAffectingData, PdoRowData[], PdoColumnData[]]> { // return adapted data from third party query execution return [{}, [], []]; } protected adaptBindValue(value: ValidBindingsSingle): ValidBindingsSingle { // adapt parameter bindings before execute third party statement return value; } } class FakeDriver extends PdoDriver { constructor( driver: string, protected options: ThirdPartyConnectionOptions, poolOptions: PoolOptions, attributes: PdoAttributes ) { super(driver, poolOptions, attributes); } protected async createConnection(unsecure?: boolean): Promise<ThirdPartyConnectionToDB> { const { ...thirdPartyOptions } = this.options; // debugmode must be enabled only through ATTR_DEBUG const debugMode = this.getAttribute(ATTR_DEBUG) as number; if (!unsecure) { // unsecure is true only if pdo.getRawDriverConnection() is called // in that case the connection it's not acquired from the pool // so it will never be reused by lupdo core apis // and you can skip overrides, it's up to the user manage connection thirdPartyOptions.doNotReturnColumns = false; thirdPartyOptions.numberAlwaysString = false; } return new ThirdPartyConnectionToDB({ ...thirdPartyOptions, debug: debugMode === DEBUG_ENABLED }); } protected createPdoConnection(connection: ThirdPartyConnectionToDB): PdoConnectionI { // return new PdoConnection // it should be a basic connection that can execute only not prepared sql // it should be used only to set session variables on the third party connection before it gets used. return new FakeConnection(connection); } protected async closeConnection(connection: ThirdPartyConnectionToDB): Promise<void> { // close connection } protected async destroyConnection(connection: ThirdPartyConnectionToDB): Promise<void> { // if available get new connection to force kill pending connection } protected validateRawConnection(): boolean { // validate third party connection before will be used by the pool return true; } public getRawConnection(): PdoRawConnectionI { return new FakeRawConnection(this.pool); } public async getVersion(): Promise<string> { return '1.0.0-fake'; } } Pdo.addDriver('fake', FakeDriver); export function createFakePdo( options: ThirdPartyConnectionOptions, poolOptions?: PoolOptions, attributes?: PdoAttributes ): Pdo { return new Pdo('fake', options, poolOptions, attributes); } ```