@riao/dbal
Version:
319 lines • 10.8 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Database = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
const config_1 = require("../config");
const get_database_path_1 = require("./get-database-path");
const ddl_1 = require("../ddl");
const dml_1 = require("../dml");
const schema_query_repository_1 = require("../schema/schema-query-repository");
/**
* Represents a single database instance, including a driver,
* configuration, connection, etc.
*/
class Database {
constructor() {
/**
* Reconstructors will be used to re-initialize repositories
* after the database has been initialized.
*
* This allows repositories to be created in global scope
* before the database is init()'d
*/
this.queryRepoInitQueue = [];
this.ddlRepoInitQueue = [];
this.schemaRepoInitQueue = [];
this.isLoaded = false;
/**
* Migrations directory, relative to this database
* e.g. If the migrations are in `database/main/migrations`,
* set this to `migrations`
*/
this.migrations = 'migrations';
/**
* Seeds directory, relative to this database
* e.g. If the seeds are in `database/main/seeds`,
* set this to `seeds`
*/
this.seeds = 'seeds';
/**
* Schema storage directory, relative to this database
* e.g. If the schema is in `database/main/.schema`,
* set this to `.schema`
*/
this.schemaDirectory = '.schema';
/**
* Query builder class type used to create new query builders
*/
this.queryBuilderType = dml_1.DatabaseQueryBuilder;
/**
* Query repository class type used to create new repos
*/
this.queryRepositoryType = dml_1.QueryRepository;
/**
* DDL builder class type used to create new builders
*/
this.ddlBuilderType = ddl_1.DataDefinitionBuilder;
/**
* DDL repository class type used to create new repos
*/
this.ddlRepositoryType = ddl_1.DataDefinitionRepository;
/**
* Schema Query repository class type used to create new repos
*/
this.schemaQueryRepositoryType = schema_query_repository_1.SchemaQueryRepository;
}
/**
* Initialize the database
*
* @param options Database options
*/
init(options) {
return __awaiter(this, void 0, void 0, function* () {
options = options !== null && options !== void 0 ? options : {};
if (!this.name) {
throw new Error('Cannot load database without a name');
}
if (!this.databasePath) {
this.databasePath = (0, get_database_path_1.getDatabasePath)();
}
if (!this.driver) {
this.driver = new this.driverType();
}
if (options.connectionOptions) {
this.env = options.connectionOptions;
}
else {
this.configureFromEnv();
}
yield this.connect();
this.isLoaded = true;
// Load schema query repos
this.schemaQuery = this.getSchemaQueryRepository();
for (const repo of this.schemaRepoInitQueue) {
repo.init({
database: this.env.database,
driver: this.driver,
});
}
yield this.loadSchema();
// Load DDL repositories
this.ddl = this.getDataDefinitionRepository();
for (const repo of this.ddlRepoInitQueue) {
repo.init({
driver: this.driver,
});
}
// Load query repositories
this.query = this.getQueryRepository();
for (const repo of this.queryRepoInitQueue) {
repo.init({
driver: this.driver,
schema: this.schema,
});
}
});
}
/**
* Load the configuration .env
*/
configureFromEnv() {
this.env = (0, config_1.configureDb)(this.envType, this.databasePath, this.name);
}
/**
* Connect to the database
*/
connect() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.env) {
throw new Error(`Cannot connect() database "${this.name}" before init()`);
}
yield this.driver.connect(this.env);
});
}
/**
* Disconnect from the database
*/
disconnect() {
return __awaiter(this, void 0, void 0, function* () {
yield this.driver.disconnect();
});
}
/**
* Get the full relative path to this database's migrations folder
*
* @returns Returns the relative file path
*/
getMigrationsDirectory() {
return (0, path_1.join)(this.databasePath, this.name, this.migrations);
}
/**
* Get the full relative path to this database's seeds folder
*
* @returns Returns the relative file path
*/
getSeedsDirectory() {
return (0, path_1.join)(this.databasePath, this.name, this.seeds);
}
/**
* Get the full relative path to this database's schema folder
*
* @returns Returns the relative file path
*/
getSchemaDirectory() {
return (0, path_1.join)(this.databasePath, this.name, this.schemaDirectory);
}
/**
* Get a new DDL builder
*
* @returns DDL builder
*/
getDataDefinitionBuilder() {
return new this.ddlBuilderType();
}
/**
* Get a new DDL repository
*
* @param options Repository options
* @returns Returns the DDL repository
*/
getDataDefinitionRepository() {
const repo = new this.ddlRepositoryType({
ddlBuilderType: this.ddlBuilderType,
});
if (this.isLoaded) {
repo.init({ driver: this.driver });
}
else {
this.ddlRepoInitQueue.push(repo);
}
return repo;
}
/**
* Get a new query builder
*
* @returns Query builder
*/
getQueryBuilder() {
return new this.queryBuilderType();
}
/**
* Get a new query repository
*
* @param options Repository options
* @returns Returns the query repository
*/
getQueryRepository(options) {
const repo = new this.queryRepositoryType(Object.assign(Object.assign({}, (options !== null && options !== void 0 ? options : {})), { queryBuilderType: this.queryBuilderType }));
if (this.isLoaded) {
repo.init({
driver: this.driver,
schema: this.schema,
});
}
else {
this.queryRepoInitQueue.push(repo);
}
return repo;
}
/**
* Get a new schema query repository
*
* @returns Schema Query Repository
*/
getSchemaQueryRepository() {
const repo = new this.schemaQueryRepositoryType({
queryBuilderType: this.queryBuilderType,
});
if (this.isLoaded) {
repo.init({
database: this.env.database,
driver: this.driver,
});
}
else {
this.schemaRepoInitQueue.push(repo);
}
return repo;
}
/**
* Build & save the database schema
*/
buildSchema() {
return __awaiter(this, void 0, void 0, function* () {
this.schema = yield this.schemaQuery.getSchema();
yield this.saveSchema();
});
}
/**
* Save the database schema
*/
saveSchema() {
return __awaiter(this, void 0, void 0, function* () {
(0, fs_1.mkdirSync)(this.getSchemaDirectory(), { recursive: true });
const filepath = (0, path_1.join)(this.getSchemaDirectory(), 'schema.json');
const data = JSON.stringify(this.schema);
(0, fs_1.writeFileSync)(filepath, data);
});
}
/**
* Load the database schema
*/
loadSchema() {
return __awaiter(this, void 0, void 0, function* () {
const filepath = (0, path_1.join)(this.getSchemaDirectory(), 'schema.json');
if ((0, fs_1.existsSync)(filepath)) {
const data = (0, fs_1.readFileSync)(filepath).toString();
this.schema = JSON.parse(data);
}
else {
yield this.buildSchema();
}
});
}
/**
* Get schema metadata
*
* @returns Schema
*/
getSchema() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.schema) {
yield this.loadSchema();
}
return this.schema;
});
}
/**
* Run a transaction
*
* @param fn Transaction callback
* @returns Passes the return from the transaction callback
*/
transaction(fn) {
return __awaiter(this, void 0, void 0, function* () {
const connectionDriver = new this.driverType();
const ddl = this.getDataDefinitionRepository();
ddl.init({ driver: connectionDriver });
const query = this.getQueryRepository();
query.init({ driver: connectionDriver, schema: this.schema });
return yield this.driver.transaction(fn, {
driver: connectionDriver,
ddl,
query,
});
});
}
}
exports.Database = Database;
//# sourceMappingURL=database.js.map