refactored driver part

This commit is contained in:
Umed Khudoiberdiev 2016-03-19 22:01:04 +05:00
parent 3ffe430eaf
commit 7aa02a5e8d
6 changed files with 173 additions and 38 deletions

View File

@ -24,6 +24,7 @@ export class Connection {
private _subscribers: OrmSubscriber<any>[] = [];
private _broadcasters: OrmBroadcaster<any>[] = [];
private _repositories: Repository<any>[] = [];
private _options: ConnectionOptions;
// -------------------------------------------------------------------------
// Constructor
@ -81,6 +82,13 @@ export class Connection {
return this._repositories;
}
/**
* This connection options and settings.
*/
get options(): ConnectionOptions {
return this._options;
}
// -------------------------------------------------------------------------
// Public Methods
// -------------------------------------------------------------------------
@ -90,6 +98,7 @@ export class Connection {
*/
connect(options: ConnectionOptions): Promise<void> {
const schemaCreator = new SchemaCreator(this);
this._options = options;
return this._driver
.connect(options)
.then(() => {

View File

@ -38,4 +38,31 @@ export interface ConnectionOptions {
*/
autoSchemaCreate?: boolean;
/**
* Logging options.
*/
logging?: {
/**
* Some specific logger to be used. By default it console.
*/
logger?: (message: any, level: string) => void;
/**
* Used if you want to log every executed query.
*/
logQueries?: boolean;
/**
* Used if you want to log only failed query.
*/
logOnlyFailedQueries?: boolean;
/**
* Used if you want to log error of the failed query.
*/
logFailedQueryError?: boolean;
};
}

58
src/driver/BaseDriver.ts Normal file
View File

@ -0,0 +1,58 @@
import {Connection} from "../connection/Connection";
/**
* Provides base functionality for all driver implementations.
*/
export abstract class BaseDriver {
// -------------------------------------------------------------------------
// Properties
// -------------------------------------------------------------------------
connection: Connection;
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
protected logQuery(query: string) {
if (this.connection.options.logging && this.connection.options.logging.logQueries)
this.log("executing query: " + query, "log");
}
protected logQueryError(error: any) {
if (this.connection.options.logging && this.connection.options.logging.logFailedQueryError) {
this.log("error during executing query:", "error");
this.log(error, "error");
}
}
protected logFailedQuery(query: string) {
if (this.connection.options.logging &&
(this.connection.options.logging.logQueries || this.connection.options.logging.logOnlyFailedQueries))
this.log("query failed: " + query, "error");
}
protected log(message: any, level: "log"|"debug"|"info"|"error") {
if (!this.connection.options.logging) return;
if ( this.connection.options.logging.logger) {
this.connection.options.logging.logger(message, level);
} else {
switch (level) {
case "log":
console.log(message);
break;
case "debug":
console.debug(message);
break;
case "info":
console.info(message);
break;
case "error":
console.error(message);
break;
}
}
}
}

View File

@ -13,16 +13,16 @@ export interface Driver {
*/
native: any;
/**
* Gets database name to which this connection is made.
*/
db: string;
/**
* Connection used in this driver.
*/
connection: Connection;
/**
* Database name to which this connection is made.
*/
db: string;
/**
* Creates a query builder which can be used to build an sql queries.
*/
@ -44,27 +44,27 @@ export interface Driver {
disconnect(): Promise<void>;
/**
* Executes a given SQL query.
* Executes a given SQL query and returns raw database results.
*/
query<T>(query: string): Promise<T>;
/**
* Clears all tables in the currently connected database.
* Removes all tables from the currently connected database.
*/
clearDatabase(): Promise<void>;
/**
* Updates rows that match given conditions in the given table.
* Updates rows that match given simple conditions in the given table.
*/
update(tableName: string, valuesMap: Object, conditions: Object): Promise<void>;
/**
* Insert a new row into given table.
* Inserts a new row into given table.
*/
insert(tableName: string, valuesMap: Object): Promise<any>;
/**
* Insert a new row into given table.
* Performs a simple DELETE query by a given conditions in a given table.
*/
delete(tableName: string, conditions: Object): Promise<void>;

View File

@ -4,32 +4,53 @@ import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
import {QueryBuilder} from "../query-builder/QueryBuilder";
import {MysqlSchemaBuilder} from "../schema-builder/MysqlSchemaBuilder";
import {Connection} from "../connection/Connection";
import {ConnectionIsNotSetError} from "./error/ConnectionIsNotSetError";
import {BaseDriver} from "./BaseDriver";
/**
* This driver organizes work with mysql database.
*/
export class MysqlDriver implements Driver {
export class MysqlDriver extends BaseDriver implements Driver {
// -------------------------------------------------------------------------
// Properties
// Public Properties
// -------------------------------------------------------------------------
/**
* Connection used in this driver.
*/
connection: Connection;
private mysql: any;
private mysqlConnection: any;
private connectionOptions: ConnectionOptions;
// -------------------------------------------------------------------------
// Private Properties
// -------------------------------------------------------------------------
/**
* Mysql library.
*/
private mysql: any;
/**
* Connection to mysql database.
*/
private mysqlConnection: any;
// -------------------------------------------------------------------------
// Getter Methods
// -------------------------------------------------------------------------
/**
* Access to the native implementation of the database.
*/
get native(): any {
return this.mysql;
}
/**
* Database name to which this connection is made.
*/
get db(): string {
return this.connectionOptions.database;
return this.connection.options.database;
}
// -------------------------------------------------------------------------
@ -37,6 +58,7 @@ export class MysqlDriver implements Driver {
// -------------------------------------------------------------------------
constructor(mysql: any) {
super();
this.mysql = mysql;
}
@ -62,14 +84,15 @@ export class MysqlDriver implements Driver {
* Performs connection to the database based on given connection options.
*/
connect(options: ConnectionOptions): Promise<void> {
this.connectionOptions = options;
this.mysqlConnection = this.mysql.createConnection({
host: options.host,
user: options.username,
password: options.password,
database: options.database
});
return new Promise<void>((ok, fail) => this.mysqlConnection.connect((err: any) => err ? fail(err) : ok()));
return new Promise<void>((ok, fail) => {
this.mysqlConnection.connect((err: any) => err ? fail(err) : ok());
});
}
/**
@ -77,7 +100,7 @@ export class MysqlDriver implements Driver {
*/
disconnect(): Promise<void> {
if (!this.mysqlConnection)
throw new Error("Connection is not established, cannot disconnect.");
throw new ConnectionIsNotSetError("mysql");
return new Promise<void>((ok, fail) => {
this.mysqlConnection.end((err: any) => err ? fail(err) : ok());
@ -88,15 +111,18 @@ export class MysqlDriver implements Driver {
* Executes a given SQL query.
*/
query<T>(query: string): Promise<T> {
if (!this.mysqlConnection) throw new Error("Connection is not established, cannot execute a query.");
// console.info("executing:", query);
if (!this.mysqlConnection)
throw new ConnectionIsNotSetError("mysql");
this.logQuery(query);
return new Promise<any>((ok, fail) => this.mysqlConnection.query(query, (err: any, result: any) => {
if (err) {
console.error("query failed: ", query);
this.logFailedQuery(query);
this.logQueryError(err);
fail(err);
return;
} else {
ok(result);
}
ok(result);
}));
}
@ -104,21 +130,18 @@ export class MysqlDriver implements Driver {
* Clears all tables in the currently connected database.
*/
clearDatabase(): Promise<void> {
if (!this.mysqlConnection) throw new Error("Connection is not established, cannot execute a query.");
if (!this.mysqlConnection)
throw new ConnectionIsNotSetError("mysql");
// todo: optrize and make coder better
const query1 = `SET FOREIGN_KEY_CHECKS = 0;`;
const query2 = `SELECT concat('DROP TABLE IF EXISTS ', table_name, ';') AS q FROM information_schema.tables WHERE table_schema = '${this.connectionOptions.database}';`;
const query3 = `SET FOREIGN_KEY_CHECKS = 1;`;
const disableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 0;`;
const dropTablesQuery = `SELECT concat('DROP TABLE IF EXISTS ', table_name, ';') AS q FROM ` +
`information_schema.tables WHERE table_schema = '${this.db}';`;
const enableForeignKeysCheckQuery = `SET FOREIGN_KEY_CHECKS = 1;`;
return this.query(query1)
.then(() => this.query<any[]>(query2))
.then(results => {
const dropQueries = results.map(q => this.query(q['q']));
return Promise.all(dropQueries);
})
.then(() => this.query(query3))
return this.query(disableForeignKeysCheckQuery)
.then(() => this.query<any[]>(dropTablesQuery))
.then(results => Promise.all(results.map(q => this.query(q['q']))))
.then(() => this.query(enableForeignKeysCheckQuery))
.then(() => {});
}
@ -126,6 +149,9 @@ export class MysqlDriver implements Driver {
* Updates rows that match given conditions in the given table.
*/
update(tableName: string, valuesMap: Object, conditions: Object): Promise<void> {
if (!this.mysqlConnection)
throw new ConnectionIsNotSetError("mysql");
const qb = this.createQueryBuilder().update(tableName, valuesMap).from(tableName, "t");
Object.keys(conditions).forEach(key => qb.andWhere(key + "=:" + key, { [key]: (<any> conditions)[key] }));
return qb.execute().then(() => {});
@ -135,6 +161,9 @@ export class MysqlDriver implements Driver {
* Insert a new row into given table.
*/
insert(tableName: string, keyValues: Object): Promise<any> {
if (!this.mysqlConnection)
throw new ConnectionIsNotSetError("mysql");
const columns = Object.keys(keyValues).join(",");
const values = Object.keys(keyValues).map(key => (<any> keyValues)[key]).join(",");
const query = `INSERT INTO ${tableName}(${columns}) VALUES (${values})`;
@ -145,6 +174,9 @@ export class MysqlDriver implements Driver {
* Deletes from the given table by a given conditions.
*/
delete(tableName: string, conditions: Object): Promise<void> {
if (!this.mysqlConnection)
throw new ConnectionIsNotSetError("mysql");
const qb = this.createQueryBuilder().delete(tableName);
Object.keys(conditions).forEach(key => qb.andWhere(key + "=:" + key, { [key]: (<any> conditions)[key] }));
return qb.execute().then(() => {});

View File

@ -0,0 +1,9 @@
export class ConnectionIsNotSetError extends Error {
name = "ConnectionIsNotSetError";
constructor(dbType: string) {
super();
this.message = `Connection with ${dbType} database is not established. Check connection configuration.`;
}
}