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