├── .editorconfig ├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── index.d.ts ├── lib ├── Connection.d.ts ├── Pool.d.ts ├── PoolCluster.d.ts ├── PoolConnection.d.ts └── protocol │ ├── packets │ ├── Field.d.ts │ ├── FieldPacket.d.ts │ ├── OkPacket.d.ts │ ├── ResultSetHeader.d.ts │ ├── RowDataPacket.d.ts │ └── index.d.ts │ └── sequences │ ├── Query.d.ts │ └── Sequence.d.ts ├── package.json ├── test ├── test.ts └── tsconfig.json ├── tsconfig.json ├── tslint.json └── typings.json /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | [*] 3 | end_of_line = lf 4 | insert_final_newline = true 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | 10 | [*.{json,yml}] 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bundle.d.ts 2 | node_modules/ 3 | .vscode/ 4 | *.js 5 | typedoc/ 6 | typings/ 7 | typedoc/ 8 | package-lock.json 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '6' 4 | install: 5 | - npm install 6 | - typings install 7 | script: 8 | - npm run lint 9 | - npm run build 10 | - npm test 11 | before_deploy: 12 | - npm run typedoc 13 | deploy: 14 | skip_cleanup: true 15 | provider: surge 16 | project: ./typedoc/ 17 | domain: typed-mysql.surge.sh 18 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2016, Felix Frederick Becker 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Typed mysql 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/types/mysql.svg)](https://greenkeeper.io/) 4 | [![Build Status](https://travis-ci.org/types/mysql.svg?branch=master)](https://travis-ci.org/types/mysql) 5 | 6 | Typescript Typings for [mysql](https://www.npmjs.com/package/mysql). 7 | 8 | ## [API Documentation](http://typed-mysql.surge.sh) 9 | 10 | ## Installation 11 | ```sh 12 | typings install --save mysql 13 | ``` 14 | or 15 | ```sh 16 | npm install --save-dev types/mysql#semver:version 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```ts 22 | import {createConnection, QueryError, RowDataPacket} from 'mysql'; 23 | 24 | const connection = createConnection(process.env['DB']); 25 | 26 | connection.query('SELECT 1 + 1 AS solution', (err: QueryError, rows: RowDataPacket[]) => { 27 | console.log('The solution is: ', rows[0]['solution']); 28 | }); 29 | 30 | connection.query('UPDATE posts SET title = ? WHERE id = ?', ['Hello World', 1], (err: mysql.QueryError, result: mysql.OkPacket) => { 31 | console.log(result.affectedRows); 32 | }); 33 | ``` 34 | 35 | [More examples](./test) 36 | 37 | 38 | ## Contributing 39 | You can run them the tests with `npm run build` and `npm run test`. 40 | 41 | -------------------------------- 42 | 43 | _Based on typings by [William Johnston](https://github.com/wjohnsto)_ 44 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import BaseConnection = require('./lib/Connection'); 3 | import {ConnectionOptions, SslOptions} from './lib/Connection'; 4 | import BasePoolConnection = require('./lib/PoolConnection'); 5 | import BasePool = require('./lib/Pool'); 6 | import {PoolOptions} from './lib/Pool'; 7 | import BasePoolCluster = require('./lib/PoolCluster'); 8 | import {PoolClusterOptions} from './lib/PoolCluster'; 9 | import BaseQuery = require('./lib/protocol/sequences/Query'); 10 | import {QueryOptions, StreamOptions, QueryError} from './lib/protocol/sequences/Query'; 11 | 12 | export function createConnection(connectionUri: string): Connection; 13 | export function createConnection(config: BaseConnection.ConnectionOptions): Connection; 14 | export function createPool(config: BasePool.PoolOptions): Pool; 15 | export function createPoolCluster(config?: BasePoolCluster.PoolClusterOptions): PoolCluster; 16 | export function escape(value: any): string; 17 | export function format(sql: string): string; 18 | export function format(sql: string, values: any[]): string; 19 | export function format(sql: string, values: any): string; 20 | 21 | export { 22 | ConnectionOptions, 23 | SslOptions, 24 | PoolOptions, 25 | PoolClusterOptions, 26 | QueryOptions, 27 | QueryError 28 | }; 29 | export * from './lib/protocol/packets/index'; 30 | 31 | // Expose class interfaces 32 | export interface Connection extends BaseConnection {} 33 | export interface PoolConnection extends BasePoolConnection {} 34 | export interface Pool extends BasePool {} 35 | export interface PoolCluster extends BasePoolCluster {} 36 | export interface Query extends BaseQuery {} 37 | -------------------------------------------------------------------------------- /lib/Connection.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import Query = require('./protocol/sequences/Query'); 3 | import {OkPacket, FieldPacket, RowDataPacket, ResultSetHeader} from './protocol/packets/index'; 4 | import {EventEmitter} from 'events'; 5 | 6 | declare namespace Connection { 7 | 8 | export interface ConnectionOptions { 9 | /** 10 | * The MySQL user to authenticate as 11 | */ 12 | user?: string; 13 | 14 | /** 15 | * The password of that MySQL user 16 | */ 17 | password?: string; 18 | 19 | /** 20 | * Name of the database to use for this connection 21 | */ 22 | database?: string; 23 | 24 | /** 25 | * The charset for the connection. This is called 'collation' in the SQL-level of MySQL (like utf8_general_ci). 26 | * If a SQL-level charset is specified (like utf8mb4) then the default collation for that charset is used. 27 | * (Default: 'UTF8_GENERAL_CI') 28 | */ 29 | charset?: string; 30 | 31 | /** 32 | * The hostname of the database you are connecting to. (Default: localhost) 33 | */ 34 | host?: string; 35 | 36 | /** 37 | * The port number to connect to. (Default: 3306) 38 | */ 39 | port?: number; 40 | 41 | /** 42 | * The source IP address to use for TCP connection 43 | */ 44 | localAddress?: string; 45 | 46 | /** 47 | * The path to a unix domain socket to connect to. When used host and port are ignored 48 | */ 49 | socketPath?: string; 50 | 51 | /** 52 | * The timezone used to store local dates. (Default: 'local') 53 | */ 54 | timezone?: string | 'local'; 55 | 56 | /** 57 | * The milliseconds before a timeout occurs during the initial connection to the MySQL server. (Default: 10 seconds) 58 | */ 59 | connectTimeout?: number; 60 | 61 | /** 62 | * Stringify objects instead of converting to values. (Default: 'false') 63 | */ 64 | stringifyObjects?: boolean; 65 | 66 | /** 67 | * Allow connecting to MySQL instances that ask for the old (insecure) authentication method. (Default: false) 68 | */ 69 | insecureAuth?: boolean; 70 | 71 | /** 72 | * Determines if column values should be converted to native JavaScript types. It is not recommended (and may go away / change in the future) 73 | * to disable type casting, but you can currently do so on either the connection or query level. (Default: true) 74 | * 75 | * You can also specify a function (field: any, next: () => void) => {} to do the type casting yourself. 76 | * 77 | * WARNING: YOU MUST INVOKE the parser using one of these three field functions in your custom typeCast callback. They can only be called once. 78 | * 79 | * field.string() 80 | * field.buffer() 81 | * field.geometry() 82 | * 83 | * are aliases for 84 | * 85 | * parser.parseLengthCodedString() 86 | * parser.parseLengthCodedBuffer() 87 | * parser.parseGeometryValue() 88 | * 89 | * You can find which field function you need to use by looking at: RowDataPacket.prototype._typeCast 90 | */ 91 | typeCast?: boolean | ((field: any, next: () => void) => any); 92 | 93 | /** 94 | * A custom query format function 95 | */ 96 | queryFormat?: (query: string, values: any) => void; 97 | 98 | /** 99 | * When dealing with big numbers (BIGINT and DECIMAL columns) in the database, you should enable this option 100 | * (Default: false) 101 | */ 102 | supportBigNumbers?: boolean; 103 | 104 | /** 105 | * Enabling both supportBigNumbers and bigNumberStrings forces big numbers (BIGINT and DECIMAL columns) to be 106 | * always returned as JavaScript String objects (Default: false). Enabling supportBigNumbers but leaving 107 | * bigNumberStrings disabled will return big numbers as String objects only when they cannot be accurately 108 | * represented with [JavaScript Number objects] (http://ecma262-5.com/ELS5_HTML.htm#Section_8.5) 109 | * (which happens when they exceed the [-2^53, +2^53] range), otherwise they will be returned as Number objects. 110 | * This option is ignored if supportBigNumbers is disabled. 111 | */ 112 | bigNumberStrings?: boolean; 113 | 114 | /** 115 | * Force date types (TIMESTAMP, DATETIME, DATE) to be returned as strings rather then inflated into JavaScript Date 116 | * objects. Can be true/false or an array of type names to keep as strings. 117 | * 118 | * (Default: false) 119 | */ 120 | dateStrings?: boolean | Array<'TIMESTAMP' | 'DATETIME' | 'DATE'>; 121 | 122 | /** 123 | * This will print all incoming and outgoing packets on stdout. 124 | * You can also restrict debugging to packet types by passing an array of types (strings) to debug; 125 | * 126 | * (Default: false) 127 | */ 128 | debug?: any; 129 | 130 | /** 131 | * Generates stack traces on Error to include call site of library entrance ('long stack traces'). Slight 132 | * performance penalty for most calls. (Default: true) 133 | */ 134 | trace?: boolean; 135 | 136 | /** 137 | * Allow multiple mysql statements per query. Be careful with this, it exposes you to SQL injection attacks. (Default: false) 138 | */ 139 | multipleStatements?: boolean; 140 | 141 | /** 142 | * List of connection flags to use other than the default ones. It is also possible to blacklist default ones 143 | */ 144 | flags?: Array; 145 | 146 | /** 147 | * object with ssl parameters or a string containing name of ssl profile 148 | */ 149 | ssl?: string | SslOptions; 150 | } 151 | 152 | export interface SslOptions { 153 | /** 154 | * A string or buffer holding the PFX or PKCS12 encoded private key, certificate and CA certificates 155 | */ 156 | pfx?: string; 157 | 158 | /** 159 | * A string holding the PEM encoded private key 160 | */ 161 | key?: string; 162 | 163 | /** 164 | * A string of passphrase for the private key or pfx 165 | */ 166 | passphrase?: string; 167 | 168 | /** 169 | * A string holding the PEM encoded certificate 170 | */ 171 | cert?: string; 172 | 173 | /** 174 | * Either a string or list of strings of PEM encoded CA certificates to trust. 175 | */ 176 | ca?: string | string[]; 177 | 178 | /** 179 | * Either a string or list of strings of PEM encoded CRLs (Certificate Revocation List) 180 | */ 181 | crl?: string | string[]; 182 | 183 | /** 184 | * A string describing the ciphers to use or exclude 185 | */ 186 | ciphers?: string; 187 | 188 | /** 189 | * You can also connect to a MySQL server without properly providing the appropriate CA to trust. You should not do this. 190 | */ 191 | rejectUnauthorized?: boolean; 192 | } 193 | } 194 | 195 | declare class Connection extends EventEmitter { 196 | 197 | config: Connection.ConnectionOptions; 198 | threadId: number; 199 | 200 | static createQuery(sql: string, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 201 | static createQuery(sql: string, values: any | any[] | { [param: string]: any }, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 202 | 203 | beginTransaction(callback: (err: Query.QueryError | null) => void): void; 204 | 205 | connect(callback?: (err: Query.QueryError | null) => void): void; 206 | 207 | commit(callback?: (err: Query.QueryError | null) => void): void; 208 | 209 | changeUser(options: Connection.ConnectionOptions, callback?: (err: Query.QueryError | null) => void): void; 210 | 211 | query(sql: string, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 212 | query(sql: string, values: any | any[] | { [param: string]: any }, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 213 | query(options: Query.QueryOptions, callback?: (err: Query.QueryError | null, result: T, fields?: FieldPacket[]) => any): Query; 214 | query(options: Query.QueryOptions, values: any | any[] | { [param: string]: any }, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 215 | 216 | end(callback?: (err: Query.QueryError | null) => void): void; 217 | end(options: any, callback?: (err: Query.QueryError | null) => void): void; 218 | 219 | destroy(): void; 220 | 221 | pause(): void; 222 | 223 | resume(): void; 224 | 225 | escape(value: any): string; 226 | 227 | escapeId(value: string): string; 228 | escapeId(values: string[]): string; 229 | 230 | format(sql: string, values?: any | any[] | { [param: string]: any }): string; 231 | 232 | on(event: string, listener: Function): this; 233 | 234 | rollback(callback: () => void): void; 235 | } 236 | 237 | export = Connection; 238 | -------------------------------------------------------------------------------- /lib/Pool.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import Query = require('./protocol/sequences/Query'); 3 | import {OkPacket, RowDataPacket, FieldPacket, ResultSetHeader} from './protocol/packets/index'; 4 | import Connection = require('./Connection'); 5 | import PoolConnection = require('./PoolConnection'); 6 | import {EventEmitter} from 'events'; 7 | 8 | declare namespace Pool { 9 | 10 | export interface PoolOptions extends Connection.ConnectionOptions { 11 | /** 12 | * The milliseconds before a timeout occurs during the connection acquisition. This is slightly different from connectTimeout, 13 | * because acquiring a pool connection does not always involve making a connection. (Default: 10 seconds) 14 | */ 15 | acquireTimeout?: number; 16 | 17 | /** 18 | * Determines the pool's action when no connections are available and the limit has been reached. If true, the pool will queue 19 | * the connection request and call it when one becomes available. If false, the pool will immediately call back with an error. 20 | * (Default: true) 21 | */ 22 | waitForConnections?: boolean; 23 | 24 | /** 25 | * The maximum number of connections to create at once. (Default: 10) 26 | */ 27 | connectionLimit?: number; 28 | 29 | /** 30 | * The maximum number of connection requests the pool will queue before returning an error from getConnection. If set to 0, there 31 | * is no limit to the number of queued connection requests. (Default: 0) 32 | */ 33 | queueLimit?: number; 34 | 35 | /** 36 | * Enable keep-alive on the socket. It's disabled by default, but the 37 | * user can enable it and supply an initial delay. 38 | */ 39 | enableKeepAlive?: true; 40 | 41 | /** 42 | * If keep-alive is enabled users can supply an initial delay. 43 | */ 44 | keepAliveInitialDelay?: number; 45 | } 46 | } 47 | 48 | declare class Pool extends EventEmitter { 49 | 50 | config: Pool.PoolOptions; 51 | 52 | getConnection(callback: (err: NodeJS.ErrnoException, connection: PoolConnection) => any): void; 53 | 54 | query(sql: string, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 55 | query(sql: string, values: any | any[] | { [param: string]: any }, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 56 | query(options: Query.QueryOptions, callback?: (err: Query.QueryError | null, result: T, fields?: FieldPacket[]) => any): Query; 57 | query(options: Query.QueryOptions, values: any | any[] | { [param: string]: any }, callback?: (err: Query.QueryError | null, result: T, fields: FieldPacket[]) => any): Query; 58 | 59 | end(callback?: (err: NodeJS.ErrnoException | null, ...args: any[]) => any): void; 60 | 61 | on(event: string, listener: Function): this; 62 | on(event: 'connection', listener: (connection: PoolConnection) => any): this; 63 | } 64 | 65 | export = Pool; 66 | -------------------------------------------------------------------------------- /lib/PoolCluster.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import Connection = require('./Connection'); 3 | import PoolConnection = require('./PoolConnection'); 4 | import {EventEmitter} from 'events'; 5 | 6 | declare namespace PoolCluster { 7 | 8 | export interface PoolClusterOptions { 9 | /** 10 | * If true, PoolCluster will attempt to reconnect when connection fails. (Default: true) 11 | */ 12 | canRetry?: boolean; 13 | 14 | /** 15 | * If connection fails, node's errorCount increases. When errorCount is greater than removeNodeErrorCount, 16 | * remove a node in the PoolCluster. (Default: 5) 17 | */ 18 | removeNodeErrorCount?: number; 19 | 20 | /** 21 | * If connection fails, specifies the number of milliseconds before another connection attempt will be made. 22 | * If set to 0, then node will be removed instead and never re-used. (Default: 0) 23 | */ 24 | restoreNodeTimeout?: number; 25 | 26 | /** 27 | * The default selector. (Default: RR) 28 | * RR: Select one alternately. (Round-Robin) 29 | * RANDOM: Select the node by random function. 30 | * ORDER: Select the first node available unconditionally. 31 | */ 32 | defaultSelector?: string; 33 | } 34 | } 35 | 36 | declare class PoolCluster extends EventEmitter { 37 | 38 | config: PoolCluster.PoolClusterOptions; 39 | 40 | add(config: PoolCluster.PoolClusterOptions): void; 41 | add(group: string, config: PoolCluster.PoolClusterOptions): void; 42 | 43 | end(): void; 44 | 45 | getConnection(callback: (err: NodeJS.ErrnoException | null, connection: PoolConnection) => void): void; 46 | getConnection(group: string, callback: (err: NodeJS.ErrnoException | null, connection: PoolConnection) => void): void; 47 | getConnection(group: string, selector: string, callback: (err: NodeJS.ErrnoException | null, connection: PoolConnection) => void): void; 48 | 49 | of(pattern: string, selector?: string): PoolCluster; 50 | 51 | on(event: string, listener: Function): this; 52 | on(event: 'remove', listener: (nodeId: number) => void): this; 53 | on(event: 'connection', listener: (connection: PoolConnection) => void): this; 54 | } 55 | 56 | export = PoolCluster; 57 | -------------------------------------------------------------------------------- /lib/PoolConnection.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import Connection = require('./Connection'); 3 | 4 | declare class PoolConnection extends Connection { 5 | release(): void; 6 | } 7 | 8 | export = PoolConnection; 9 | -------------------------------------------------------------------------------- /lib/protocol/packets/Field.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare interface Field { 3 | constructor: { 4 | name: 'Field' 5 | }; 6 | db: string; 7 | table: string; 8 | name: string; 9 | type: string; 10 | length: number; 11 | string: Function; 12 | buffer: Function; 13 | geometry: Function; 14 | } 15 | 16 | export = Field; 17 | -------------------------------------------------------------------------------- /lib/protocol/packets/FieldPacket.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare interface FieldPacket { 3 | constructor: { 4 | name: 'FieldPacket' 5 | }; 6 | catalog: string; 7 | charsetNr: number; 8 | db: string; 9 | decimals: number; 10 | default: any; 11 | flags: number; 12 | length: number; 13 | name: string; 14 | orgName: string; 15 | orgTable: string; 16 | protocol41: boolean; 17 | table: string; 18 | type: number; 19 | zerofill: boolean; 20 | } 21 | 22 | export = FieldPacket; 23 | -------------------------------------------------------------------------------- /lib/protocol/packets/OkPacket.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare interface OkPacket { 3 | constructor: { 4 | name: 'OkPacket' 5 | }; 6 | fieldCount: number; 7 | affectedRows: number; 8 | changedRows: number; 9 | insertId: number; 10 | serverStatus: number; 11 | warningCount: number; 12 | message: string; 13 | procotol41: boolean; 14 | } 15 | 16 | export = OkPacket; 17 | -------------------------------------------------------------------------------- /lib/protocol/packets/ResultSetHeader.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare interface ResultSetHeader { 3 | constructor: { 4 | name: 'ResultSetHeader' 5 | }; 6 | affectedRows: number; 7 | fieldCount: number; 8 | info: string; 9 | insertId: number; 10 | serverStatus: number; 11 | warningStatus: number; 12 | } 13 | 14 | export = ResultSetHeader; 15 | -------------------------------------------------------------------------------- /lib/protocol/packets/RowDataPacket.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare interface RowDataPacket { 3 | constructor: { 4 | name: 'RowDataPacket' 5 | }; 6 | [column: string]: any; 7 | [column: number]: any; 8 | } 9 | 10 | export = RowDataPacket; 11 | -------------------------------------------------------------------------------- /lib/protocol/packets/index.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import OkPacket = require('./OkPacket'); 3 | import RowDataPacket = require('./RowDataPacket'); 4 | import FieldPacket = require('./FieldPacket'); 5 | import Field = require('./Field'); 6 | import ResultSetHeader = require('./ResultSetHeader'); 7 | 8 | export { 9 | OkPacket, 10 | RowDataPacket, 11 | FieldPacket, 12 | Field, 13 | ResultSetHeader 14 | }; 15 | -------------------------------------------------------------------------------- /lib/protocol/sequences/Query.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import Sequence = require('./Sequence'); 3 | import {OkPacket, RowDataPacket, FieldPacket} from '../packets/index'; 4 | import {Readable} from 'stream'; 5 | 6 | declare namespace Query { 7 | 8 | export interface QueryOptions { 9 | /** 10 | * The SQL for the query 11 | */ 12 | sql: string; 13 | 14 | /** 15 | * The values for the query 16 | */ 17 | values?: any | any[] | { [param: string]: any }; 18 | 19 | /** 20 | * Every operation takes an optional inactivity timeout option. This allows you to specify appropriate timeouts for 21 | * operations. It is important to note that these timeouts are not part of the MySQL protocol, and rather timeout 22 | * operations through the client. This means that when a timeout is reached, the connection it occurred on will be 23 | * destroyed and no further operations can be performed. 24 | */ 25 | timeout?: number; 26 | 27 | /** 28 | * Either a boolean or string. If true, tables will be nested objects. If string (e.g. '_'), tables will be 29 | * nested as tableName_fieldName 30 | */ 31 | nestTables?: any; 32 | 33 | /** 34 | * Determines if column values should be converted to native JavaScript types. It is not recommended (and may go away / change in the future) 35 | * to disable type casting, but you can currently do so on either the connection or query level. (Default: true) 36 | * 37 | * You can also specify a function (field: any, next: () => void) => {} to do the type casting yourself. 38 | * 39 | * WARNING: YOU MUST INVOKE the parser using one of these three field functions in your custom typeCast callback. They can only be called once. 40 | * 41 | * field.string() 42 | * field.buffer() 43 | * field.geometry() 44 | * 45 | * are aliases for 46 | * 47 | * parser.parseLengthCodedString() 48 | * parser.parseLengthCodedBuffer() 49 | * parser.parseGeometryValue() 50 | * 51 | * You can find which field function you need to use by looking at: RowDataPacket.prototype._typeCast 52 | */ 53 | typeCast?: any; 54 | } 55 | 56 | export interface StreamOptions { 57 | /** 58 | * Sets the max buffer size in objects of a stream 59 | */ 60 | highWaterMark?: number; 61 | 62 | /** 63 | * The object mode of the stream (Default: true) 64 | */ 65 | objectMode?: any; 66 | } 67 | 68 | export interface QueryError extends NodeJS.ErrnoException { 69 | /** 70 | * Either a MySQL server error (e.g. 'ER_ACCESS_DENIED_ERROR'), 71 | * a node.js error (e.g. 'ECONNREFUSED') or an internal error 72 | * (e.g. 'PROTOCOL_CONNECTION_LOST'). 73 | */ 74 | code: string; 75 | 76 | /** 77 | * The sql state marker 78 | */ 79 | sqlStateMarker?: string; 80 | 81 | /** 82 | * The sql state 83 | */ 84 | sqlState?: string; 85 | 86 | /** 87 | * The field count 88 | */ 89 | fieldCount?: number; 90 | 91 | /** 92 | * Boolean, indicating if this error is terminal to the connection object. 93 | */ 94 | fatal: boolean; 95 | } 96 | } 97 | 98 | declare class Query extends Sequence { 99 | 100 | /** 101 | * The SQL for a constructed query 102 | */ 103 | sql: string; 104 | 105 | /** 106 | * Emits a query packet to start the query 107 | */ 108 | start(): void; 109 | 110 | /** 111 | * Determines the packet class to use given the first byte of the packet. 112 | * 113 | * @param firstByte The first byte of the packet 114 | * @param parser The packet parser 115 | */ 116 | determinePacket(firstByte: number, parser: any): any; 117 | 118 | /** 119 | * Creates a Readable stream with the given options 120 | * 121 | * @param options The options for the stream. 122 | */ 123 | stream(options: Query.StreamOptions): Readable; 124 | 125 | on(event: string, listener: Function): this; 126 | on(event: 'error', listener: (err: Query.QueryError) => any): this; 127 | on(event: 'fields', listener: (fields: FieldPacket, index: number) => any): this; 128 | on(event: 'result', listener: (result: RowDataPacket | OkPacket, index: number) => any): this; 129 | on(event: 'end', listener: () => any): this; 130 | } 131 | 132 | export = Query; 133 | -------------------------------------------------------------------------------- /lib/protocol/sequences/Sequence.d.ts: -------------------------------------------------------------------------------- 1 | 2 | import {EventEmitter} from 'events'; 3 | 4 | declare class Sequence extends EventEmitter { } 5 | export = Sequence; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@types/mysql", 3 | "version": "2.0.0", 4 | "description": "Typings for mysql", 5 | "scripts": { 6 | "build": "typings bundle -o test/bundle.d.ts", 7 | "test": "tsc -p test", 8 | "lint": "tslint -c tslint.json \"lib/**/*.d.ts\" index.d.ts", 9 | "typedoc": "typedoc --includeDeclarations --excludeExternals --name mysql --mode file --readme none --out typedoc lib index.d.ts typings/index.d.ts" 10 | }, 11 | "author": "Felix Becker ", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "mysql": "~2.17.1", 15 | "tslint": "^5.2.0", 16 | "typedoc": "^0.7.0", 17 | "typescript": "^2.0.3", 18 | "typings": "^2.1.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/test.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as fs from 'fs'; 3 | import * as mysql from 'mysql'; 4 | import * as stream from 'stream'; 5 | 6 | // Connections 7 | let connection = mysql.createConnection({ 8 | host: 'localhost', 9 | user: 'me', 10 | password: 'secret' 11 | }); 12 | 13 | connection.connect(); 14 | 15 | connection.query('SELECT 1 + 1 AS solution', function (err: mysql.QueryError, rows: mysql.RowDataPacket[], fields: mysql.FieldPacket) { 16 | if (err) { 17 | throw err; 18 | } 19 | 20 | console.log('The solution is: ', rows[0]['solution']); 21 | }); 22 | 23 | // multipleStatements 24 | 25 | connection.query('SELECT 1 AS x; SELECT 1 AS x; SELECT 1 AS x', function (err: mysql.QueryError, rows: mysql.RowDataPacket[][], fields: mysql.FieldPacket) { 26 | if (err) { 27 | throw err; 28 | } 29 | 30 | console.log(rows[0][0]['x']); 31 | console.log(rows[1][0]['x']); 32 | console.log(rows[2][0]['x']); 33 | }); 34 | 35 | connection.end(); 36 | 37 | connection = mysql.createConnection({ 38 | host: 'example.org', 39 | user: 'bob', 40 | password: 'secret' 41 | }); 42 | 43 | connection.connect(function (err) { 44 | if (err) { 45 | console.error('error connecting: ' + err.stack); 46 | return; 47 | } 48 | 49 | console.log('connected as id ' + connection.threadId); 50 | }); 51 | 52 | connection.query('SELECT 1', function (err, rows) { 53 | // connected! (unless `err` is set) 54 | }); 55 | 56 | connection = mysql.createConnection({ 57 | host: 'localhost', 58 | ssl: { 59 | ca: '' 60 | } 61 | }); 62 | 63 | connection = mysql.createConnection({ 64 | host: 'localhost', 65 | ssl: { 66 | // DO NOT DO THIS 67 | // set up your ca correctly to trust the connection 68 | rejectUnauthorized: false 69 | } 70 | }); 71 | 72 | connection.end(function (err) { 73 | // The connection is terminated now 74 | }); 75 | 76 | connection.destroy(); 77 | 78 | connection.changeUser({ user: 'john' }, function (err) { 79 | if (err) { 80 | throw err; 81 | } 82 | }); 83 | 84 | let userId = 'some user provided value'; 85 | let sql = 'SELECT * FROM users WHERE id = ' + connection.escape(userId); 86 | connection.query(sql, function (err, results) { 87 | // ... 88 | }); 89 | connection.query('SELECT * FROM users WHERE id = ?', [userId], function (err, results) { 90 | // ... 91 | }); 92 | 93 | let post = { id: 1, title: 'Hello MySQL' }; 94 | let query = connection.query('INSERT INTO posts SET ?', post, function (err, result) { 95 | // Neat! 96 | }); 97 | console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL' 98 | 99 | let queryStr = 'SELECT * FROM posts WHERE title=' + mysql.escape('Hello MySQL'); 100 | 101 | console.log(queryStr); // SELECT * FROM posts WHERE title='Hello MySQL' 102 | 103 | let sorter = 'date'; 104 | sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter); 105 | connection.query(sql, function (err, results) { 106 | // ... 107 | }); 108 | 109 | sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId('posts.' + sorter); 110 | connection.query(sql, function (err, results) { 111 | // ... 112 | }); 113 | 114 | let userIdNum = 1; 115 | let columns = ['username', 'email']; 116 | query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userIdNum], function (err, results) { 117 | // ... 118 | }); 119 | 120 | console.log(query.sql); // SELECT `username`, `email` FROM `users` WHERE id = 1 121 | 122 | sql = 'SELECT * FROM ?? WHERE ?? = ?'; 123 | let inserts = ['users', 'id', userId]; 124 | sql = mysql.format(sql, inserts); 125 | 126 | sql = 'INSERT INTO posts SET ?'; 127 | post = { id: 1, title: 'Hello MySQL' }; 128 | sql = mysql.format(sql, post); 129 | 130 | connection.config.queryFormat = function (query, values) { 131 | if (!values) { 132 | return query; 133 | } 134 | return query.replace(/\:(\w+)/g, function (txt: string, key: string) { 135 | if (values.hasOwnProperty(key)) { 136 | return this.escape(values[key]); 137 | } 138 | return txt; 139 | }.bind(this)); 140 | }; 141 | 142 | connection.query('UPDATE posts SET title = :title', { title: 'Hello MySQL' }); 143 | 144 | let s: stream.Readable = connection.query('UPDATE posts SET title = :title', { title: 'Hello MySQL' }).stream({ highWaterMark: 5 }); 145 | 146 | connection.query('INSERT INTO posts SET ?', { title: 'test' }, function (err: mysql.QueryError, result: mysql.OkPacket) { 147 | console.log(result.insertId); 148 | }); 149 | 150 | connection.query('DELETE FROM posts WHERE title = "wrong"', function (err: mysql.QueryError, result: mysql.OkPacket) { 151 | console.log('deleted ' + result.affectedRows + ' rows'); 152 | }); 153 | 154 | connection.query('UPDATE posts SET ...', function (err: mysql.QueryError, result: mysql.OkPacket) { 155 | console.log('changed ' + result.changedRows + ' rows'); 156 | }); 157 | 158 | connection.connect(function (err) { 159 | console.log('connected as id ' + connection.threadId); 160 | }); 161 | 162 | /// Pools 163 | 164 | let poolConfig = { 165 | connectionLimit: 10, 166 | host: 'example.org', 167 | user: 'bob', 168 | password: 'secret' 169 | }; 170 | 171 | let pool = mysql.createPool(poolConfig); 172 | 173 | pool.query('SELECT 1 + 1 AS solution', function (err: mysql.QueryError, rows: mysql.RowDataPacket[], fields: mysql.FieldPacket) { 174 | if (err) { 175 | throw err; 176 | } 177 | 178 | console.log('The solution is: ', rows[0]['solution']); 179 | }); 180 | 181 | pool = mysql.createPool({ 182 | host: 'example.org', 183 | user: 'bob', 184 | password: 'secret' 185 | }); 186 | 187 | pool.getConnection(function (err, connection) { 188 | // connected! (unless `err` is set) 189 | }); 190 | 191 | pool.on('connection', function (connection) { 192 | connection.query('SET SESSION auto_increment_increment=1'); 193 | }); 194 | 195 | pool.getConnection(function (err, connection) { 196 | // Use the connection 197 | connection.query('SELECT something FROM sometable', function (err, rows) { 198 | // And done with the connection. 199 | connection.release(); 200 | 201 | // Don't use the connection here, it has been returned to the pool. 202 | }); 203 | }); 204 | 205 | /// PoolClusters 206 | 207 | // create 208 | let poolCluster = mysql.createPoolCluster(); 209 | 210 | let poolClusterConfig = { 211 | canRetry: true, 212 | removeNodeErrorCount: 2, 213 | restoreNodeTimeout: 3, 214 | defaultSelector: 'RANDOM' 215 | }; 216 | 217 | poolCluster.add(poolClusterConfig); // anonymous group 218 | poolCluster.add('MASTER', poolClusterConfig); 219 | poolCluster.add('SLAVE1', poolClusterConfig); 220 | poolCluster.add('SLAVE2', poolClusterConfig); 221 | 222 | // Target Group : ALL(anonymous, MASTER, SLAVE1-2), Selector : round-robin(default) 223 | poolCluster.getConnection(function (err, connection) { }); 224 | 225 | // Target Group : MASTER, Selector : round-robin 226 | poolCluster.getConnection('MASTER', function (err, connection) { }); 227 | 228 | // Target Group : SLAVE1-2, Selector : order 229 | // If can't connect to SLAVE1, return SLAVE2. (remove SLAVE1 in the cluster) 230 | poolCluster.on('remove', function (nodeId) { 231 | console.log('REMOVED NODE : ' + nodeId); // nodeId = SLAVE1 232 | }); 233 | 234 | poolCluster.getConnection('SLAVE*', 'ORDER', function (err, connection) { }); 235 | 236 | // of namespace : of(pattern, selector) 237 | poolCluster.of('*').getConnection(function (err, connection) { }); 238 | 239 | const cluster = poolCluster.of('SLAVE*', 'RANDOM'); 240 | pool.getConnection(function (err, connection) { }); 241 | pool.getConnection(function (err, connection) { }); 242 | 243 | let poolClusterWithOptions = mysql.createPoolCluster({ 244 | canRetry: true, 245 | removeNodeErrorCount: 3, 246 | restoreNodeTimeout: 1000, 247 | defaultSelector: 'RR' 248 | }); 249 | 250 | // destroy 251 | poolCluster.end(); 252 | 253 | // Queries 254 | 255 | query = connection.query('SELECT * FROM posts'); 256 | query 257 | .on('error', function (err: NodeJS.ErrnoException) { 258 | // Handle error, an 'end' event will be emitted after this as well 259 | }) 260 | .on('fields', function (fields: any) { 261 | // the field packets for the rows to follow 262 | }) 263 | .on('result', function (row: any) { 264 | // Pausing the connnection is useful if your processing involves I/O 265 | connection.pause(); 266 | 267 | let processRow = (row: any, cb: () => void) => { 268 | cb(); 269 | }; 270 | 271 | processRow(row, function () { 272 | connection.resume(); 273 | }); 274 | }) 275 | .on('end', function () { 276 | // all rows have been received 277 | }); 278 | 279 | let writable = fs.createWriteStream('file.txt'); 280 | connection.query('SELECT * FROM posts') 281 | .stream({ highWaterMark: 5 }) 282 | .pipe(writable); 283 | 284 | connection = mysql.createConnection({ multipleStatements: true }); 285 | 286 | connection.query('SELECT 1; SELECT 2', function (err: mysql.QueryError, results: mysql.RowDataPacket) { 287 | // `results` is an array with one element for every statement in the query: 288 | console.log(results[0]); // [{1: 1}] 289 | console.log(results[1]); // [{2: 2}] 290 | }); 291 | 292 | query = connection.query('SELECT 1; SELECT 2'); 293 | 294 | query 295 | .on('fields', function (fields, index) { 296 | // the fields for the result rows that follow 297 | }) 298 | .on('result', function (row, index) { 299 | // index refers to the statement this result belongs to (starts at 0) 300 | }); 301 | 302 | let options = { sql: '...', nestTables: true }; 303 | 304 | connection.query(options, function (err, results) { 305 | /* results will be an array like this now: 306 | [{ 307 | table1: { 308 | fieldA: '...', 309 | fieldB: '...', 310 | }, 311 | table2: { 312 | fieldA: '...', 313 | fieldB: '...', 314 | }, 315 | }, ...] 316 | */ 317 | }); 318 | 319 | connection.beginTransaction(function (err) { 320 | let title = 'title'; 321 | 322 | if (err) { throw err; } 323 | connection.query('INSERT INTO posts SET title=?', title, function (err: mysql.QueryError, result: mysql.OkPacket) { 324 | if (err) { 325 | connection.rollback(function () { 326 | throw err; 327 | }); 328 | } 329 | 330 | let log = 'Post ' + result.insertId + ' added'; 331 | 332 | connection.query('INSERT INTO log SET data=?', log, function (err, result) { 333 | if (err) { 334 | connection.rollback(function () { 335 | throw err; 336 | }); 337 | } 338 | connection.commit(function (err) { 339 | if (err) { 340 | connection.rollback(function () { 341 | throw err; 342 | }); 343 | } 344 | console.log('success!'); 345 | }); 346 | }); 347 | }); 348 | }); 349 | 350 | // Kill query after 60s 351 | connection.query({ sql: 'SELECT COUNT(*) AS count FROM big_table', timeout: 60000 }, function (err: mysql.QueryError, rows: mysql.RowDataPacket[]) { 352 | if (err && err.code === 'PROTOCOL_SEQUENCE_TIMEOUT') { 353 | throw new Error('too long to count table rows!'); 354 | } 355 | 356 | if (err) { 357 | throw err; 358 | } 359 | 360 | console.log(rows[0]['count'] + ' rows'); 361 | }); 362 | 363 | connection = mysql.createConnection({ 364 | port: 84943 // WRONG PORT 365 | }); 366 | 367 | connection.connect(function (err) { 368 | if (err) { 369 | console.log(err.code); // 'ECONNREFUSED' 370 | console.log(err.fatal); // true 371 | } 372 | }); 373 | 374 | connection.query('SELECT 1', function (err) { 375 | if (err) { 376 | console.log(err.code); // 'ECONNREFUSED' 377 | console.log(err.fatal); // true 378 | } 379 | }); 380 | 381 | connection.query('USE name_of_db_that_does_not_exist', function (err, rows) { 382 | if (err) { 383 | console.log(err.code); // 'ER_BAD_DB_ERROR' 384 | } 385 | }); 386 | 387 | connection.query('SELECT 1', function (err: mysql.QueryError | null, rows: mysql.RowDataPacket[]) { 388 | console.log(err); // null 389 | console.log(rows.length); // 1 390 | }); 391 | 392 | connection.on('error', function (err: NodeJS.ErrnoException | null) { 393 | if (err) { 394 | console.log(err.code); // 'ER_BAD_DB_ERROR' 395 | } 396 | }); 397 | 398 | connection.query('USE name_of_db_that_does_not_exist'); 399 | 400 | // I am Chuck Norris: 401 | connection.on('error', function () { 402 | // ignore 403 | }); 404 | 405 | connection = mysql.createConnection({ typeCast: false }); 406 | 407 | query = connection.query({ sql: '...', typeCast: false }, function (err, results) { 408 | // 409 | }); 410 | 411 | connection.query({ 412 | sql: '...', 413 | typeCast: function (field: any, next: Function) { 414 | if (field.type === 'TINY' && field.length === 1) { 415 | return (field.string() === '1'); // 1 = true, 0 = false 416 | } 417 | return next(); 418 | } 419 | }); 420 | 421 | connection = mysql.createConnection('mysql://localhost/test?flags=-FOUND_ROWS'); 422 | connection = mysql.createConnection({ debug: true }); 423 | connection = mysql.createConnection({ debug: ['ComQueryPacket', 'RowDataPacket'] }); 424 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "noImplicitAny": true, 5 | "strictNullChecks": true, 6 | "module": "commonjs", 7 | "typeRoots": [ 8 | "../typings/globals", 9 | "../typings/modules" 10 | ] 11 | }, 12 | "files": [ 13 | "test.ts", 14 | "bundle.d.ts", 15 | "../typings/index.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": true, 4 | "strictNullChecks": true, 5 | "target": "es2015", 6 | "module": "commonjs", 7 | "typeRoots": [ 8 | "typings/globals", 9 | "typings/modules" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [true, "check-space"], 5 | "indent": [true, "spaces"], 6 | "no-duplicate-variable": true, 7 | "no-eval": true, 8 | "no-internal-module": true, 9 | "no-trailing-whitespace": true, 10 | "no-var-keyword": true, 11 | "one-line": [true, "check-catch", "check-finally", "check-else", "check-open-brace", "check-whitespace"], 12 | "quotemark": [true, "single"], 13 | "semicolon": [true, "always"], 14 | "triple-equals": [true, "allow-null-check"], 15 | "typedef-whitespace": [ 16 | true, 17 | { 18 | "call-signature": "nospace", 19 | "index-signature": "nospace", 20 | "parameter": "nospace", 21 | "property-declaration": "nospace", 22 | "variable-declaration": "nospace" 23 | }, 24 | { 25 | "call-signature": "onespace", 26 | "index-signature": "onespace", 27 | "parameter": "onespace", 28 | "property-declaration": "onespace", 29 | "variable-declaration": "onespace" 30 | } 31 | ], 32 | "variable-name": [true, "ban-keywords"], 33 | "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"], 34 | "jsdoc-format": true, 35 | "no-consecutive-blank-lines": true, 36 | "one-variable-per-declaration": [true, "ignore-for-loop"], 37 | "curly": true, 38 | "no-empty": false, 39 | "no-duplicate-key": true, 40 | "no-unreachable": true, 41 | "no-unused-expression": true, 42 | "no-unused-variable": [false], 43 | "eofline": true, 44 | "trailing-comma": [true, {"singleline": "never", "multiline": "never"}], 45 | "align": [true, "parameters", "statements"] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mysql", 3 | "version": "2.11.1", 4 | "homepage": "https://github.com/types/mysql", 5 | "main": "index.d.ts", 6 | "globalDependencies": { 7 | "node": "registry:env/node#6.0.0+20170213133316" 8 | } 9 | } 10 | --------------------------------------------------------------------------------