UNPKG

dynamicsmobile

Version:

Allows development of off-line mobile and web business apps over the Dynamics Mobile platform. More info on https://www.dynamicsmobile.com

422 lines 20 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MobileDbQuery = void 0; const tslib_1 = require("tslib"); const dms_platform_bridge_factory_1 = require("../platform/dms-platform-bridge-factory"); const uuidv = tslib_1.__importStar(require("uuid")); const context_service_1 = require("../lib-core/context-service"); const tools_1 = require("../lib-core/tools"); const application_context_service_1 = require("../lib-core/application-context-service"); const dms_root_container_1 = require("../ioc/dms-root-container"); const db_query_1 = require("../lib-core/db-query"); const livelink_query_service_1 = require("../lib-core/livelink-query-service"); const mobile_sqlquery_service_1 = require("./mobile-sqlquery-service"); const livelinkquery_backendservice_1 = require("../lib-backendservice/livelinkquery-backendservice"); class MobileDbQuery extends db_query_1.DbQuery { constructor(_entityName, _entityTable) { super(); this._entityName = _entityName; this._entityTable = _entityTable; this.dms = dms_root_container_1.RootDIContainer.inject(application_context_service_1.DmsApplicationService); this._page = null; this._max = null; this._filter = null; this._fields = null; this._expand = null; this._group = null; this._aggregate = null; this._sort = null; this._appCode = this.dms ? this.dms.appCode : ''; if (typeof window === 'undefined') { this.q = new livelinkquery_backendservice_1.LiveLinkQueryBackendService(this.dms, livelink_query_service_1.appAreaServiceName, this._appCode, _entityName, _entityTable, _entityName, [], null, false); } else { this.q = null; } } _checkIfFuncWasUsed(methodName, testMember) { if (testMember != null) throw new Error("Method '" + methodName + "' was used already. Please review your code."); } _checkFunctionArgs(methodName, argName, argValue) { if (argValue == null) throw new Error("Method '" + methodName + "' requires argument '" + argName + "'"); } fields(fields) { if (this.q) { this.q.fields(fields); } else { this._checkIfFuncWasUsed("fields", this._fields); this._checkFunctionArgs("fields", "fields", fields); if (this._aggregate) throw Error("Method 'fields' can not be used together with method 'aggregate'"); if (this._group) throw Error("Method 'fields' can not be used together with method 'group'"); this._fields = fields; } return this; } filter(filterExpr) { if (this.q) { this.q.filter(filterExpr); } else { this._checkIfFuncWasUsed("where", this._filter); this._checkFunctionArgs("filter", "filterExpr", filterExpr); this._filter = filterExpr; } return this; } group(groupExpr) { if (this.q) { this.q.group(groupExpr); } else { this._checkIfFuncWasUsed("group", this._group); this._checkFunctionArgs("group", "groupExpr", groupExpr); if (this._fields) throw Error("Method 'group' can not be used together with method 'fields'"); this._group = groupExpr; } return this; } aggregate(aggregateExpr) { if (this.q) { this.q.aggregate(aggregateExpr); } else { this._checkIfFuncWasUsed("aggregate", this._aggregate); this._checkFunctionArgs("aggregate", "aggregateExpr", aggregateExpr); if (this._fields) throw Error("Method 'fields' can not be used together with method 'aggregate'"); this._aggregate = aggregateExpr; } return this; } ; sort(sortExpr) { if (this.q) { this.q.sort(sortExpr); } else { this._checkIfFuncWasUsed("sortExpr", this._sort); this._checkFunctionArgs("sort", "sortExrp", sortExpr); this._sort = sortExpr; } return this; } page(pageNo) { if (this.q) { this.q.page(pageNo); } else { this._checkIfFuncWasUsed("page", this._page); this._checkFunctionArgs("page", "pageNo", pageNo); this._page = pageNo; } return this; } limit(maxRecords) { if (this.q) { this.q.limit(maxRecords); } else { //this._checkIfFuncWasUsed("limit", this._max); this._checkFunctionArgs("limit", "maxRecords", maxRecords); this._max = maxRecords; } return this; } expand(expandExrp) { if (this.q) { this.q.expand(expandExrp); } else { this._checkIfFuncWasUsed("expand", this._expand); this._checkFunctionArgs("expand", "expandExrp", expandExrp); this._expand = expandExrp; } return this; } sqlOperatorsToODATAOperators(op) { //the spaces in-front and behind the ODATA operator are important return op.replace(/=/g, ' eq ').replace(/</g, ' lt ').replace(/>/g, ' gt ').replace(/<>/g, ' ne '); } executeSelect() { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (this.q) { return yield this.q.executeSelect(); } else { var whereClause = (this._filter ? ('WHERE ' + this._filter) : ''); var orderByClause = (this._sort ? ('ORDER BY ' + this._sort) : ''); var limitClause = (this._max ? ('limit ' + this._max) : ''); var joinClause = (this._expand ? (this._expand) : ''); var _sql = `SELECT ${this._fields ? this._fields.join(',') : '*'} FROM ${this._entityTable} ${joinClause} ${whereClause} ${orderByClause} ${limitClause}`; var result = yield (0, dms_platform_bridge_factory_1.PlatformBridgeFactory)(this.dms).execute("fetchsql", { query: _sql }); var actualResult = []; if (result && result.length > 0) { result.forEach(entity => { if (!entity.DMS_ROWID) entity.DMS_ROWID = uuidv.v4(); var ctor = context_service_1.ContextInstanceLoader.businessObjectTypesMap[this._entityName]; var newEntity = new ctor(); var finalEntity = Object.assign(newEntity, entity); finalEntity.members.forEach(function (member) { switch (member.dataType.toLowerCase()) { // case 'string': // if (finalEntity[member.name]) // finalEntity[member.name] = Tools.escapeStringForJson(finalEntity[member.name]) // break; case 'datetime': if (finalEntity[member.name]) { let d = finalEntity[member.name]; d = d.replace(/ /, 'T'); //iOS needs it finalEntity[member.name] = new Date(d); } break; case 'int32': case 'int64': if (finalEntity[member.name] || finalEntity[member.name] == '0') finalEntity[member.name] = parseInt(finalEntity[member.name]); break; case 'boolean': if (finalEntity[member.name] == 'true' || finalEntity[member.name] == '1') finalEntity[member.name] = true; else if (finalEntity[member.name] == 'false' || finalEntity[member.name] == '0') finalEntity[member.name] = false; break; case 'decimal': if (finalEntity[member.name] || finalEntity[member.name] == '0') finalEntity[member.name] = parseFloat(finalEntity[member.name]); break; } }); actualResult.push(finalEntity); }); } return actualResult; } }); } getEntityValueAsDbString(value, valueType) { if (!valueType) throw 'DbQuery.getEntityValueAsDbString requires argument valueType'; if (value == undefined || value == 'undefined' || value == 'null' || Number.isNaN(value)) { return "null"; } else if (valueType.toLowerCase() == 'binary') return `'${value.toString()}'`; else if (valueType.toLowerCase() == "string") { return "'" + value + "'"; } else if (valueType.toLowerCase() == "dateTime") { return "'" + value.toSqLiteFormat() + "'"; } else if (valueType.toLowerCase() == "double" || valueType.toLowerCase() == "int32" || valueType.toLowerCase() == "int64" || valueType.toLowerCase() == "decimal") { if (value.toString().toLowerCase() == "nan") return "null"; else return value.toString(); } else if (valueType.toLowerCase() == "boolean") { if (value == true) return "1"; else return "0"; } else if (valueType.toLowerCase() == "datetime" || valueType.toLowerCase() == "date") { return "'" + tools_1.Tools.formatDateToSqlite(value) + "'"; } else return value.toString(); } executeCreate(entity) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (this.q) { return this.q.executeCreate(entity); } else { var me = this; var fields = []; var values = []; if (!entity) throw 'DbQuery.executeCreate requires argument entity'; if (!entity.members || entity.members.length == 0) throw 'DbQuery.executeCreate requires argument entity.members to contain array of members'; entity.members.forEach(function (member) { if (!member.dataType) { throw 'DbQuery.entityCreate expects entity to have dataType member for member ' + member.name; } fields.push(member.name); if (member.name == 'DMS_ROWID') { if (!entity['DMS_ROWID']) entity['DMS_ROWID'] = uuidv.v4(); values.push(`'${entity['DMS_ROWID']}'`); } else { values.push(me.getEntityValueAsDbString(entity[member.name], member.dataType)); } }); entity['state'] = 1; // if (this.platformType == null) { // //cash the platform type for faster insert experience // const deviceService = RootDIContainer.inject(DeviceService); // this.platformType = deviceService.getPlatformType(); // } // if (this.platformType == PlatformType.Web) { // const q = new LiveLinkQueryAppArea(this.dms, appAreaServiceName, this.dms.appCode, this._entityName, this._entityTable, this._entityName, [], null, true); // return await q.executeCreate(entity) as any; // } // else { var actualSql = `INSERT INTO ${this._entityTable}(${fields.join(',')})VALUES(${values.join(',')})`; const r = yield (0, dms_platform_bridge_factory_1.PlatformBridgeFactory)(this.dms).execute("execsql", { query: actualSql }); return r; } } }); } executeUpdate(entity) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (this.q) { return this.q.executeUpdate(entity); } else { var me = this; var values = []; entity.members.forEach(function (member) { if (!member.dataType) { throw 'DbQuery.executeUpdate expects entity to have dataType for property ' + member.name; } if (member.name != 'DMS_ROWID') values.push(`${member.name}=${me.getEntityValueAsDbString(entity[member.name], member.dataType)}`); }); entity['state'] = 2; // if (this.platformType == null) { // //cash the platform type for faster insert experience // const deviceService = RootDIContainer.inject(DeviceService); // this.platformType = deviceService.getPlatformType(); // } // if (this.platformType == PlatformType.Web) { // const q = new LiveLinkQueryAppArea(this.dms, appAreaServiceName, this.dms.appCode, this._entityName, this._entityTable, this._entityName, [], null, true); // return await q.executeUpdate(entity) as any; // } // else { var actualSql = `UPDATE ${this._entityTable} SET ${values.join(',')} WHERE DMS_ROWID='${entity['DMS_ROWID']}'`; yield (0, dms_platform_bridge_factory_1.PlatformBridgeFactory)(this.dms).execute("execsql", { query: actualSql }); } } }); } executeDelete(entity) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (this.q) { return this.q.executeDelete(entity); } else { var me = this; var values = []; entity['state'] = 3; // if (this.platformType == null) { // //cash the platform type for faster insert experience // const deviceService = RootDIContainer.inject(DeviceService); // this.platformType = deviceService.getPlatformType(); // } // if (this.platformType == PlatformType.Web) { // const q = new LiveLinkQueryAppArea(this.dms, appAreaServiceName, this.dms.appCode, this._entityName, this._entityTable, this._entityName, [], null, true); // await q.executeDelete({ DMS_ROWID: entity.DMS_ROWID } as any) as any; // } // else { var actualSql = `DELETE FROM ${this._entityTable} WHERE DMS_ROWID='${entity.DMS_ROWID}'`; yield (0, dms_platform_bridge_factory_1.PlatformBridgeFactory)(this.dms).execute("execsql", { query: actualSql }); } } }); } static mapPropTypeToSqlType(prop) { switch (prop.dataType.toLowerCase()) { case 'int32': return 'INTEGER '; case 'int64': return 'INTEGER '; case 'float': return 'INTEGER '; case 'decimal': return 'REAL '; case 'date': return 'DATETIME '; case 'datetime': return 'DATETIME '; default: return 'nchar '; } } static createTable(db, entity) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const propSql = []; for (let i = 0; i < entity.members.length; i++) { const prop = entity.members[i]; propSql.push(`${prop.name} ${MobileDbQuery.mapPropTypeToSqlType(prop)}`); } const sql = `CREATE TABLE ${MobileDbQuery.getEntityTableName(entity)} (${propSql.join(',')})`; yield db.execute(sql); }); } static getEntityTableName(entity) { const dms = dms_root_container_1.RootDIContainer.inject(application_context_service_1.DmsApplicationService); return entity.tableName ? entity.tableName : dms.appCode.toUpperCase() + '_' + entity.name; } static upgradeDatabaseShema() { return tslib_1.__awaiter(this, void 0, void 0, function* () { //adds missing tables and missing fields in the local mobile database //by comparing the current database with the mobil const db = dms_root_container_1.RootDIContainer.inject(mobile_sqlquery_service_1.MobileSqlQueryService); let dbSchema = yield db.execute(`SELECT name,sql FROM sqlite_master WHERE type='table'`); for (let i = 0; i < dbSchema.length; i++) { dbSchema[i].members = dbSchema[i].sql.split('(')[1].split(',').map(r => { const s = r.trim().split(' '); //separate member name and type return { name: s[0].trim(), dataType: s[1].trim() }; }); } const schema = context_service_1.ContextInstanceLoader.businessObjectTypesMap; const entityNames = Object.getOwnPropertyNames(context_service_1.ContextInstanceLoader.businessObjectTypesMap); if (entityNames.length == 0) { throw new Error("Method MobileDbQuery.upgradeDatabaseSchema requires clause import from '@dms-bo' in the ts file"); } for (let i = 0; i < entityNames.length; i++) { const entity = schema[entityNames[i]]; if (entityNames[i] != 'modelGrammar' && typeof (entity) == 'object' && entity.members && entity.members.length > 0) { const tableExists = dbSchema.find(v => { const r = v.name == MobileDbQuery.getEntityTableName(entity); return r; }); if (!tableExists) { MobileDbQuery.createTable(db, entity); } } } //add missing fields for (let i = 0; i < entityNames.length; i++) { const entity = schema[entityNames[i]]; if (entityNames[i] != 'modelGrammar' && typeof (entity) == 'object' && entity.members && entity.members.length > 0) { const tbl = dbSchema.find(v => { const r = (v.name == MobileDbQuery.getEntityTableName(entity)); return r; }); if (tbl) { for (let k = 0; k < entity.members.length; k++) { const fieldFound = tbl.members.find(tblMember => { return tblMember.name == entity.members[k].name; }); if (!fieldFound) { yield db.execute(`ALTER TABLE ${MobileDbQuery.getEntityTableName(entity)} add column ${entity.members[k].name} ${MobileDbQuery.mapPropTypeToSqlType(entity.members[k])}`); } } } else { //console.log('oops ' +entity.name); } } } }); } } exports.MobileDbQuery = MobileDbQuery; //# sourceMappingURL=mobile-db-query.js.map