A Database object represents a virtual connection to a database. The Database class is meant to be subclassed by database adapters in order to provide the functionality needed for executing queries.
Static PropertiesProperty | Type | Default Value | Description |
AUTOINCREMENT | property | 'AUTOINCREMENT' | Default AUTO INCREMENT SQL |
CASCADE | property | 'CASCADE' | Default CASCACDE SQL |
COMMA_SEPARATOR | property | ' | Default comma |
DATABASES | patio.Database[] | DATABASES | A list of currently connected Databases. |
NOT_NULL | property | ' NOT NULL' | Default NOT NULL SQL |
NO_ACTION | property | 'NO ACTION' | Default NO ACTION SQL |
NULL | property | ' NULL' | Default NULL SQL |
PRIMARY_KEY | property | ' PRIMARY KEY' | Default PRIMARY KEY SQL |
RESTRICT | property | 'RESTRICT' | Default RESTRICT SQL |
SET_DEFAULT | property | 'SET DEFAULT' | Default SET DEFAULT SQL |
SET_NULL | property | 'SET NULL' | Default SET NULL SQL |
TEMPORARY | property | 'TEMPORARY ' | Default TEMPORARY SQL |
UNDERSCORE | property | '_' | Default UNDERSCORE SQL, used in index creation. |
UNIQUE | property | ' UNIQUE' | Default UNIQUE SQL |
UNSIGNED | property | ' UNSIGNED' | Default UNSIGNED SQL |
identifierInputMethod | String | function (){
return this.__identifierInputMethod;
} | The String or comb method to use transform identifiers with when they are sent to database. See patio#identifierInputMethod |
identifierOutputMethod | String | function (){
return this.__identifierOutputMethod;
} | The String or comb method to use transform identifiers with when they are retrieved from database. See patio#identifierOutputMethod |
logger | function | function (){
return LOGGER;
} | The "patio.Database" logger. |
quoteIdentifiers | Boolean | function (){
return this.__quoteIdentifiers;
} | Boolean of whether or not to quote identifiers before sending then to the database. See patio#quoteIdentifiers |
Property | Type | Default Value | Description |
SQL_BEGIN | property | 'BEGIN' | The BEGIN SQL fragment used to signify the start of a transaciton. |
SQL_COMMIT | property | 'COMMIT' | The COMMIT SQL fragment used to signify the end of a transaction and the final commit. |
SQL_RELEASE_SAVEPOINT | property | 'RELEASE SAVEPOINT autopoint_%d' | The RELEASE SAVEPOINT SQL fragment used by trasactions when using save points. The adapter should override this SQL fragment if the adapters SQL is different. This fragment will not be used if patio.Database#supportsSavepoints is false. |
SQL_ROLLBACK | property | 'ROLLBACK' | The ROLLBACK SQL fragment used to rollback a database transaction. This should be overrode by adapters if the SQL for the adapters database is different. |
SQL_ROLLBACK_TO_SAVEPOINT | property | 'ROLLBACK TO SAVEPOINT autopoint_%d' | The ROLLBACK TO SAVEPOINT SQL fragment used to rollback a database transaction to a particular save point. This should be overrode by adapters if the SQL for the adapters database is different. This fragment will not be used if patio.Database#supportsSavepoints is false. |
SQL_SAVEPOINT | property | 'SAVEPOINT autopoint_%d' | The SAVEPOINT SQL fragment used for creating a save point in a database transaction. This fragment will not be used if patio.Database#supportsSavepoints is false. |
TRANSACTION_ISOLATION_LEVELS | property | {
uncommitted: 'READ UNCOMMITTED',
committed: 'READ COMMITTED',
repeatable: 'REPEATABLE READ',
serializable: 'SERIALIZABLE'
} | Object containing different database transaction isolation levels. This object is used to look up the proper SQL when starting a new transaction and setting the isolation level in the options. |
__schemaUtiltyDataset | function | function (){
this.__schemaUtiltyDs = this.__schemaUtiltyDs || this.dataset;
return this.__schemaUtiltyDs;
} | |
autoIncrementSql | function | function (){
return this._static.AUTOINCREMENT;
} | |
beginTransactionSql | String | function (){
return this.SQL_BEGIN;
} | SQL to BEGIN a transaction. See patio.Database#SQL_BEGIN for default, |
commitTransactionSql | String | function (){
return this.SQL_COMMIT;
} | SQL to COMMIT a transaction. See patio.Database#SQL_COMMIT for default, |
connectionExecuteMethod | property | "execute" | The method name to invoke on a connection. The method name should be overrode by an adapter if the method to execute a query is different for the adapter specific connection class. |
connectionPoolDefaultOptions | Object | function (){
return {};
} | The default options for the connection pool. |
dataset | patio.Dataset | returns an empty adapter specific patio.Dataset that can be used to query the patio.Database with. | |
defaultPrimaryKeyType | String |
"integer"
| Default type for primary/foreign keys when a type is not specified. |
defaultPrimaryKeyTypeDefault | String |
"integer"
| Default type for primary/foreign keys when a type is not specified. |
defaultSchemaDefault | {String|patio.sql.Identifier} | function (){
return null;
} | Default schema to use. This is generally null but may be overridden by an adapter. |
identifierInputMethod | String | function (){
return this.__identifierInputMethod;
} | The String or comb method to use transform identifiers with when sending identifiers to the database. If this property is undefined then patio.Database#identifierInputMethodDefault will be used. |
identifierInputMethodDefault | String |
toUpperCase
| The default String or comb method to use transform identifiers with when sending identifiers to the database. |
identifierOutputMethod | String | function (){
return this.__identifierOutputMethod;
} | The String or comb method to use transform identifiers with when they are retrieved from database. If this property is undefined then patio.Database#identifierOutputMethodDefault will be used. |
identifierOutputMethodDefault | String |
toLowerCase
| The default String or comb method to use transform identifiers with when they are retrieved from the database. |
inputIdentifierFunc | Function | function (){
var ds = this.dataset;
return function (ident) {
return ds.inputIdentifier(ident);
};
} | Return a function for the dataset's patio.Dataset#inputIdentifierMethod. Used in metadata parsing to make sure the returned information is in the correct format. |
logger | function | function (){
return LOGGER;
} | The "patio.Database" logger. |
metadataDataset | patio.Dataset | function (){
if (this.__metadataDataset) {
return this.__metadataDataset;
}
var ds = this.dataset;
ds.identifierInputMethod = this.identifierInputMethod;
ds.identifierOutputMethod = this.identifierOutputMethod;
this.__metadataDataset = ds;
return ds;
} | Return a dataset that uses the default identifier input and output methods for this database. Used when parsing metadata so that column are returned as expected. |
outputIdentifierFunc | Function | function (){
var ds = this.dataset;
return function (ident) {
return ds.outputIdentifier(ident);
};
} | Return a function for the dataset's patio.Dataset#outputIdentifierMethod. Used in metadata parsing to make sure the returned information is in the correct format. |
quoteIdentifiers | Boolean |
true
| Boolean of whether or not to quote identifiers before sending then to the database. If this property is undefined then then patio.Database#quoteIdentifiersDefault will be used. |
quoteIdentifiersDefault | Boolean |
true
| Default boolean of whether or not to quote identifiers before sending then to the database. |
rollbackTransactionSql | String | function (){
return this.SQL_ROLLBACK;
} | SQL to ROLLBACK a transaction. See patio.Database#SQL_ROLLBACK for default, |
serialPrimaryKeyOptions | Object |
{primaryKey : true, type : "integer", autoIncrement : true}
| Default serial primary key options, used by the table creation code. |
supportsPreparedTransactions | Boolean |
false
| Whether the database and adapter support prepared transactions (two-phase commit) |
supportsSavepoints | Boolean |
false
| Whether the database and adapter support savepoints. |
supportsTransactionIsolationLevels | Boolean |
false
| Whether the database and adapter support transaction isolation levels. |
temporaryTableSql | function | function (){
return this._static.TEMPORARY;
} | |
uri | String | A database URI used to create the database connection. This property is available even if an object was used to create the database connection. | |
function (opts){ opts = opts || {}; if (!patio) { patio = require("../index"); } this.patio = patio; this._super(arguments, [opts]); opts = merge(this.connectionPoolDefaultOptions, opts); this.schemas = {}; this.type = opts.type; this.defaultSchema = opts.defaultSchema || this.defaultSchemaDefault; this.preparedStatements = {}; this.opts = opts; this.pool = ConnectionPool.getPool(opts, hitch(this, this.createConnection), hitch(this, this.closeConnection), hitch(this, this.validate)); }
Creates a connection to a Database see patio#createConnection.
Argumentsfunction (connectionString,opts){ opts = opts || {}; if (isString(connectionString)) { var url = URL.parse(connectionString, true); if (url.auth) { var parts = url.auth.split(":"); if (!opts.user) { opts.user = parts[0]; } if (!opts.password) { opts.password = parts[1]; } } opts.type = url.protocol.replace(":", ""); opts.host = url.hostname; if (url.port) { opts.port = url.port; } if (url.pathname) { var path = url.pathname; var pathParts = path.split("/").slice(1); if (pathParts.length >= 1) { opts.database = pathParts[0]; } } opts = merge(opts, url.query, {uri: connectionString}); } else { opts = merge({}, connectionString, opts); } if (opts && isHash(opts) && (opts.adapter || opts.type)) { var type = (opts.type = opts.adapter || opts.type); var Adapter = ADAPTERS[type]; if (Adapter) { var adapter = new Adapter(opts); this.DATABASES.push(adapter); return adapter; } else { throw new DatabaseError(type + " adapter was not found"); } } else { throw new DatabaseError("Options required when connecting."); } }
Logs a DEBUG level message to the "patio.Database" logger.
Sourcefunction (){ if (LOGGER.isDebug) { LOGGER.debug.apply(LOGGER, arguments); } }
Logs a ERROR level message to the "patio.Database" logger.
Sourcefunction (){ if (LOGGER.isError) { LOGGER.error.apply(LOGGER, arguments); } }
Logs a FATAL level message to the "patio.Database" logger.
Sourcefunction (){ if (LOGGER.isFatal) { LOGGER.fatal.apply(LOGGER, arguments); } }
Logs an INFO level message to the "patio.Database" logger.
Sourcefunction (){ if (LOGGER.isInfo) { LOGGER.info.apply(LOGGER, arguments); } }
Logs a TRACE level message to the "patio.Database" logger.
Sourcefunction (){ if (LOGGER.isTrace) { LOGGER.trace.apply(LOGGER, arguments); } }
Logs a WARN level message to the "patio.Database" logger.
Sourcefunction (){ if (LOGGER.isWarn) { LOGGER.warn.apply(LOGGER, arguments); } }
function (table,op){ var ret = new Promise(); var quotedName = op.name ? this.__quoteIdentifier(op.name) : null; var alterTableOp = null; switch (op.op) { case "addColumn": alterTableOp = format("ADD COLUMN %s", this.__columnDefinitionSql(op)); break; case "dropColumn": alterTableOp = format("DROP COLUMN %s", quotedName); break; case "renameColumn": alterTableOp = format("RENAME COLUMN %s TO %s", quotedName, this.__quoteIdentifier(op.newName)); break; case "setColumnType": alterTableOp = format("ALTER COLUMN %s TYPE %s", quotedName, this.typeLiteral(op)); break; case "setColumnDefault": alterTableOp = format("ALTER COLUMN %s SET DEFAULT %s", quotedName, this.literal(op["default"])); break; case "setColumnNull": alterTableOp = format("ALTER COLUMN %s %s NOT NULL", quotedName, op["null"] ? "DROP" : "SET"); break; case "addIndex": return ret.callback(this.__indexDefinitionSql(table, op)).promise(); case "dropIndex": return ret.callback(this.__dropIndexSql(table, op)).promise(); case "addConstraint": alterTableOp = format("ADD %s", this.__constraintDefinitionSql(op)); break; case "dropConstraint": alterTableOp = format("DROP CONSTRAINT %s", quotedName); break; case "noInherit": alterTableOp = format("NO INHERIT %s", quotedName); break; default : throw new DatabaseError("Invalid altertable operator"); } return ret.callback(format("ALTER TABLE %s %s", this.__quoteSchemaTable(table), alterTableOp)).promise(); }
function (table,operations){ var self = this; return new PromiseList(operations.map(function (operation) { return self.__alterTableSql(table, operation); })); }
function (column){ var sql = [format("%s %s", this.__quoteIdentifier(column.name), this.typeLiteral(column))]; column.unique && sql.push(this._static.UNIQUE); (column.allowNull === false || column["null"] === false) && sql.push(this._static.NOT_NULL); (column.allowNull === true || column["null"] === true) && sql.push(this._static.NULL); !isUndefined(column["default"]) && sql.push(format(" DEFAULT %s", this.literal(column["default"]))); column.primaryKey && sql.push(this._static.PRIMARY_KEY); column.autoIncrement && sql.push(" " + this.autoIncrementSql); column.table && sql.push(this.__columnReferencesColumnConstraintSql(column)); return sql.join(""); }
function (generator){ var self = this; return generator.columns.map(function (column) { return self.__columnDefinitionSql(column); }).concat(generator.constraints.map(function (constraint) { return self.__constraintDefinitionSql(constraint); })).join(this._static.COMMA_SEPARATOR); }
function (column){ return this.__columnReferencesSql(column); }
function (column){ var sql = format(" REFERENCES %s", this.__quoteSchemaTable(column.table)); column.key && (sql += format("(%s)", array.toArray(column.key).map(this.__quoteIdentifier, this).join(this._static.COMMA_SEPARATOR))); column.onDelete && (sql += format(" ON DELETE %s", this.__onDeleteClause(column.onDelete))); column.onUpdate && (sql += format(" ON UPDATE %s", this.__onUpdateClause(column.onUpdate))); column.deferrable && (sql += " DEFERRABLE INITIALLY DEFERRED"); return sql; }
function (constraint){ return format("FOREIGN KEY %s%s", this.literal(constraint.columns.map(function (c) { return isString(c) ? sql.stringToIdentifier(c) : c; })), this.__columnReferencesSql(constraint)); }
function (constraint){ var ret = [constraint.name ? format("CONSTRAINT %s ", this.__quoteIdentifier(constraint.name)) : ""]; switch (constraint.type) { case "check": var check = constraint.check; ret.push(format("CHECK %s", this.__filterExpr(isArray(check) && check.length === 1 ? check[0] : check))); break; case "primaryKey": ret.push(format("PRIMARY KEY %s", this.literal(constraint.columns.map(function (c) { return isString(c) ? sql.stringToIdentifier(c) : c; })))); break; case "foreignKey": ret.push(this.__columnReferencesTableConstraintSql(constraint)); break; case "unique": ret.push(format("UNIQUE %s", this.literal(constraint.columns.map(function (c) { return isString(c) ? sql.stringToIdentifier(c) : c; })))); break; default: throw new DatabaseError(format("Invalid constriant type %s, should be 'check', 'primaryKey', foreignKey', or 'unique'", constraint.type)); } return ret.join(""); }
function (name,generator,options){ return this.executeDdl(this.__createTableSql(name, generator, options)); }
function (name,generator,options){ var e = options.ignoreIndexErrors; var ret; var promises = generator.indexes.map(function (index) { var ps = this.__indexSqlList(name, [index]).map(this.executeDdl, this); return new PromiseList(ps); }, this); if (promises.length) { ret = new PromiseList(promises).chain(function (res) { return res; }, function (err) { if (!e) { throw err; } }); } else { ret = new Promise().callback(); } return ret.promise(); }
function (name,generator,options){ return format("CREATE %sTABLE %s (%s)", options.temp ? this.temporaryTableSql : "", this.__quoteSchemaTable(name), this.__columnListSql(generator)); }
function (name,source,opts){ var sql = "CREATE"; opts = opts || {}; if (opts.replace) { sql += " OR REPLACE"; } sql += " VIEW %s AS %s"; return format(sql, this.__quoteSchemaTable(name), source); }
function (tableName,columns){ var parts = this.__schemaAndTable(tableName); var schema = parts[0], table = parts[1]; var index = []; if (schema && schema !== this.defaultSchema) { index.push(schema); } index.push(table); index = index.concat(columns.map(function (c) { return isString(c) ? c : this.literal(c).replace(/\W/g, ""); }, this)); index.push("index"); return index.join(this._static.UNDERSCORE); }
function (table,op){ return format("DROP INDEX %s", this.__quoteIdentifier(op.name || this.__defaultIndexName(table, op.columns))); }
function (name){ return format("DROP TABLE %s", this.__quoteSchemaTable(name)); }
function (name){ return format("DROP VIEW %s", this.__quoteSchemaTable(name)); }
function (args,block){ var ds = this.__schemaUtiltyDataset; return ds.literal(ds._filterExpr.apply(ds, arguments)); }
function (tableName,index){ var indexName = index.name || this.__defaultIndexName(tableName, index.columns); if (index.type) { throw new DatabaseError("Index types are not supported for this database"); } else if (index.where) { throw new DatabaseError("Partial indexes are not supported for this database"); } else { return format("CREATE %sINDEX %s ON %s %s", index.unique ? "UNIQUE " : "", this.__quoteIdentifier(indexName), this.__quoteSchemaTable(tableName), this.literal(index.columns.map(function (c) { return isString(c) ? new Identifier(c) : c; }))); } }
Array of SQL DDL statements, one for each index specification, for the given table.
Argumentsfunction (tableName,indexes){ var self = this; return indexes.map(function (index) { return self.__indexDefinitionSql(tableName, index); }); }
function (action){ return this._static[action.toUpperCase()] || this._static.NO_ACTION; }
function (action){ return this._static[action.toUpperCase()] || this._static.NO_ACTION; }
function (v){ return this.__schemaUtiltyDataset.quoteIdentifier(v); }
function (table){ return this.__schemaUtiltyDataset.quoteSchemaTable(table); }
function (name,newName){ return format("ALTER TABLE %s RENAME TO %s", this.__quoteSchemaTable(name), this.__quoteSchemaTable(newName)); }
function (){ this.__schemaUtiltyDs = null; }
function (tableName){ return this.__schemaUtiltyDataset.schemaAndTable(tableName); }
function (column){ var type = column.type; var meth = "__typeLiteralGeneric"; var isStr = isString(type); var proper = isStr ? type.charAt(0).toUpperCase() + type.substr(1) : null; if (type === String || (isStr && type.match(/string/i))) { meth += "String"; } else if ((isStr && type.match(/number/i)) || type === Number) { meth += "Numeric"; } else if ((isStr && type.match(/datetime/i)) || type === DateTime) { meth += "DateTime"; } else if ((isStr && type.match(/date/i)) || type === Date) { meth += "Date"; } else if ((isStr && type.match(/year/i)) || type === Year) { meth += "Year"; } else if ((isStr && type.match(/timestamp/i)) || type === TimeStamp) { meth += "Timestamp"; } else if ((isStr && type.match(/time/i)) || type === Time) { meth += "Time"; } else if ((isStr && type.match(/decimal/i)) || type === Decimal) { meth += "Decimal"; } else if ((isStr && type.match(/float/i)) || type === Float) { meth += "Float"; } else if ((isStr && type.match(/boolean/i)) || type === Boolean) { meth += "Boolean"; } else if ((isStr && type.match(/buffer/i)) || type === Buffer) { meth += "Blob"; } else if ((isStr && type.match(/json/i)) || type === Json) { meth += "Json"; } else if (isStr && isFunction(this[meth + proper])) { meth += proper; } else { return this.__typeLiteralSpecific(column); } return this[meth](column); }
function (column){ return "blob"; }
function (column){ return "boolean"; }
function (column){ var type = column.type, ret = "date"; if (column.onlyTime) { ret = "time"; } else if (column.timeStamp) { ret = "timestamp"; } else if (column.dateTime) { ret = "datetime"; } else if (column.yearOnly) { ret = "year"; } return ret; }
function (column){ return "datetime"; }
function (column){ return "double precision"; }
function (column){ return "double precision"; }
function (column){ return "json"; }
function (column){ return column.size ? format("numeric(%s)", array.toArray(column.size).join(', ')) : column.isInt ? "integer" : column.isDouble ? "double precision" : "numeric"; }
function (column){ return column.text ? "text" : format("%s(%s)", column.fixed ? "char" : "varchar", column.size || 255); }
function (column){ return "time"; }
function (column){ return "timestamp"; }
function (column){ return "year"; }
function (column){ var type = column.type; type = type === "double" ? "double precision" : type; if (type === "varchar") { column.size = isNumber(column.size) ? column.size : 255; } var elements = column.size || column.elements; return format("%s%s%s", type, elements ? this.literal(toArray(elements)) : "", column.unsigned ? " UNSIGNED" : ""); }
function (schema){ return !!schema.primaryKey; }
Adds a column to the specified table. This method expects a column name, a datatype and optionally a hash with additional constraints and options:
This method is a shortcut to patio.Database#alterTable with an addColumn call.
Example//Outside of a table //ALTER TABLE test ADD COLUMN name text UNIQUE' DB.addColumn("test", "name", "text", {unique : true});Arguments
the table to add the column to.
the name of the column to add.
datatype of the column
additional options that can be used when adding a column.
Boolean
: set to true if this column is a primary key.
Boolean
: whether or not this column should allow null.
Boolean
: set to true to add a UNIQUE constraint to a column,
Promise
a promise that is resolved when the ADD COLUMN action is complete.
function (table,column,type,opts){ var args = argsToArray(arguments).slice(1); return this.alterTable(table, function () { this.addColumn.apply(this, args); }); }
Adds an index to a table for the given columns
This method is a shortcut to patio.Database#alterTable with an addIndex call.
ExampleDB.addIndex("test", "name", {unique : true}); //=> 'CREATE UNIQUE INDEX test_name_index ON test (name)' DB.addIndex("test", ["one", "two"]); //=> ''CREATE INDEX test_one_two_index ON test (one, two)''Arguments
the table to add the index to.
the name of the column/s to create an index for.
additional options that can be used when adding an index.
Boolean
: set to true if this this index should have a UNIQUE constraint.
Boolean
: set to true to ignore errors.
Promise
a promise that is resolved when the CREATE INDEX action is complete.
function (table,columns,options){ options = options || {}; var ignoreErrors = options.ignoreErrors === true; return this.alterTable(table, function () { this.addIndex(columns, options); }).chain(function (res) { return res; }, function (err) { if (!ignoreErrors) { throw err; } }); }
Returns true if this DATABASE is currently in a transaction.
ArgumentsBoolean
true if this dabase is currently in a transaction.
function (conn,opts){ opts = opts || {}; return this.__transactions.indexOf(conn) !== -1 && (!this.supportsSavepoints || !opts.savepoint); }
Alters the given table with the specified block.
NOTE: The block is invoked in the scope of the table that is being altered. The block is also called with the table as the first argument. Within the block you must use this(If the block has not been bound to a different scope), or the table object that is passed in for all alter table operations. See patio.AlterTableGenerator for avaiable operations.
Note that addColumn accepts all the options available for column definitions using createTable, and addIndex accepts all the options available for index definition.
Example//using the table object DB.alterTable("items", function(table){ //you must use the passed in table object. table.addColumn("category", "text", {default : 'javascript'}); table.dropColumn("category"); table.renameColumn("cntr", "counter"); table.setColumnType("value", "float"); table.setColumnDefault("value", "float"); table.addIndex(["group", "category"]); table.dropIndex(["group", "category"]); }); //using this DB.alterTable("items", function(){ this.addColumn("category", "text", {default : 'javascript'}); this.dropColumn("category"); this.renameColumn("cntr", "counter"); this.setColumnType("value", "float"); this.setColumnDefault("value", "float"); this.addIndex(["group", "category"]); this.dropIndex(["group", "category"]); }); //This will not work DB.alterTable("items", comb.hitch(someObject, function(){ //This is called in the scope of someObject so this //will not work and will throw an error this.addColumn("category", "text", {default : 'javascript'}); })); //This will work DB.alterTable("items", comb.hitch(someObject, function(table){ //This is called in the scope of someObject so you must //use the table argument table.category("text", {default : 'javascript'}); }));Arguments
the block to invoke for the ALTER TABLE operations
String|patio.sql.Identifier
: to the table to perform the ALTER TABLE operations on.
Promise
a promise that is resolved once all ALTER TABLE operations have completed.
function (name,generator,block){ if (isFunction(generator)) { block = generator; generator = new AlterTableGenerator(this, block); } var self = this; return this.__alterTableSqlList(name, generator.operations).chain(function (res) { return asyncArray(comb(res).pluck("1") .flatten()) .forEach(function (sql) { return self.executeDdl(sql); }) .chain(function () { return self.removeCachedSchema(name); }); }); }
Casts the given type to a SQL type.
ExampleDB.castTypeLiteral(Number) //=> numeric DB.castTypeLiteral("foo") //=> foo DB.castTypeLiteral(String) //=> varchar(255) DB.castTypeLiteral(Boolean) //=> booleanArguments
the javascript type to cast to a SQL type.
String
the SQL data type.
function (type){ return this.typeLiteral({type: type}); }
This is an abstract method that should be implemented by adapters to close a connection to the database.
Argumentsthe database connection to close.
function (conn){ throw new NotImplemented("Close connection must be implemented by the adapter"); }
This is an abstract method that should be implemented by adapters to create a connection to the database.
Argumentsoptions that are adapter specific.
function (options){ throw new NotImplemented("Create connection must be implemented by the adapter"); }
Creates a view, replacing it if it already exists:
ExampleDB.createOrReplaceView("cheapItems", "SELECT * FROM items WHERE price < 100"); //=> CREATE OR REPLACE VIEW cheapItems AS SELECT * FROM items WHERE price < 100 DB.createOrReplaceView("miscItems", DB.from("items").filter({category : 'misc'})); //=> CREATE OR REPLACE VIEW miscItems AS SELECT * FROM items WHERE category = 'misc'Arguments
the name of the view to create.
the SQL or patio.Dataset to use as the source of the view.
Promise
a promise that is resolved when the CREATE OR REPLACE VIEW action is complete.
function (name,source,opts){ if (isInstanceOf(source, Dataset)) { source = source.sql; } opts = opts || {}; opts.replace = true; var self = this; return this.executeDdl(this.__createViewSql(name, source, opts)).chain(function () { return self.removeCachedSchema(name); }); }
Creates a table with the columns given in the provided block:
NOTE: The block is invoked in the scope of the table that is being created. The block is also called with the table as the first argument. Within the block you must use this(If the block has not been bound to a different scope), or the table object that is passed in for all create table operations. See patio.SchemaGenerator for available operations.
Example//using the table to create the table DB.createTable("posts", function(table){ table.primaryKey("id"); table.column('title", "text"); //you may also invoke the column name as //function on the table table.content(String); table.index(title); }); //using this to create the table DB.createTable("posts", function(){ this.primaryKey("id"); this.column('title", "text"); //you may also invoke the column name as //function on the table this.content(String); this.index(title); });Arguments
the name of the table to create.
an optional options object
the block to invoke when creating the table.
Boolean
: set to true if this table is a TEMPORARY table.
Boolean
: Ignore any errors when creating indexes.
Promise
a promise that is resolved when the CREATE TABLE action is completed.
function (name,options,block){ if (isFunction(options)) { block = options; options = {}; } this.removeCachedSchema(name); if (isInstanceOf(options, SchemaGenerator)) { options = {generator: options}; } var generator = options.generator || new SchemaGenerator(this, block), self = this; return this.__createTableFromGenerator(name, generator, options).chain(function () { return self.__createTableIndexesFromGenerator(name, generator, options); }); }
Creates the table unless the table already exists.
See patio.Database#createTable for parameter types.
Argumentsfunction (name,options,block){ var self = this; return this.tableExists(name).chain(function (exists) { if (!exists) { return self.createTable(name, options, block); } }); }
Creates a view based on a dataset or an SQL string:
ExampleDB.createView("cheapItems", "SELECT * FROM items WHERE price < 100"); //=> CREATE VIEW cheapItems AS SELECT * FROM items WHERE price < 100 DB.createView("miscItems", DB.from("items").filter({category : 'misc'})); //=> CREATE VIEW miscItems AS SELECT * FROM items WHERE category = 'misc'Arguments
the name of the view to create.
the SQL or patio.Dataset to use as the source of the view.
function (name,source,opts){ if (isInstanceOf(source, Dataset)) { source = source.sql; } return this.executeDdl(this.__createViewSql(name, source, opts)); }
Disconnects the database closing all connections.
ReturnsPromise a promise that is resolved once all the connections have been closed.
function (){ var self = this; return this.pool.endAll() .chain(function () { return self.onDisconnect(self); }) .chain(function () { return null; }); }
Removes a column from the specified table.
This method is a shortcut to patio.Database#alterTable with an dropColumn call.
ExampleDB.dropColumn("items", "category"); //=> 'ALTER TABLE items DROP COLUMN category',Arguments
the table to alter.
the column to drop.
Promise
a promise that is resolved once the DROP COLUMN action is complete.
function (table,column){ column = argsToArray(arguments).slice(1); return this.alterTable(table, function () { this.dropColumn.apply(this, column); }); }
Removes an index for the given table and column/s.
This method is a shortcut to patio.Database#alterTable with an dropIndex call.
ExampleDB.dropIndex("posts", "title"); //=>'DROP INDEX posts_title_index DB.dropIndex("posts", ["author", "title"]); //'DROP INDEX posts_author_title_index'Arguments
the table to alter.
String|patio.sql.Identifier
: the name of the column/s the index was created from.
Promise
a promise that is resolved once the DROP INDEX action is complete.
function (table,columns,options){ var args = argsToArray(arguments).slice(1); return this.alterTable(table, function () { this.dropIndex.apply(this, args); }); }
Drops one or more tables corresponding to the given names.
ExampleDB.dropTable("test"); //=>'DROP TABLE test' DB.dropTable("a", "bb", "ccc"); //=>'DROP TABLE a', //=>'DROP TABLE bb', //=>'DROP TABLE ccc'Arguments
the names of the tables to drop.
Promise
a promise that is resolved once all tables have been dropped.
function (names){ if (!isArray(names)) { names = comb(arguments).toArray(); } names = names.filter(function (t) { return isString(t) || isInstanceOf(t, Identifier, QualifiedIdentifier); }); var self = this; return asyncArray(names).forEach(function (name) { return self.executeDdl(self.__dropTableSql(name)).chain(function () { return self.removeCachedSchema(name); }); }, 1); }
Drops one or more views corresponding to the given names.
ExampleDB.dropView("test_view"); //=>'DROP VIEW test_view' DB.dropTable("test_view_1", "test_view_2", "test_view_3"); //=>'DROP VIEW test_view_1', //=>'DROP VIEW test_view_2', //=>'DROP VIEW test_view_3'Arguments
the names of the views to drop.
{}
] : Additional options that very based on the database adapter.
Promise
a promise that is resolved once the view/s have been dropped.
function (names,opts){ if (isArray(names)) { opts = opts || {}; var self = this; return asyncArray(names).forEach(function (name) { return self.executeDdl(self.__dropViewSql(name, opts)).chain(function () { self.removeCachedSchema(name); }); }, null, 1).chain(function () { return null; }); } else { var args = argsToArray(arguments); if (comb.isHash(args[args.length - 1])) { opts = args.pop(); } return this.dropView(args.filter(function (t) { return isString(t) || isInstanceOf(t, Identifier, QualifiedIdentifier); }), opts); } }
Executes the given SQL on the database. This method should be implemented by adapters. This method should not be called directly by user code.
Argumentsfunction (sql,opts,conn){ var ret; if (opts.stream) { ret = this.__executeStreamed(sql, opts, conn); } else { ret = this.__executePromised(sql, opts, conn); } return ret; }
Method that should be used when submitting any DDL (Data DefinitionLanguage) SQL, such as patio.Database#createTable. By default, calls patio.Database#executeDui. This method should not be called directly by user code.
Argumentsfunction (sql,opts){ opts = opts || {}; return this.executeDui(sql, opts); }
Method that should be used when issuing a DELETE, UPDATE, or INSERT statement. By default, calls patio.Database#execute. This method should not be called directly by user code.
Argumentsfunction (sql,opts){ opts = opts || {}; return this.execute(sql, opts); }
Method that should be used when issuing a INSERT statement. By default, calls patio.Database#executeDui. This method should not be called directly by user code.
Argumentsfunction (sql,opts){ opts = opts || {}; return this.executeDui(sql, opts); }
Fetches records for an arbitrary SQL statement. If a block is given, it is used to iterate over the records:
DB.fetch('SELECT * FROM items', function(r){ //do something with row });If a block is not given then patio.Database#fetch method returns a patio.Dataset instance:
DB.fetch('SELECT * FROM items').all().chain(function(records){ //do something with the records. });
patio.Database#fetch can also perform parameterized queries for protection against SQL injection:
DB.fetch('SELECT * FROM items WHERE name = ?', myName).all().chain(function(records){ //do something with the records. });Arguments
variable number of args where the first argument is a String. If more than one argument is given then the SQL will be treated as a place holder string. See patio.Dataset#withSql.
null
] : if the last argument given is a function then patio.Dataset#forEach will be invoked on the dataset with the block called for each row.
Promise|patio.Dataset
if no block is given then a patio.Dataset will be returned. If a block is given then the return value will be a Promise that will be invoked after all records have been returned and processed through the block.
function (args,block){ var ret; args = argsToArray(arguments); block = isFunction(args[args.length - 1]) ? args.pop() : null; var ds = this.dataset.withSql.apply(this.dataset, args); if (block) { ret = ds.forEach(block).chain(function () { return ds; }).promise(); } else { ret = ds; } return ret; }
Forcibly creates a table, attempting to drop it unconditionally (and catching any errors), then creating it.
See patio.Database#createTable for parameter types.
Example// DROP TABLE a // CREATE TABLE a (a integer) DB.forceCreateTable("a", function(){ this.a("integer"); });Arguments
function (name,options,block){ var self = this; return this.dropTable(name).chainBoth(function () { return self.createTable(name, options, block); }); }
Forcible drops one or more tables corresponding to the given names, ignoring errors.
ExampleDB.dropTable("test"); //=>'DROP TABLE test' DB.dropTable("a", "bb", "ccc"); //=>'DROP TABLE a', //=>'DROP TABLE bb', //=>'DROP TABLE ccc'Arguments
the names of the tables to drop.
Promise
a promise that is resolved once all tables have been dropped.
function (names){ if (!isArray(names)) { names = comb(arguments).toArray(); } names = names.filter(function (t) { return isString(t) || isInstanceOf(t, Identifier, QualifiedIdentifier); }); var l = names.length, ret = new Promise(), self = this; var drop = function (i) { if (i < l) { var name = names[i++]; self.executeDdl(self.__dropTableSql(name)).both(function () { self.removeCachedSchema(name); drop(i); }); } else { ret.callback(); } }; drop(0); return ret.promise(); }
Returns a new patio.Dataset with the [@link patio.Dataset#from} method invoked. If a block is given, it is used as a filter(see patio.Dataset#filter on the dataset.
ExampleDB.from("items").sql //=> SELECT * FROM items DB.from("items", function(){ return this.id.gt(2) }).sql; //=> SELECT * FROM items WHERE (id > 2)Arguments
table/s to pass to patio.Dataset#from with.
an option block to pass to patio.Dataset#filter with.
patio.Dataset
a dataset to use for querying the patio.Database with.
function (args,block){ args = argsToArray(arguments); block = isFunction(args[args.length - 1]) ? args.pop() : null; var ds = this.dataset; ds = ds.from.apply(ds, args); return block ? ds.filter(block) : ds; }
Proxy for patio.Dataset#get.
Sourcefunction (){ return this.dataset.get.apply(this.dataset, arguments); }
Return a Promise that is resolved with an object containing index information.
The keys are index names. Values are objects with two keys, columns and unique. The value of columns is an array of column names. The value of unique is true or false depending on if the index is unique.
Should not include the primary key index, functional indexes, or partial indexes.
ExampleDB.indexes("artists").chain(function(indexes){ //e.g. indexes === {artists_name_ukey : {columns : [name], unique : true}}; })Arguments
function (table,opts){ throw new NotImplemented("indexes should be overridden by adapters"); }
This function acts as a proxy to patio.Dataset#literal.
Argumentsfunction (v){ return this.dataset.literal(v); }
Logs a DEBUG level message to the "patio.Database" logger.
Sourcefunction (){ LOGGER.debug.apply(LOGGER, arguments); }
Logs an ERROR level message to the "patio.Database" logger.
Argumentsfunction (error){ LOGGER.error.apply(LOGGER, arguments); }
Logs a FATAL level message to the "patio.Database" logger.
Sourcefunction (){ LOGGER.fatal.apply(LOGGER, arguments); }
Logs an INFO level message to the "patio.Database" logger.
Sourcefunction (){ LOGGER.info.apply(LOGGER, arguments); }
Logs a TRACE level message to the "patio.Database" logger.
Sourcefunction (){ LOGGER.trace.apply(LOGGER, arguments); }
Logs a WARN level message to the "patio.Database" logger.
Sourcefunction (){ LOGGER.warn.apply(LOGGER, arguments); }
Remove the cached schema for the given table name
ExampleDB.schema("artists").chain(function(){ DB.removeCachedSchema("artists"); });Arguments
String|patio.sql.Identifier|patio.sql.QualifiedIdentifier
: table to remove from this databases cached schemas.
function (table){ if (this.schemas && !isEmpty(this.schemas)) { delete this.schemas[this.__quoteSchemaTable(table)]; } }
Renames a column in the specified table.
This method is a shortcut to patio.Database#alterTable with an renameColumn call.
ExampleDB.renameColumn("items", "cntr", "counter"); //=> ALTER TABLE items RENAME COLUMN cntr TO counterArguments
the table to alter.
the name of the column to rename.
the new name of the column.
Promise
a promise that is resolved once the RENAME COLUMN action is complete.
function (table,column,newColumn){ var args = argsToArray(arguments).slice(1); return this.alterTable(table, function () { this.renameColumn.apply(this, args); }); }
Renames a table.
Examplecomb.executeInOrder(DB, function(DB){ DB.tables(); //=> ["items"] DB.renameTable("items", "old_items"); //=>'ALTER TABLE items RENAME TO old_items' DB.tables; //=> ["old_items"] });Arguments
the name of the table to rename
the new name of the table
Promise
a promise that is resolved once the table is renamed.
function (name,newName){ var self = this; return this.executeDdl(this.__renameTableSql(name, newName)).chain(function () { self.removeCachedSchema(name); }).promise(); }
Runs the supplied SQL statement string on the database server..
ExampleDB.run("SET some_server_variable = 42")Arguments
the SQL to run.
Promise
a promise that is resolved with the result of the query.
function (sql,opts){ opts = opts || {}; return this.executeDdl(sql, opts); }
Parse the schema from the database.
ExampleDB.schema("artists").chain(function(schema){ //example schema { id : { type : "integer", primaryKey : true, "default" : "nextval('artist_id_seq'::regclass)", jsDefault : null, dbType : "integer", allowNull : false }, name : { type : "string", primaryKey : false, "default" : null, jsDefault : null, dbType : "text", allowNull : false } } })Arguments
the table to get the schema for.
null
] : Additinal options.
false
] boolean
: Set to true to ignore any cached results.
String|patio.sql.Identifier
: An explicit schema to use. It may also be implicitly provided via the table name.
Promise
Returns a Promise that is resolved with the schema for the given table as an object where the key is the column name and the value is and object containg column information. The default column information returned.
function (table,opts){ if (!isFunction(this.schemaParseTable)) { throw new Error("Schema parsing is not implemented on this database"); } opts = opts || {}; var schemaParts = this.__schemaAndTable(table); var sch = schemaParts[0], tableName = schemaParts[1]; var quotedName = this.__quoteSchemaTable(table); opts = sch && !opts.schema ? merge({schema: sch}, opts) : opts; if (opts.reload) { delete this.schemas[quotedName]; } var self = this; return this.schemaParseTable(tableName, opts).chain(function (cols) { if (!cols || cols.length === 0) { throw new Error("Error parsing schema, " + table + " no columns returns, table probably doesnt exist"); } else { var schema = {}; cols.forEach(function (c) { var name = c[0]; c = c[1]; c.jsDefault = self.__columnSchemaToJsDefault(c["default"], c.type); schema[name] = c; }); return schema; } }); }
Match the database's column type to a javascript type via a regular expression, and return the javascript type as a string such as "integer" or "string".
Argumentsfunction (dbType){ var ret = dbType, m; if (dbType.match(/^interval$/i)) { ret = "interval"; } else if (dbType.match(/^(character( varying)?|n?(var)?char)/i)) { ret = "string"; } else if (dbType.match(/^int(eger)?|(big|small|tiny)int/i)) { ret = "integer"; } else if (dbType.match(/^date$/i)) { ret = "date"; } else if (dbType.match(/^year/i)) { ret = "year"; } else if (dbType.match(/^((small)?datetime|timestamp( with(out)? time zone)?)$/i)) { ret = "datetime"; } else if (dbType.match(/^time( with(out)? time zone)?$/i)) { ret = "time"; } else if (dbType.match(/^(bit|boolean)$/i)) { ret = "boolean"; } else if (dbType.match(/^(real|float|double( precision)?)$/i)) { ret = "float"; } else if ((m = dbType.match(/^(?:(?:(?:num(?:ber|eric)?|decimal|double)(?:\(\d+,\s*(\d+)\))?)|(?:small)?money)/i))) { ret = m[1] && m[1] === '0' ? "integer" : "decimal"; } else if (dbType.match(/n?text/i)) { ret = "text"; } else if (dbType.match(/bytea|[bc]lob|image|(var)?binary/i)) { ret = "blob"; } else if (dbType.match(/^enum/i)) { ret = "enum"; } else if (dbType.match(/^set/i)) { ret = "set"; } else if (dbType.match(/^json/i)) { ret = "json"; } return ret; }
Returns a new patio.Dataset with the patio.Dataset#select method invoked.
ExampleDB.select(1) //=> SELECT 1 DB.select(function(){ return this.server_version(); }).sql; //=> SELECT server_version() DB.select("id").from("items").sql; //=> SELECT id FROM items @link {patio.Dataset} a dataset to query the {@link patio.Database} with.Source
function (){ var ds = this.dataset; return ds.select.apply(ds, arguments); }
Sets the default value for the given column in the given table:
This method is a shortcut to patio.Database#alterTable with an setColumnDefault call.
ExampleDB.setColumnDefault("items", "category", "misc"); //=> ALTER TABLE items ALTER COLUMN category SET DEFAULT 'misc'Arguments
the table to alter.
the name of the column to set the DEFAULT on.
the new default value of the column.
Promise
a promise that is resolved once the SET DEFAULT action is complete.
function (table,column,def){ var args = argsToArray(arguments).slice(1); return this.alterTable(table, function () { this.setColumnDefault.apply(this, args); }); }
Set the data type for the given column in the given table:
This method is a shortcut to patio.Database#alterTable with an setColumnType call.
ExampleDB.setColumnType("items", "category", String); //=> ALTER TABLE items ALTER COLUMN category TYPE varchar(255)Arguments
the table to alter.
the name of the column to set the TYPE on.
the datatype of the column.
Promise
a promise that is resolved once the SET TYPE action is complete.
function (table,column,type){ var args = argsToArray(arguments).slice(1); return this.alterTable(table, function () { this.setColumnType.apply(this, args); }); }
Determine if a table exists.
Examplecomb.executeInOrder(DB, function(DB){ return { table1Exists : DB.tableExists("table1"), table2Exists : DB.tableExists("table2") }; }).chain(function(ret){ //ret.table1Exists === true //ret.table2Exists === false });Arguments
String|patio.sql.Identifier|patio.sql.QualifiedIdentifier
: table to remove from this
Promise
a promise resolved with a boolean indicating if the table exists.
function (table,cb){ return this.from(table).first().chain(function () { return true; }, function () { return false; }).classic(cb).promise(); }
Returns a promise with a list of tables names in this database. This method should be implemented by the adapter.
ExampleDB.tables().chain(function(tables){ //e.g. tables === ["table1", "table2", "table3"]; });Returns
Promise
a promise that is resolved with a list of tablenames.
function (){ throw new NotImplemented("tables should be implemented by the adapter"); }
Starts a database transaction. When a database transaction is used, either all statements are successful or none of the statements are successful.
Note that MySQL MyISAM tables do not support transactions.
//normal transaction
DB.transaction(function() {
return comb.when(
this.execute('DROP TABLE test;'),
this.execute('DROP TABLE test2;')
);
});
//transaction with a save point.
DB.transaction(function() {
return this.transaction({savepoint : true}, function() {
return comb.when(
this.execute('DROP TABLE test;'),
this.execute('DROP TABLE test2;')
);
});
});
Using a promise.
var ds = db.from("user");
db.transaction(function(){
return ds.insert({
firstName:"Jane",
lastName:"Gorgenson",
password:"password",
dateOfBirth:new Date(1956, 1, 3)
}).chain(function(){
return ds.forEach(function(user){
return ds.where({id:user.id}).update({firstName:user.firstName + 1});
});
});
});
Using the done method
var ds = db.from("user");
db.transaction(function(db, done){
ds.insert({
firstName:"Jane",
lastName:"Gorgenson",
password:"password",
dateOfBirth:new Date(1956, 1, 3)
}).chain(function(){
ds.forEach(function(user){
return ds.where({id:user.id}).update({firstName:user.firstName + 1});
}).classic(done)
});
});
//WITH ISOLATION LEVELS
db.supportsTransactionIsolationLevels = true;
//BEGIN
//SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
//DROP TABLE test1'
//COMMIT
DB.transaction({isolation:"uncommited"}, function(d) {
return d.run("DROP TABLE test1");
});
//BEGIN
//SET TRANSACTION ISOLATION LEVEL READ COMMITTED
//DROP TABLE test1
//COMMIT
DB.transaction({isolation:"committed"}, function(d) {
return d.run("DROP TABLE test1");
});
//BEGIN
//SET TRANSACTION ISOLATION LEVEL REPEATABLE READ'
//DROP TABLE test1
//COMMIT
DB.transaction({isolation:"repeatable"}, function(d) {
return d.run("DROP TABLE test1");
});
//BEGIN
//SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
//DROP TABLE test1
//COMMIT
DB.transaction({isolation:"serializable"}, function(d) {
return d.run("DROP TABLE test1");
});
//With an Error
//BEGIN
//DROP TABLE test
//ROLLBACK
DB.transaction(function(d) {
d.execute('DROP TABLE test');
throw "Error";
});
Arguments
{}
] : options to use when performing the transaction.
a function used to perform the transaction. This function is called in the scope of the database by default so one can use this. The funciton is also called with the database as the first argument, and a function to be called when the tranaction is complete. If you return a promise from the transaction block then you do not need to call the done cb.
String
: This will ensure that the transaction will be run on its own connection and not part of another transaction if one is already in progress.
String
: The transaction isolation level to use for this transaction, should be "uncommitted", "committed", "repeatable", or "serializable", used if given and the database/adapter supports customizable transaction isolation levels.
String
: A string to use as the transaction identifier for a prepared transaction (two-phase commit), if the database/adapter supports prepared transactions.
Boolean
: Whether to create a new savepoint for this transaction, only respected if the database/adapter supports savepoints. By default patio will reuse an existing transaction, so if you want to use a savepoint you must use this option.
Promise
a promise that is resolved once the transaction is complete.
function (opts,cb){ if (isFunction(opts)) { cb = opts; opts = {}; } else { opts = opts || {}; } var ret; if (!this.__alreadyInTransaction) { this.__alreadyInTransaction = true; ret = this.__transaction(null, opts, cb); } else { ret = this.__enqueueTransaction(opts, cb); } return ret.promise(); }
function (column){ return this.__typeLiteralGeneric(column); }
Typecast the value to the given columnType. Calls typecastValue{ColumnType} if the method exists, otherwise returns the value.
ExampleDB.typeCastValue("boolean", 0) //=> false DB.typeCastValue("boolean", 1) //=> true DB.typeCastValue("timestamp", '2004-02-01 12:12:12') //=> new patio.sql.TimeStamp(2004, 1, 1, 12, 12, 12);Arguments
the SQL datatype of the column
the value to typecast.
the typecasted value.
patio.DatabaseError
if there is an error converting the value to the column type.
function (columnType,value){ if (isNull(value) || isUndefined(value)) { return null; } var meth = "__typecastValue" + columnType.charAt(0).toUpperCase() + columnType.substr(1).toLowerCase(); try { if (isFunction(this[meth])) { return this[meth](value); } else { return value; } } catch (e) { throw e; } }
Validates a connection before it is returned to the patio.ConnectionPool. This method should be implemented by the adapter.
Argumentsfunction (conn){ throw new NotImplemented("Validate must be implemented by the adapter"); }