diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 71c7472a4..3ea68d240 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -20,6 +20,7 @@ All definitions files include a header with the author and editors, so at some p
* [Angular Translate](http://pascalprecht.github.io/angular-translate/) (by [Michel Salib](https://github.com/michelsalib))
* [Angular UI Bootstrap](http://angular-ui.github.io/bootstrap) (by [Brian Surowiec](https://github.com/xt0rted))
* [any-db](https://github.com/grncdr/node-any-db) (by [Rogier Schouten](https://github.com/rogier-schouten))
+* [any-db-transaction](https://github.com/grncdr/node-any-db-transaction) (by [Rogier Schouten](https://github.com/rogier-schouten))
* [AppFramework](http://app-framework-software.intel.com/) (by [Kyo Ago](https://github.com/kyo-ago))
* [Arbiter](http://arbiterjs.com/) (by [Arash Shakery](https://github.com/arash16))
* [asciify](https://github.com/olizilla/asciify) (by [Alan](http://alan.norbauer.com))
diff --git a/any-db-transaction/any-db-transaction-tests.ts b/any-db-transaction/any-db-transaction-tests.ts
new file mode 100644
index 000000000..55ca53bdc
--- /dev/null
+++ b/any-db-transaction/any-db-transaction-tests.ts
@@ -0,0 +1,29 @@
+
+///
+///
+
+"use strict";
+
+import anyDB = require("any-db");
+import begin = require("any-db-transaction");
+
+var conn: anyDB.Connection = anyDB.createConnection("mysql://user:password@localhost/testdb");
+
+
+var transaction = begin(conn);
+var transaction2 = begin(transaction);
+
+begin(conn, { autoRollback: true });
+begin(conn, (error: Error, result: begin.Transaction): void => {
+});
+
+transaction.query("SELECT * FROM MyTable");
+
+transaction.commit();
+transaction.commit((error: Error): void => {
+});
+
+transaction.rollback();
+transaction.rollback((error: Error): void => {
+});
+
diff --git a/any-db-transaction/any-db-transaction.d.ts b/any-db-transaction/any-db-transaction.d.ts
new file mode 100644
index 000000000..7f65e959d
--- /dev/null
+++ b/any-db-transaction/any-db-transaction.d.ts
@@ -0,0 +1,93 @@
+// Type definitions for any-db-transaction 2.2.1
+// Project: https://github.com/grncdr/node-any-db-transaction
+// Definitions by: Rogier Schouten
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+declare module "any-db-transaction" {
+ import anyDB = require("any-db");
+
+ module begin {
+ /**
+ * Transaction objects are are simple wrappers around a Connection that also implement the Queryable API,
+ * but guarantee that all queries take place within a single database transaction or not at all. Note that
+ * begin also understands how to acquire (and release) a connection from a ConnectionPool as well, so you
+ * can simply pass a pool to it: var tx = begin(pool)
+ *
+ * By default, any queries that error during a transaction will cause an automatic rollback. If a query has
+ * no callback, the transaction will also handle (and re-emit) 'error' events for the Query instance.
+ * This enables handling errors for an entire transaction in a single place.
+ *
+ * Transactions may also be nested by passing a Transaction to begin and these nested transactions can
+ * safely error and rollback without rolling back their parent transaction
+ *
+ * Transaction events:
+ * 'query', query - emitted immediately after .query is called on a connection via tx.query. The argument is a query object.
+ * 'commit:start' - Emitted when .commit() is called.
+ * 'commit:complete' - Emitted after the transaction has committed.
+ * 'rollback:start' - Emitted when .rollback() is called.
+ * 'rollback:complete' - Emitted after the transaction has rolled back.
+ * 'close' - Emitted after rollback or commit completes.
+ * 'error', err - Emitted under three conditions:
+ * There was an error acquiring a connection.
+ * Any query performed in this transaction emits an error that would otherwise go unhandled.
+ * Any of query, begin, commit, or rollback are called after the connection has already been committed or rolled back.
+ * Note that the 'error' event may be emitted multiple times! depending on the callback you are registering, you way want to wrap it using [once][].
+ */
+ interface Transaction extends anyDB.Queryable {
+
+ /**
+ * Issue a COMMIT (or RELEASE ... in the case of nested transactions) statement to the database.
+ * If a continuation is provided it will be called (possibly with an error) after the COMMIT
+ * statement completes. The transaction object itself will be unusable after calling commit().
+ */
+ commit(callback?: (error: Error) => void): void;
+
+ /**
+ * The same as Transaction.commit but issues a ROLLBACK. Again, the transaction will be unusable after calling this method.
+ */
+ rollback(callback?: (error: Error) => void): void;
+ }
+
+ interface TransactionOptions {
+ /**
+ * Adapter name e.g. 'mysql'
+ */
+ adapter?: anyDB.Adapter;
+ /**
+ * SQL statement for beginning a transaction, default 'BEGIN'
+ */
+ begin?: string;
+ /**
+ * SQL statement for committing a transaction, default 'COMMIT'
+ */
+ commit?: string;
+ /**
+ * SQL statement for rolling back a transaction, default 'ROLLBACK'
+ */
+ rollback?: string;
+ /**
+ * Callback for transaction
+ */
+ callback?: (error: Error, transaction: Transaction) => void;
+ /**
+ * Rollback automatically on error, default true
+ */
+ autoRollback?: boolean;
+ }
+ }
+
+ /**
+ * Start a transaction
+ */
+ function begin(q: anyDB.Queryable, options?: begin.TransactionOptions, callback?: (error: Error, transaction: begin.Transaction) => void): begin.Transaction;
+ function begin(q: anyDB.Queryable, callback?: (error: Error, transaction: begin.Transaction) => void): begin.Transaction;
+ function begin(q: anyDB.Queryable, beginStatement?: string, callback?: (error: Error, transaction: begin.Transaction) => void): begin.Transaction;
+ function begin(q: anyDB.Queryable, options?: begin.TransactionOptions, beginStatement?: string, callback?: (error: Error, transaction: begin.Transaction) => void): begin.Transaction;
+
+ export = begin;
+}
+
+
+
diff --git a/any-db/any-db-tests.ts b/any-db/any-db-tests.ts
index 06a0dd2b0..15dc6c7e6 100644
--- a/any-db/any-db-tests.ts
+++ b/any-db/any-db-tests.ts
@@ -7,7 +7,32 @@ import anyDB = require("any-db");
var conn: anyDB.Connection = anyDB.createConnection("mysql://user:password@localhost/testdb");
var sql: string = "SELECT * FROM questions";
+
+conn.query(sql, [1, "boo"]);
+
conn.query(sql).on("data", (row: Object[]): void => {
// nothing
});
+
+conn.query(sql, [1, "s"], (error: Error, result: anyDB.ResultSet): void => {
+ result.rows.length;
+ result.fields.length;
+});
+
conn.end();
+
+
+var poolConfig: anyDB.PoolConfig = {
+ min: 1,
+ max: 200
+};
+
+var pool: anyDB.ConnectionPool = anyDB.createPool("mysql://user:password@localhost/testdb", poolConfig);
+
+pool.query(sql).on("data", (row: Object[]): void => {
+// nothing
+});
+
+pool.close((error: Error): void => {
+});
+
diff --git a/any-db/any-db.d.ts b/any-db/any-db.d.ts
index fbdd4537e..04817623a 100644
--- a/any-db/any-db.d.ts
+++ b/any-db/any-db.d.ts
@@ -7,12 +7,12 @@
declare module "any-db" {
import events = require("events");
- import stream = require("stream");
+ import stream = require("stream");
export interface ConnectOpts {
adapter: string;
}
-
+
export interface Adapter {
name: string;
/**
@@ -20,10 +20,10 @@ declare module "any-db" {
* If a continuation is given, it must be called, either with an error or the established connection.
*/
createConnection(opts: ConnectOpts, callback?: (error: Error, result: Connection) => void): Connection;
-
+
/**
- * Create a Query that may eventually be executed later on by a Connection. While this function is rarely needed by user code,
- * it makes it possible for ConnectionPool.query and Transaction.query to fulfill the Queryable.query contract
+ * Create a Query that may eventually be executed later on by a Connection. While this function is rarely needed by user code,
+ * it makes it possible for ConnectionPool.query and Transaction.query to fulfill the Queryable.query contract
* by synchronously returning a Query stream
*/
createQuery(text: string, params?: any[], callback?: (error: Error, result: ResultSet) => void): Query;
@@ -33,36 +33,62 @@ declare module "any-db" {
* Other properties are driver specific
*/
export interface Field {
- name: string;
+ name: string;
}
/**
* ResultSet objects are just plain data that collect results of a query when a continuation
- * is provided to Queryable.query. The lastInsertId is optional, and currently supported by
+ * is provided to Queryable.query. The lastInsertId is optional, and currently supported by
* sqlite3 and mysql but not postgres, because it is not supported by Postgres itself.
*/
export interface ResultSet {
- fields: Field[];
- rows: Object[];
+ /**
+ * Affected rows. Note e.g. for INSERT queries the rows property is not filled even
+ * though rowCount is non-zero.
+ */
rowCount: number;
+ /**
+ * Result rows
+ */
+ rows: Object[];
+ /**
+ * Result field descriptions
+ */
+ fields: Field[];
+
+ /**
+ * Not supported by all drivers.
+ */
+ fieldCount?: number;
+ /**
+ * Not supported by all drivers.
+ */
lastInsertId?: any;
+ /**
+ * Not supported by all drivers.
+ */
+ affectedRows?: number;
+ /**
+ * Not supported by all drivers.
+ */
+ changedRows?: number;
}
/**
- * Query objects are returned by the Queryable.query method, available on connections,
- * pools, and transactions. Queries are instances of Readable, and as such can be piped
- * through transforms and support backpressure for more efficient memory-usage on very
+ * Query objects are returned by the Queryable.query method, available on connections,
+ * pools, and transactions. Queries are instances of Readable, and as such can be piped
+ * through transforms and support backpressure for more efficient memory-usage on very
* large results sets. (Note: at this time the sqlite3 driver does not support backpressure)
*
- * Internally, Query instances are created by a database Adapter and may have more methods,
- * properties, and events than are described here. Consult the documentation for your
+ * Internally, Query instances are created by a database Adapter and may have more methods,
+ * properties, and events than are described here. Consult the documentation for your
* specific adapter to find out about any extensions.
*
* Events:
*
* Error event
- * The 'error' event is emitted at most once per query. Note that this event will be
- * emitted for errors even if a callback was provided, the callback will
+ * The 'error' event is emitted at most once per query. Note that this event will be
+ * emitted for errors even if a callback was provided, the callback will
* simply be subscribed to the 'error' event.
* One argument is passed to event listeners:
* error - the error object.
@@ -89,25 +115,25 @@ declare module "any-db" {
*/
export interface Query extends stream.Readable {
/**
- * The SQL query as a string. If you are using MySQL this will contain
+ * The SQL query as a string. If you are using MySQL this will contain
* interpolated values after the query has been enqueued by a connection.
*/
text: string;
-
+
/**
* The array of parameter values.
*/
values: any[];
-
+
/**
- * The callback (if any) that was provided to Queryable.query. Note that
- * Query objects must not use a closed over reference to their callback,
- * as other any-db libraries may rely on modifying the callback property
+ * The callback (if any) that was provided to Queryable.query. Note that
+ * Query objects must not use a closed over reference to their callback,
+ * as other any-db libraries may rely on modifying the callback property
* of a Query they did not create.
*/
callback: (error: Error, results: ResultSet) => void;
}
-
+
/**
* Events:
* The 'query' event is emitted immediately before a query is executed. One argument is passed to event handlers:
@@ -118,30 +144,30 @@ declare module "any-db" {
* The Adapter instance that will be used by this Queryable for creating Query instances and/or connections.
*/
adapter: Adapter;
-
+
/**
- * Execute a SQL statement using bound parameters (if they are provided) and return a Query object
- * that is a Readable stream of the resulting rows. If a Continuation is provided the rows
- * returned by the database will be aggregated into a [ResultSet][] which will be passed to the
+ * Execute a SQL statement using bound parameters (if they are provided) and return a Query object
+ * that is a Readable stream of the resulting rows. If a Continuation is provided the rows
+ * returned by the database will be aggregated into a [ResultSet][] which will be passed to the
* continuation after the query has completed.
- * The second form is not needed for normal use, but must be implemented by adapters to work correctly
- * with ConnectionPool and Transaction. See Adapter.createQuery for more details.
+ * The second form is not needed for normal use, but must be implemented by adapters to work correctly
+ * with ConnectionPool and Transaction. See Adapter.createQuery for more details.
*/
query(text: string, params?: any[], callback?: (error: Error, results: ResultSet) => void): Query
-
+
/**
- * The second form is not needed for normal use, but must be implemented by adapters to work correctly
- * with ConnectionPool and Transaction. See Adapter.createQuery for more details.
+ * The second form is not needed for normal use, but must be implemented by adapters to work correctly
+ * with ConnectionPool and Transaction. See Adapter.createQuery for more details.
*/
- query(query: Query): Query;
+ // query(query: Query): Query;
}
-
+
/**
- * Connection objects are obtained using createConnection from Any-DB or ConnectionPool.acquire,
+ * Connection objects are obtained using createConnection from Any-DB or ConnectionPool.acquire,
* both of which delegate to the createConnection implementation of the specified adapter.
- * While all Connection objects implement the Queryable interface, the implementations in
- * each adapter may add additional methods or emit additional events. If you need to access a
- * feature of your database that is not described here (such as Postgres' server-side prepared
+ * While all Connection objects implement the Queryable interface, the implementations in
+ * each adapter may add additional methods or emit additional events. If you need to access a
+ * feature of your database that is not described here (such as Postgres' server-side prepared
* statements), consult the documentation for your adapter.
*
* Events:
@@ -155,64 +181,59 @@ declare module "any-db" {
*
* Close event
* The 'close' event is emitted when the connection has been closed.
- * No arguments are passed to event listeners.
+ * No arguments are passed to event listeners.
*/
- export interface Connection extends Queryable {
+ export interface Connection extends Queryable {
/**
- * Close the database connection. If a continuation is provided it
+ * Close the database connection. If a continuation is provided it
* will be called after the connection has closed.
*/
end(callback?: (error: Error) => void): void;
}
-
+
export interface ConnectionStatic {
new(): Connection;
-
+
name: string;
createConnection(): void;
createPool(): void;
}
-
+
/**
* ConnectionPool events
* 'acquire' - emitted whenever pool.acquire is called
* 'release' - emitted whenever pool.release is called
* 'query', query - emitted immediately after .query is called on a
* connection via pool.query. The argument is a Query object.
- * 'close' - emitted when the connection pool has closed all of it
+ * 'close' - emitted when the connection pool has closed all of it
* connections after a call to close().
*/
- export interface ConnectionPool extends events.EventEmitter {
+ export interface ConnectionPool extends Queryable {
/**
- * The string name of the adapter used for this connection pool, e.g. 'sqlite3'.
- */
- adapter: string;
-
- /**
- * Implements Queryable.query by automatically acquiring a connection
+ * Implements Queryable.query by automatically acquiring a connection
* and releasing it when the query completes.
*/
- query(text: string, params?: any[], callback?: (error: Error, results: ResultSet) => void): Query;
-
+ query(text: string, params?: any[], callback?: (error: Error, results: ResultSet) => void): Query;
+
/**
* Remove a connection from the pool. If you use this method you must
* return the connection back to the pool using ConnectionPool.release
*/
acquire(callback: (error: Error, result: Connection) => void): void;
-
+
/**
- * Return a connection to the pool. This should only be called with connections
+ * Return a connection to the pool. This should only be called with connections
* you've manually acquired. You must not continue to use the connection after releasing it.
*/
release(connection: Connection): void;
-
+
/**
- * Stop giving out new connections, and close all existing database connections as they
+ * Stop giving out new connections, and close all existing database connections as they
* are returned to the pool.
*/
close(callback?: (error: Error) => void): void;
}
-
+
/**
* A PoolConfig is generally a plain object with any of the following properties (they are all optional):
*/
@@ -222,8 +243,8 @@ declare module "any-db" {
*/
min?: number;
/**
- * max (default 10) The maximum number of connections to keep open in the pool.
- * When this limit is reached further requests for connections will queue waiting
+ * max (default 10) The maximum number of connections to keep open in the pool.
+ * When this limit is reached further requests for connections will queue waiting
* for an existing connection to be released back into the pool.
*/
max?: number;
@@ -236,7 +257,7 @@ declare module "any-db" {
*/
reapInterval?: number;
/**
- * (default true) When this is true, the pool will reap connections that
+ * (default true) When this is true, the pool will reap connections that
* have been idle for more than idleTimeout milliseconds.
*/
refreshIdle?: boolean;
@@ -246,19 +267,19 @@ declare module "any-db" {
*/
onConnect?: (connection: Connection, ready: (error: Error, result: Connection) => void) => void;
/**
- * Called each time a connection is returned to the pool. Use this to restore a connection to
- * it's original state (e.g. rollback transactions, set the database session vars). If reset
+ * Called each time a connection is returned to the pool. Use this to restore a connection to
+ * it's original state (e.g. rollback transactions, set the database session vars). If reset
* fails to call the done continuation the connection will be lost in limbo.
*/
reset?: (connection: Connection, done: (error: Error) => void) => void;
/**
- * (default function (err) { return true }) - Called when an error is encountered
- * by pool.query or emitted by an idle connection. If shouldDestroyConnection(error)
+ * (default function (err) { return true }) - Called when an error is encountered
+ * by pool.query or emitted by an idle connection. If shouldDestroyConnection(error)
* is truthy the connection will be destroyed, otherwise it will be reset.
*/
shouldDestroyConnection?: (error: Error) => boolean;
}
-
+
/**
* Create a database connection.
* @param url String of the form adapter://user:password@host/database
@@ -266,7 +287,7 @@ declare module "any-db" {
* @returns Connection object.
*/
export function createConnection(url: string, callback?: (error: Error, connection: Connection) => void): Connection;
-
+
/**
* Create a database connection.
* @param opts Object with adapter name and any properties that the given adapter requires
@@ -274,8 +295,9 @@ declare module "any-db" {
* @returns Connection object.
*/
export function createConnection(opts: ConnectOpts, callback?: (error: Error, connection: Connection) => void): Connection;
-
-
+
+
export function createPool(url: string, config: PoolConfig): ConnectionPool;
-
+ export function createPool(opts: ConnectOpts, config: PoolConfig): ConnectionPool;
+
}