UNPKG

ionic-database-builder

Version:

Extended library from database-builder to assist in creating and maintaining SQL commands. Allowing integrate execute commands with SQLite ('@ionic-native/sqlite'), Web Sql, etc. Through the interface injection 'DatabaseCreatorContract' returning an imple

681 lines (660 loc) 25.1 kB
import { InjectionToken, Injectable, Inject, Injector, Optional, NgModule, SkipSelf } from '@angular/core'; import { Observable, from, of } from 'rxjs'; import { __awaiter } from 'tslib'; import { DatabaseBuilderError, Crud, ExecutableBuilder, Query, Ddl, DatabaseHelper, forkJoinSafe, WebSqlDatabaseAdapter } from 'database-builder'; import { mergeMap } from 'rxjs/operators'; import * as momentNs from 'moment'; class DatabaseFactoryContract { } const IS_AVAILABLE_DATABASE = new InjectionToken('is_available'); const IS_ENABLE_LOG = new InjectionToken('is_enable_log'); const DATABASE_CREATOR = new InjectionToken('database_creator'); const DATABASE_MIGRATION = new InjectionToken('database_migration'); const PLATFORM_LOAD = new InjectionToken('platform_load'); class DatabaseFactoryDefault extends DatabaseFactoryContract { constructor(_isAvailable, _databaseCreator) { super(); this._isAvailable = _isAvailable; this._databaseCreator = _databaseCreator; } database(databaseName) { return new Observable((observer) => { if (this._isAvailable) { this._databaseCreator.create({ name: databaseName, location: 'default' }) .then(database => { observer.next(database); observer.complete(); }) .catch(err => { observer.error(err); observer.complete(); }); } else { observer.next(void 0); observer.complete(); } }); } } DatabaseFactoryDefault.decorators = [ { type: Injectable } ]; DatabaseFactoryDefault.ctorParameters = () => [ { type: Boolean, decorators: [{ type: Inject, args: [IS_AVAILABLE_DATABASE,] }] }, { type: undefined, decorators: [{ type: Inject, args: [DATABASE_CREATOR,] }] } ]; class DatabaseManager { constructor(databaseFactory, _platformLoad) { this.databaseFactory = databaseFactory; this._platformLoad = _platformLoad; this._databases = new Map(); } cleanDatabaseName(name) { return name.replace(/([^a-z0-9]+)/gi, '-'); } addDatabaseNameExtension(databaseName) { return `${databaseName}.db`; } databaseInstance(name, version) { const keyDatabaseName = name + version; return this._databases.has(keyDatabaseName) ? this._databases.get(keyDatabaseName) : this.setDatabase(keyDatabaseName, this.createDatabase(this.databaseNameFile(name), version)); } invalidateInstance() { this._databases = new Map(); } setDatabase(keyDatabaseName, promiseDatabase) { if (promiseDatabase) { return this._databases .set(keyDatabaseName, promiseDatabase) .get(keyDatabaseName); } throw new DatabaseBuilderError(`Connection with provider of database cannot be created!`); } createDatabase(name, version) { return new Promise((resolve, reject) => { this._platformLoad.ready() .then(() => { this.databaseFactory.database(name) .subscribe((database) => { this.migrationVersion(database, version) .subscribe(_ => { resolve(database); }, err => { reject(err); }); }, err => { this.catchException(err); reject(err); }); }) .catch(err => { this.catchException(err); reject(err); }); }); } catchException(e) { // tslint:disable-next-line:no-console console.error(e); } } class BuildableDatabaseManager extends DatabaseManager { constructor(databaseFactory, _databaseSettings, _injector, _mapper, platformLoad, enableLog = true) { super(databaseFactory, platformLoad); this._databaseSettings = _databaseSettings; this._injector = _injector; this._mapper = _mapper; this.enableLog = enableLog; } get mapper() { return this._mapper; } databaseInstance() { const database = super.databaseInstance(this.databaseName(), this.version()); if (!database) { throw new Error('SQLite not avaliable!'); } return database; } managedTransaction() { return from(this.databaseInstance()).pipe(mergeMap((database) => { if (!database.managedTransaction) { throw new DatabaseBuilderError('Managed Transaction not supported in current middleware!'); } return of(database.managedTransaction()); })); } // /** // * @deprecated Use managedTransaction() // */ // public newTransaction(successTransaction: () => void): Observable<DatabaseBaseTransaction> { // return new Observable((observer: Observer<DatabaseBaseTransaction>) => { // this.databaseInstance() // .then(database => { // database.transaction((result: DatabaseBaseTransaction) => { // observer.next(result); // observer.complete(); // }) // .then(x => { // successTransaction(); // }) // .catch(error => { // observer.error(error); // observer.complete(); // }); // }) // .catch(err => { // observer.error(err); // observer.complete(); // }); // }); // } // /** // * @deprecated Use managedTransaction() // */ // public transaction(successTransaction: () => void): Observable<Crud> { // return new Observable((observer: Observer<Crud>) => { // this.newTransaction(successTransaction) // .subscribe((transaction) => { // observer.next(new Crud({ database: transaction, getMapper: this._mapper, enableLog: this.enableLog })); // observer.complete(); // }, error => { // observer.error(error); // observer.complete(); // }); // }); // } /** * @deprecated Use managedTransaction() */ beginTransaction() { return new Observable((observer) => { this.sql('BEGIN TRANSACTION') .subscribe(r => { this.crud() .subscribe(crud => { observer.next(crud); observer.complete(); }, error => { observer.error(error); observer.complete(); }); }, error => { observer.error(error); observer.complete(); }); }); } /** * @deprecated Use managedTransaction() */ commitTransaction() { return new Observable((observer) => { this.sql('COMMIT') .subscribe(r => { observer.next(true); observer.complete(); }, error => { observer.error(error); observer.complete(); }); }); } /** * @deprecated Use managedTransaction() */ rollbackTransaction() { return new Observable((observer) => { this.sql('ROLLBACK') .subscribe(r => { observer.next(true); observer.complete(); }, error => { observer.error(error); observer.complete(); }); }); } crud() { return new Observable((observer) => { this.databaseInstance() .then((database) => __awaiter(this, void 0, void 0, function* () { observer.next(new Crud(yield this._databaseSettings.config(this._injector, database), { database, getMapper: this._mapper, enableLog: this.enableLog })); observer.complete(); })) .catch(error => { observer.error(error); observer.complete(); }); }); } sql(sql, params = []) { return new Observable((observer) => { this.databaseInstance() .then(database => { const executable = new ExecutableBuilder(this.enableLog); executable.execute([{ query: sql, params }], database) .subscribe((cursor) => { observer.next(cursor[0]); observer.complete(); }, err => { observer.error(err); observer.complete(); }); }) .catch(err => { observer.error(err); observer.complete(); }); }); } query(typeT, alias = void 0) { return new Observable((observer) => { this.databaseInstance() .then(database => { const that = this; observer.next(new Query(typeT, { alias, getMapper: (tKey) => { return that._mapper.get(tKey); }, mapperTable: this._mapper.get(typeT).mapperTable, database, enableLog: this.enableLog })); observer.complete(); }) .catch(error => { observer.error(error); observer.complete(); }); }); } ddl() { return new Observable((observer) => { this.databaseInstance() .then(database => { observer.next(new Ddl({ database, getMapper: this._mapper, enableLog: this.enableLog })); observer.complete(); }) .catch(error => { observer.error(error); observer.complete(); }); }); } } const moment = momentNs; class DatabaseMigrationBase { version(database, version) { return new Observable((observer) => { this.checkTableVersion(database) .subscribe(_ => { this.checkVersion(database, version) .subscribe((result) => { this.migration(database, result) .subscribe(r => { observer.next(r); observer.complete(); }, err => this.error(err, observer)); }, err => this.error(err, observer)); }, err => this.error(err, observer)); }); } error(error, observer) { // tslint:disable-next-line:no-console console.error(error); observer.error(error); observer.complete(); } checkTableVersion(database) { return new Observable((observer) => { // return new Promise<any>((resolve, reject) => { const scriptTableVersion = `CREATE TABLE IF NOT EXISTS MigrationVersion( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT , data INTEGER , version TEXT );`; database.executeSql(scriptTableVersion, {}) .then(result => { observer.next(result); observer.complete(); }, err => this.error(err, observer)); }); } checkVersion(database, newVersion) { return new Observable((observer) => { this.getVersion(database).subscribe((oldVersion) => { if (oldVersion > 0) { if (newVersion > oldVersion) { // tslint:disable-next-line:no-console console.info(`Version old: ${oldVersion}`); database.executeSql(`UPDATE MigrationVersion SET (data, version) = (?, ?);`, [moment().unix(), newVersion]) .then() .catch(err => this.error(err, observer)); } } else { database.executeSql(`INSERT INTO MigrationVersion (data, version) VALUES (?, ?)`, [moment().unix(), newVersion]) .then() .catch(err => this.error(err, observer)); } observer.next({ oldVersion, newVersion }); observer.complete(); }); }); } getVersion(database) { return new Observable((observer) => { database.executeSql(`SELECT * FROM MigrationVersion`, {}) .then((result) => { let version = 0; if (result.rows.length > 0) { version = Number.parseFloat(result.rows.item(0).version); } observer.next(version); observer.complete(); }) .catch(err => this.error(err, observer)); }); } migration(database, control) { return new Observable((observer) => { this.migrationExecute(database, control) .subscribe(result => { observer.next(result); observer.complete(); }, err => this.error(err, observer)); }); } } class DatabaseSettingsFactoryContract { } class PlatformLoad { } class PlatformLoadDefault extends PlatformLoad { ready() { return Promise.resolve(); } } PlatformLoadDefault.decorators = [ { type: Injectable } ]; class DatabaseSettingsFactoryDefault extends DatabaseSettingsFactoryContract { constructor(versionOrModel, databaseName, mapper) { super(); if (Number.isInteger(versionOrModel)) { this._model = { version: versionOrModel, databaseName, mapper }; } else { this._model = versionOrModel; } } databaseName(injector) { return this._model.databaseName; } version(injector) { return this._model.version; } mapper() { return this._model.mapper; } config(injector, database) { return Promise.resolve({ sqliteLimitVariables: 999 }); } } class DatabaseHelperService extends DatabaseHelper { } DatabaseHelperService.decorators = [ { type: Injectable } ]; class DatabaseMigrationContract { onStart() { } onFinish() { } onProgress() { } } class DatabaseMigration extends DatabaseMigrationBase { constructor(_injector, _databaseMigrationContract) { super(); this._injector = _injector; this._databaseMigrationContract = _databaseMigrationContract; // tslint:disable-next-line: deprecation this._settings = _injector.get(DatabaseSettingsFactoryContract); } reset(database) { // tslint:disable-next-line:no-console console.info('database reset'); const observablesWait = []; const mappers = this._settings.mapper(this._injector); // remove dados offline da versão anterior, pois o formato dos dados foi alterado de uma versão para a outra const ddl = new Ddl({ database, getMapper: mappers, enableLog: true }); mappers.forEachMapper((value, key) => { if (!value.readOnly) { observablesWait.push(ddl.drop(value.newable).execute()); observablesWait.push(ddl.create(value.newable).execute()); } }); return forkJoinSafe(observablesWait); } migrationExecute(database, version) { return new Observable((observer) => { let observablesNested = []; if (this._databaseMigrationContract) { this._databaseMigrationContract.onStart(); const toObservables = this._databaseMigrationContract.to(version, database, this._settings.mapper(this._injector), this); if (toObservables && toObservables.length > 0) { observablesNested = observablesNested.concat(toObservables); } } if (observablesNested.length === 0 && version.oldVersion < 1) { observablesNested.push(this.reset(database)); } if (observablesNested.length > 0) { this._databaseMigrationContract.onProgress(); } this.callNested(observablesNested, 0) .subscribe((result) => { observer.next(result); observer.complete(); }, (error) => { observer.error(error); observer.complete(); }, () => { this._databaseMigrationContract.onFinish(); }); }); } callNested(observablesNested, nextIndex) { return new Observable((observer) => { if (observablesNested.length > nextIndex) { observablesNested[nextIndex].subscribe((result) => { this.callNested(observablesNested, ++nextIndex).subscribe((_) => { observer.next(true); observer.complete(); }, (error) => { observer.error(error); observer.complete(); }); }); } else { observer.next(true); observer.complete(); } }); } } DatabaseMigration.decorators = [ { type: Injectable } ]; DatabaseMigration.ctorParameters = () => [ { type: Injector }, { type: DatabaseMigrationContract, decorators: [{ type: Optional }, { type: Inject, args: [DATABASE_MIGRATION,] }] } ]; class DatabaseMockService { create(config) { console.log('Database Fake! \\o/'); return new Promise((resolve, reject) => { resolve({ executeSql: (statement, params) => { this.executeFake(statement, params); return new Promise((executeSqlResolve, executeSqlReject) => { executeSqlResolve(this.resultFake()); }); }, transaction: (fn) => { return new Promise((executeSqlResolve, executeSqlReject) => { fn({ executeSql: (sql, values, success, error) => { this.executeFake(sql, values); success(void 0, this.resultFake()); }, }); executeSqlResolve(void 0); }); } }); }); } executeFake(sql, params) { console.log(`Fake - sql: ${sql}, params: ${JSON.stringify(params)}`); } resultFake() { return { rows: { length: 20, item: (index) => { return { index }; } } }; } } DatabaseMockService.decorators = [ { type: Injectable } ]; class Database extends BuildableDatabaseManager { constructor(_isAvailable, isEnableLog, databaseSettings, injector, databaseFactory, _databaseMigration, platformLoad) { super(databaseFactory, databaseSettings, injector, databaseSettings.mapper(injector), platformLoad, isEnableLog); this._isAvailable = _isAvailable; this._databaseMigration = _databaseMigration; } migrationVersion(database, version) { if (this._isAvailable) { return this._databaseMigration.version(database, version); } return new Observable((observer) => { observer.next(true); observer.complete(); }); } databaseName() { return this._databaseSettings.databaseName(this._injector); } version() { return this._databaseSettings.version(this._injector); } databaseNameFile(databaseName = this.databaseName()) { return this.addDatabaseNameExtension(this.cleanDatabaseName(databaseName)); } } Database.decorators = [ { type: Injectable } ]; Database.ctorParameters = () => [ { type: Boolean, decorators: [{ type: Inject, args: [IS_AVAILABLE_DATABASE,] }] }, { type: Boolean, decorators: [{ type: Inject, args: [IS_ENABLE_LOG,] }] }, { type: DatabaseSettingsFactoryContract }, { type: Injector }, { type: DatabaseFactoryContract }, { type: DatabaseMigration }, { type: PlatformLoad, decorators: [{ type: Inject, args: [PLATFORM_LOAD,] }] } ]; class WebSqlDatabaseService extends WebSqlDatabaseAdapter { constructor() { super(window); } } WebSqlDatabaseService.decorators = [ { type: Injectable } ]; WebSqlDatabaseService.ctorParameters = () => []; class IonicDatabaseBuilderModule { constructor(parentModule) { if (parentModule) { throw new Error('IonicDatabaseBuilderModule is already loaded. Import it in the AppModule only'); } } static forSimple(isEnableLogProvider = false, isAvailableProvider = true, platformLoad = PlatformLoadDefault) { return { ngModule: IonicDatabaseBuilderModule, providers: [ { provide: IS_ENABLE_LOG, useValue: isEnableLogProvider }, { provide: IS_AVAILABLE_DATABASE, useValue: isAvailableProvider }, { provide: PLATFORM_LOAD, useClass: platformLoad }, ] }; } static forRoot(settingsProvider, databaseCreatorProvider, databaseMigrationContract, platformLoad = PlatformLoadDefault, isEnableLogProvider = false, isAvailableProvider = true) { return { ngModule: IonicDatabaseBuilderModule, providers: [ { provide: DatabaseSettingsFactoryContract, useClass: settingsProvider }, { provide: DATABASE_CREATOR, useClass: databaseCreatorProvider }, { provide: DATABASE_MIGRATION, useClass: databaseMigrationContract }, { provide: IS_ENABLE_LOG, useValue: isEnableLogProvider }, { provide: PLATFORM_LOAD, useClass: platformLoad }, { provide: IS_AVAILABLE_DATABASE, useValue: isAvailableProvider }, ] }; } } IonicDatabaseBuilderModule.decorators = [ { type: NgModule, args: [{ providers: [ DatabaseMigration, Database, DatabaseHelperService, { provide: DatabaseFactoryContract, useClass: DatabaseFactoryDefault }, { provide: PLATFORM_LOAD, useClass: PlatformLoadDefault } ] },] } ]; IonicDatabaseBuilderModule.ctorParameters = () => [ { type: IonicDatabaseBuilderModule, decorators: [{ type: Optional }, { type: SkipSelf }] } ]; /* * Public API Surface of ionic-database-builder */ /** * Generated bundle index. Do not edit. */ export { BuildableDatabaseManager, DATABASE_CREATOR, DATABASE_MIGRATION, Database, DatabaseFactoryContract, DatabaseFactoryDefault, DatabaseHelperService, DatabaseManager, DatabaseMigration, DatabaseMigrationBase, DatabaseMigrationContract, DatabaseMockService, DatabaseSettingsFactoryContract, DatabaseSettingsFactoryDefault, IS_AVAILABLE_DATABASE, IS_ENABLE_LOG, IonicDatabaseBuilderModule, PLATFORM_LOAD, PlatformLoad, PlatformLoadDefault, WebSqlDatabaseService }; //# sourceMappingURL=ionic-database-builder.js.map