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
JavaScript
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