@easyquery/enterprise
Version:
EasyQuery.JS Enterprise
1,230 lines (1,217 loc) • 45.7 kB
JavaScript
'use strict';
var core = require('@easyquery/core');
var core$1 = require('@easydata/core');
var ui = require('@easydata/ui');
const majVer = 7;
const minVer = 4;
const magics = [45, 128, 231];
Math.trunc = Math.trunc || function (x) {
if (isNaN(x)) {
return NaN;
}
if (x > 0) {
return Math.floor(x);
}
return Math.ceil(x);
};
const lcv = {
__kt: 0,
versionNum: '' + majVer + '.' + minVer,
ck: function (key) {
if (!key || !key.length) {
this.__kt = -3;
return;
}
try {
var part1 = key.slice(0, key.length - 12);
var infoBytes = _bs(part1);
var part2 = key.slice(key.length - 12);
let ism = false;
for (const magic of magics) {
var edc = t36(magic);
if (part2[0] === edc[0] && part2[2] === edc[1]) {
ism = true;
break;
}
}
if (!ism) {
lcv.__kt = -1;
}
var idx = minVer % 4;
var shift = majVer + minVer;
if (part2[6 + idx] != encChar(shift, 19)) {
lcv.__kt = -2;
return;
}
if (part2[1] != encChar(infoBytes[3])) {
return;
}
lcv.__kt = part2[3] != encChar(infoBytes[5]) ? 2 : 3;
if (lcv.__kt === 2) {
var eds = `${f36(part2.substring(4, 6) + part2.substring(10))}`;
var ed = new Date(2000 + Number.parseInt(eds.substring(0, 2)), Number.parseInt(eds.substring(2, 4)) - 1, Number.parseInt(eds.substring(4)), 0, 0, 0, 0);
if (Date.now() > ed.getTime()) {
lcv.__kt = 1;
}
}
}
catch (error) {
}
}
};
function encChar(x, b = 20) {
return String.fromCharCode(65 + x % b);
}
function _bs(str) {
var binary_string = urlatob(str);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes;
}
function urlatob(str) {
var s = str;
s = s.replace(/-/g, '+');
s = s.replace(/_/g, '/');
switch (s.length % 4) {
case 0:
break;
case 2:
s += "==";
break;
case 3:
s += "=";
break;
}
return window.atob(s);
}
const tokens = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
function t36(val) {
var result = "";
while (val > 0) {
result = tokens[val % tokens.length] + result;
val /= tokens.length;
}
return result;
}
function f36(val) {
var d = 0;
for (var i = 0; i < val.length; ++i)
d += tokens.indexOf(val[i]) * Math.pow(tokens.length, val.length - i - 1);
return d;
}
class ConditionEx extends core.Condition {
constructor() {
super(...arguments);
this.readOnly = false;
this.parameterized = false;
this.inJoin = false;
}
isReadOnly() {
return this.readOnly || (this.getParent() && this.getParent().isReadOnly());
}
setReadOnly(value) {
this.readOnly = value || (this.getParent() && this.getParent().isReadOnly());
this.conditions && this.conditions.forEach((cond) => {
cond.setReadOnly(value);
});
}
isParameterized() {
return this.parameterized;
}
setParameterized(value) {
this.parameterized = value;
}
isInJoin() {
return this.inJoin;
}
setInJoin(value) {
this.inJoin = value;
}
loadFromData(model, data) {
super.loadFromData(model, data);
if (lcv.__kt <= 1)
return;
if (typeof data.readOnly !== 'undefined') {
this.setReadOnly(data.readOnly);
}
if (typeof data.inJoin !== 'undefined') {
this.setInJoin(data.inJoin);
}
if (typeof data.parameterized !== 'undefined') {
this.setParameterized(data.parameterized);
}
//if condition group
//this.linkType = data.linking;
if (data.conds) {
for (let i = 0; i < data.conds.length; i++) {
let newCond = this.query.createCondition();
newCond.loadFromData(model, data.conds[i]);
this.conditions.push(newCond);
newCond.setParent(this);
}
}
}
saveToData() {
let obj = super.saveToData();
if (lcv.__kt <= 1)
return obj;
if (this.isReadOnly()) {
obj.readOnly = this.isReadOnly();
}
if (this.isParameterized()) {
obj.parameterized = this.isParameterized();
}
if (this.isInJoin()) {
obj.inJoin = this.isInJoin();
}
if (this.tag == core.CondTag.Group) {
//if condition group
//obj.linking = this.linkType;
obj.conds = [];
for (let i = 0; i < this.conditions.length; i++) {
obj.conds.push(this.conditions[i].saveToData());
}
}
return obj;
}
}
class QueryColumnEx extends core.QueryColumn {
constructor() {
super(...arguments);
this.readOnly = false;
}
isReadOnly() {
return this.readOnly;
}
setReadOnly(value) {
this.readOnly = value;
}
/**
* Loads column from its JSON representation object.
* @param model The Data Model.
* @param colData The JSON representation object.
*/
loadFromData(model, colData) {
super.loadFromData(model, colData);
if (lcv.__kt <= 2)
return;
if (colData) {
if (typeof colData.readOnly != 'undefined') {
this.readOnly = colData.readOnly;
}
}
}
saveToData() {
let colData = super.saveToData();
if (lcv.__kt <= 2)
return colData;
if (this.isReadOnly()) {
colData.readOnly = this.isReadOnly();
}
return colData;
}
}
class QueryEx extends core.Query {
constructor(model, options) {
super(model, null, options);
}
isEx() {
return lcv.__kt > 1;
}
createSubQuery() {
return new QueryEx(this.model, { context: this.context });
}
createCondition(tag = core.CondTag.Simple) {
if (lcv.__kt <= 1)
return super.createCondition(tag);
return new ConditionEx(this, tag);
}
createColumn(justsorted = false) {
if (lcv.__kt <= 1)
return super.createColumn(justsorted);
return new QueryColumnEx(this, justsorted);
}
/**
* Adds a condition group - a group of simple conditions (predicates) linked by AND or OR
* @param descriptor The descriptor of the new condition group.
* @returns The new search condition.
*/
addConditionGroup(descriptor, addChildCondition = true) {
if (lcv.__kt <= 1)
return super.addConditionGroup(descriptor, addChildCondition);
let parent = descriptor.parent || this.getRootCondition();
let lType = descriptor.linking || (parent.linkType === core.LinkType.All ? core.LinkType.Any : core.LinkType.All);
let group = this.createCondition(core.CondTag.Group);
group.linkType = lType;
if (addChildCondition) {
let model = this.getModel();
let attr = model.getFirstUICAttr();
if (attr) {
let op = model.getDefaultOperatorForAttr(attr);
let cond = this.createSimpleConditionObject(attr, op, "");
group.addCondition(cond);
}
}
parent.addCondition(group);
return group;
}
addExtraConditionGroup(descriptor, addChildCondition = true) {
descriptor.parent = descriptor.parent || this.extraConditions;
if (lcv.__kt <= 1)
return super.addExtraConditionGroup(descriptor, addChildCondition);
return this.addConditionGroup(descriptor);
}
buildQueryPath() {
const model = this.getModel();
if (lcv.__kt <= 1)
return this.buildQueryPath();
if (model.getMainEntity())
return this.buildQueryPath();
const entities = this.getEntitiesInQuery();
if (entities.length == 0) {
throw Error("Cannon build path. Path is empty");
}
let tree = new core.Tree(entities[0]);
for (let i = 1; i < entities.length; i++) {
const entity = entities[i];
if (tree.contains(entity)) {
continue;
}
let path = this.findPath(tree.value, entity);
if (path != null) {
//Add path to tree
tree = this.addPathToTree(tree, (path[0] === tree.value) ? path.slice(1) : path);
}
else {
throw Error("Unable to build query. Cannot build path.");
}
}
tree.setParents();
return tree;
}
addPathToTree(tree, path) {
if (path.length == 0) {
return;
}
let pathAdded = false;
for (let child of tree.childs) {
if (child.value === path[0]) {
pathAdded = true;
if (path.length > 1)
child = this.addPathToTree(child, path.slice(1));
break;
}
}
if (!pathAdded) {
let link = this.getModel().findLink(tree.value, path[0]);
if (link) {
let newNode = new core.Tree(path[0]);
tree.addChild(newNode);
if (path.length > 1)
newNode = this.addPathToTree(newNode, path.slice(1));
}
else if (!tree.parent) {
let node = new core.Tree(tree);
tree = new core.Tree(path[0]);
tree.addChild(node);
if (path.length > 1)
tree = this.addPathToTree(tree, path.slice(1));
}
else {
throw Error("Unable to build query. Cannot build path.");
}
}
return tree;
}
findPath(entityFrom, entityTo) {
let curPath = [];
let curStep = [];
let nextStep = [];
let passedEntities = [];
let pathFound = false;
curPath.push(entityFrom);
curStep.push(curPath);
passedEntities.push(entityFrom);
while (!pathFound) {
nextStep = [];
for (let path of curStep) {
pathFound = this.checkPath(path, entityTo, nextStep, passedEntities);
if (pathFound) {
path.push(entityTo);
curPath = path;
break;
}
}
curStep = [];
if (!pathFound) {
if (nextStep.length == 0)
return null;
//copy nextStep to curStep
for (let path of nextStep)
curStep.push(path);
}
}
return curPath;
}
checkPath(path, entityTo, nextStep, passedEntities) {
const endPoint = path[path.length - 1];
const entityLinks = this.getModel().getLinksByEntity(endPoint);
for (let link of entityLinks) {
let entity2 = null;
if (link.entityFrom == endPoint) {
entity2 = link.entityTo;
}
else {
entity2 = link.entityFrom;
}
if (entity2 == entityTo) { //if reach the destination
nextStep = [];
return true;
}
//if destination is not reached yet we add current node (entity2) to the path and proceed
if (path.indexOf(entity2) < 0 && passedEntities.indexOf(entity2) < 0) { //to prevent cycling
passedEntities.push(entity2);
let newPath = new Array();
newPath = newPath.concat(path);
newPath.push(entity2);
nextStep.push(newPath);
}
}
return false;
}
}
class EqServerQueryStorage {
constructor(context) {
this.context = context;
}
init() {
}
newQuery(options) {
options = options || {};
const query = options.query || this.context.getQuery();
const model = this.context.getModel();
const modelId = options.modelId || (model ? model.getId() : "");
if (options.queryId) {
query.setId(options.queryId);
}
if (options.name) {
query.setName(options.name);
}
if (options.description) {
query.setDescription(options.description);
}
let requestData = {
'query': query.toJSONData()
};
if (options.data) {
requestData['data'] = options.data;
}
const url = this.context.resolveEndpoint('NewQuery', { modelId: modelId });
const http = this.context.getServices().getHttpClient();
return http.post(url, requestData)
.then((responseData) => {
return responseData.query;
});
}
getQueryList(options) {
options = options || {};
const modelId = options.modelId || this.context.getModel().getId();
const url = this.context.resolveEndpoint('GetQueryList', { modelId: modelId });
const http = this.context.getServices().getHttpClient();
return http.get(url)
.then((responseData) => {
if (!responseData.queries) {
return Promise.reject({
message: 'Wrong response format'
});
}
return responseData.queries;
});
}
loadQuery(options) {
options = options || {};
const model = this.context.getModel();
const query = this.context.getQuery();
const modelId = options.modelId || model.getId();
const queryId = options.queryId || query.getId();
const url = this.context.resolveEndpoint('GetQuery', { modelId: modelId, queryId: queryId });
const http = this.context.getServices().getHttpClient();
return http.get(url)
.then((responseData) => {
return responseData.query;
});
}
saveQuery(options) {
options = options || {};
const query = options.query || this.context.getQuery();
const queryId = options.queryId || query.getId();
if (options.queryId) {
query.setId(options.queryId);
}
const modelId = options.modelId || query.getModel().getId();
if (options.queryId) {
query.setId(options.queryId);
}
let requestData = {
'query': query.toJSONData()
};
if (options.data) {
requestData['data'] = options.data;
}
const url = this.context.resolveEndpoint('SaveQuery', { modelId: modelId, queryId: queryId });
const http = this.context.getServices().getHttpClient();
return http.put(url, requestData)
.then((responseData) => {
return responseData.query;
});
}
removeQuery(options) {
options = options || {};
const context = this.context;
const query = context.getQuery();
const modelId = options.modelId || query.getModel().getId();
const queryId = options.queryId || query.getId();
let requestData = {
'modelId': modelId,
'queryId': queryId
};
if (options.data) {
requestData['data'] = options.data;
}
const url = this.context.resolveEndpoint('RemoveQuery', { modelId: modelId, queryId: queryId });
const http = this.context.getServices().getHttpClient();
return http.delete(url, requestData).getPromise();
}
}
class DataModelEx extends core.DataModel {
}
class DataTableAggregatesCalculator {
constructor(context) {
this.context = context;
//stores current totals by level (group) number
this.levelsTotals = [];
this.prevRow = null;
this.aggrContainer = new core.EqAggregatesContainer(context);
}
getAggrContainer() {
return this.aggrContainer;
}
initObjects() {
this.aggrSettings = this.context.getQuery().getAggregationSettings();
this.groups = this.aggrSettings.getGroups();
this.aggregates = this.aggrSettings.getAggregates();
this.aggrColIds = this.aggrSettings.getAggregates().map(a => a.colId);
this.aggrCols = this.context.resultTable.columns.getItems()
.filter(col => this.aggrColIds.indexOf(col.id) >= 0);
this.levelsTotals = [];
this.prevRow = null;
}
createColumnAggregatesObject() {
return {
sum: 0,
min: Number.MAX_VALUE,
max: Number.MIN_VALUE
};
}
calculate(options) {
this.initObjects();
this.aggrContainer.clear();
options = options || {};
options.maxLevel = options.maxLevel >= 0
? options.maxLevel : 0;
var levelNumber = this.groups.length + 1; //number of groups plus grand totals
for (let levelIndex = 0; levelIndex < levelNumber; levelIndex++) {
let levelTotals = { count: 0, columns: {} };
this.resetLevelTotals(levelTotals);
this.levelsTotals.push(levelTotals);
}
const allRows = this.context.resultTable.getCachedRows();
if (allRows.length > 0) {
for (const row of allRows) {
this.processDataRow(row);
}
//flusing the totals for all group levels
for (let levelIndex = 1; levelIndex < levelNumber; levelIndex++) {
this.flushLevelTotals(levelIndex);
}
//flusing the grand totals (if they are turned on)
if (this.aggrSettings.hasGrandTotals()) {
this.flushLevelTotals(0);
}
}
return Promise.resolve();
}
resetLevelTotals(rowTotals) {
for (const aggrCol of this.aggrCols) {
rowTotals.columns[aggrCol.id] = this.createColumnAggregatesObject();
}
rowTotals.count = 0;
}
processDataRow(row) {
const levelIndexChanged = this.checkLevelChange(row);
if (levelIndexChanged >= 0) {
for (let levelIndex = levelIndexChanged; levelIndex < this.levelsTotals.length; levelIndex++) {
this.flushLevelTotals(levelIndex);
}
}
if (this.aggrSettings.hasGrandTotals()) {
this.updateLevelTotals(0, row);
}
let levelIndex = 1;
for (const group of this.groups) {
this.updateLevelTotals(levelIndex, row);
levelIndex++;
}
this.prevRow = row;
}
/** Checks if the values in group columns were changed
and return the level number they were */
checkLevelChange(row) {
if (this.prevRow == null)
return -1;
for (let groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
var group = this.groups[groupIndex];
for (const colId of group.columns) {
const value = row.getValue(colId);
const prevValue = this.prevRow.getValue(colId);
if (!this.aggrSettings.compareValues(prevValue, value)) {
return groupIndex + 1;
}
}
}
return -1;
}
/** Saves the current values in levelData for the specified level to AggregateContainer
and then reset the data row for that level
*/
flushLevelTotals(levelIndex) {
let levelTotals = this.levelsTotals[levelIndex];
const group = levelIndex > 0 ? this.groups[levelIndex - 1] : null;
let groupKey = this.aggrSettings.buildGroupKey(group, this.prevRow);
var groupTotals = {};
for (const aggr of this.aggregates) {
const columnTotals = levelTotals.columns[aggr.colId];
groupTotals[aggr.colId] = this.applyAggrFunc(aggr.funcId, columnTotals, levelTotals);
}
if (this.aggrSettings.hasRecordCount()) {
groupTotals[this.aggrSettings.COUNT_FIELD_NAME] = levelTotals.count;
}
this.aggrContainer.updateAggregateData(levelIndex, groupKey, groupTotals);
this.resetLevelTotals(levelTotals);
}
applyAggrFunc(funcId, columnTotals, levelTotals) {
switch (funcId) {
case "SUM":
return columnTotals.sum;
case "AVG":
return columnTotals.sum / levelTotals.count;
case "COUNT":
case "CNTDST":
return levelTotals.count;
case "MIN":
return columnTotals.min;
case "MAX":
return columnTotals.max;
}
}
/** Updates the totals by values in the current DataRow
* and according to the specified aggregate
*/
updateLevelTotals(levelIndex, row) {
const levelTotals = this.levelsTotals[levelIndex];
levelTotals.count += 1;
for (const aggr of this.aggregates) {
const value = row.getValue(aggr.colId);
const columnTotals = levelTotals.columns[aggr.colId];
columnTotals.sum += value;
if (value < columnTotals.min) {
columnTotals.min = value;
}
if (value > columnTotals.max) {
columnTotals.max = value;
}
}
}
needRecalculation() {
return true;
}
reset() {
}
}
function strIsEmpty(str) {
if (str) {
return str.trim() === '';
}
else
return true;
}
const baseLicApiUrl = 'https://account.korzh.com/api/license';
const eqVersion = lcv.versionNum;
class LCDialog {
constructor(context) {
this.http = new core$1.HttpClient();
this.context = context;
}
show() {
const dialogService = new ui.DefaultDialogService();
this.dialogSet = dialogService.createSet([
{
closable: false,
cancelable: false,
submitOnEnter: true,
title: 'No license key for EasyQuery',
body: this.buildStartPage(),
submitButtonText: 'Submit',
onInput: this.validateForm.bind(this),
onSubmit: this.startPageOnSubmit.bind(this)
},
{
closable: false,
cancelable: false,
submitOnEnter: true,
title: 'Please check your inbox',
body: this.buildCodePage(),
submitButtonText: 'Get License Key',
onInput: this.validateForm.bind(this),
onSubmit: this.codePageOnSubmit.bind(this)
},
{
closable: false,
cancelable: false,
submitable: false,
title: 'Success',
body: this.buildSuccessPage()
},
{
closable: false,
cancelable: false,
submitable: false,
title: 'Failure',
body: this.buildFailurePage()
},
]);
const dialog1 = this.dialogSet.open(0);
setTimeout(() => {
this.validateForm(dialog1);
const emailInput = document.getElementById('eqAuthEmail');
if (emailInput) {
emailInput.focus();
}
}, 200);
}
isValidForm(form) {
const emailInput = form.querySelector('#eqAuthEmail'); //form.querySelector('[name="email"]') as HTMLInputElement;
if (emailInput) {
return !strIsEmpty(emailInput.value) &&
emailInput.value
.toLowerCase()
.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
}
const codeInput = form.querySelector('#eqAuthCode'); //form.querySelector('[name="code"]') as HTMLInputElement;
if (codeInput) {
return !strIsEmpty(codeInput.value) &&
!isNaN(+codeInput.value) &&
codeInput.value == codeInput.value.trim() &&
codeInput.value.length === 6;
}
return true;
}
validateForm(dialog) {
const submitButton = dialog.getSubmitButtonElement();
submitButton.disabled = !this.isValidForm(dialog.getRootElement());
}
addInputField(parentBuilder, inputOptions) {
parentBuilder
.addChild('label', b => b
.attr('for', inputOptions.id)
.addHtml(`${inputOptions.label} ${inputOptions.required ? '<sup style="color: red">*</sup>' : ''}: `))
.addChild('input', b => {
b.id(inputOptions.id);
b.name(inputOptions.name || inputOptions.id);
b.type(inputOptions.type || 'text');
if (typeof (inputOptions.value) !== 'undefined') {
b.value(inputOptions.value);
}
if (inputOptions.onInput) {
b.on('input', inputOptions.onInput);
}
});
}
buildStartPage() {
let form;
let controlsPanelBuilder;
const formBuilder = ui.domel('div');
formBuilder.addChild('div', b => b
.html('<div style="font-size:1.2em">The EasyQuery license key is either absent, invalid or was issued for a different version of the library.</div>' +
'<div style="font-size:1.2em">Please fill out the form to obtain a valid trial license key.</div>'));
formBuilder
.addClass('kfrm-form')
.addChild('div', b => {
controlsPanelBuilder = b;
b.addClass('kfrm-fields label-above');
b.addClass('kfrm-break-20');
});
this.addInputField(controlsPanelBuilder, {
id: 'eqAuthEmail',
name: 'email',
label: 'Email',
required: true
});
this.addInputField(controlsPanelBuilder, {
id: 'eqAuthName',
name: 'contactName',
label: 'Name (optional)',
required: false
});
formBuilder.addChild('div', b => b
.html('<div style="margin-top:20px;font-size:0.9em">* By clicking Submit, you agree with Korzh.com <a href="https://korzh.com/terms-of-use">Terms of use</a>' +
' and <a href="https://korzh.com/privacy">Privacy policy</a>.</div>' +
'<div style="font-size:0.9em">You also agree to receive email messages from Korzh.com. This consent may be revoked at any time.</div>'));
form = formBuilder.toDOM();
return form;
}
buildCodePage() {
let form;
let controlsPanelBuilder;
const formBuilder = ui.domel('div');
formBuilder.addChild('div', b => b
.html('<div style="font-size:1.2em">We sent a confirmation code to <strong>{{email}}</strong>.</div>' +
'<div style="font-size:1.2em">Please find it in the email and enter to the text box below</div>'));
formBuilder
.addClass('kfrm-form')
.addChild('div', b => {
controlsPanelBuilder = b;
b.addClass('kfrm-fields label-above');
b.addClass('kfrm-break-20');
});
this.addInputField(controlsPanelBuilder, {
id: 'eqAuthCode',
name: 'code',
label: 'Confirmation code',
required: true
});
formBuilder.addChild('div', b => b
.html('<div style="margin-top:20px;font-size:0.9em">NB: Don\'t forget to check your SPAM folder ' +
'if the message does not arrive within the next 5 minutes, and mark it as "Not Spam" if it\'s found there.</div>'));
form = formBuilder.toDOM();
return form.outerHTML;
}
buildSuccessPage() {
let form;
const formBuilder = ui.domel('div');
formBuilder.addChild('div', b => b
.html('<div style="font-size:1.2em">You have successfully completed the registration.</div>' + '{{message}}'));
form = formBuilder.toDOM();
return form.outerHTML;
}
buildFailurePage() {
let form;
const formBuilder = ui.domel('div');
formBuilder.addChild('div', b => b
.html('{{message}}'));
form = formBuilder.toDOM();
return form.outerHTML;
}
startPageOnSubmit(dlg) {
const emailInput = document.getElementById('eqAuthEmail');
const nameInput = document.getElementById('eqAuthName');
this.authEmail = emailInput.value;
this.authName = nameInput.value;
dlg.disableButtons();
this.http.post(core.equtils.combinePath(baseLicApiUrl, 'get-code'), {
email: this.authEmail,
name: this.authName,
data: {
ptag: this.context.backendInfo.type,
apptype: this.context.backendInfo.subType,
}
}, { dataType: 'json' })
.then(result => {
if (result.status !== 0) {
throw new Error(result.message);
}
const dlg = this.dialogSet.openNext({ email: this.authEmail });
setTimeout(() => {
this.validateForm(dlg);
const codeInput = document.getElementById('eqAuthCode');
if (codeInput) {
codeInput.focus();
}
}, 200);
})
.catch(error => {
dlg.showAlert('Error: ' + error.message, "error", true);
dlg.enableButtons();
});
return false;
}
codePageOnSubmit(dlg) {
const codeInput = document.getElementById('eqAuthCode');
const authCode = codeInput.value;
dlg.disableButtons();
this.http.post(core.equtils.combinePath(baseLicApiUrl, 'get-key'), {
token: authCode,
email: this.authEmail,
ptag: this.context.backendInfo.type,
version: eqVersion
}, { dataType: 'json' })
.then(result => {
switch (result.status) {
case 0:
const url = core.equtils.combinePath(this.context.getBaseEndpoint(), 'lck');
this.http.post(url, {
version: eqVersion,
key: result.key
}, { dataType: 'json' })
.then(_ => this.dialogSet.open(2, {
message: '<div style="font-size:1.2em">Please restart your web application to get the key applied.</div>'
}), _ => this.dialogSet.open(2, {
message: '<div style="font-size:1.2em">' +
'Please visit <a href="https://account.korzh.com">your account page on Korzh.com</a> to get the key ' +
'and then add it to the <i>appsettings.json</i> file (in the <i>EasyQuery/LicenseKey</i> option).</div>'
}));
break;
case 2:
this.dialogSet.open(3, {
message: '<div style="font-size:1.2em">Your trial license for EasyQuery has expired.</div>' +
'<div style="font-size:1.2em">Please <a href="https://korzh.com/support">contact us</a> if you want to extend the trial period.</div>'
});
break;
case 3:
this.dialogSet.open(3, {
message: '<div style="font-size:1.2em">The maintenance subscription for your EasyQuery license has expired.</div>' +
'<div style="font-size:1.2em">You need to <a href="https://account.korzh.com">renew the subscription</a> to get a valid license.</div>'
});
break;
default:
throw new Error(result.message);
}
})
.catch(error => {
//quick fix for 7.2.5 (must be removed after fixing of HttpResponseError in EasyData)
if (!error.message) {
error.message = 'Invalid or expired code. Please re-submit your request.';
}
dlg.showAlert('Error: ' + error.message, "error", true);
dlg.enableButtons();
});
return false;
}
}
function showNoLicenseAlert(context) {
if (lcv.__kt == -3) {
const lcd = new LCDialog(context);
lcd.show();
}
else {
let title, body, buttonTitle, buttonUrl;
switch (lcv.__kt) {
case 1:
title = 'EasyQuery trial has expired';
body = `Your trial period for EasyQuery has expired.
You can <a href="https://korzh.com/support">submit a request to extend your trial</a> or <a href="https://korzh.com/easyquery#licensing">buy a license</a> to get rid of all limitations.`;
buttonTitle = 'Buy a license';
buttonUrl = '#licensing';
break;
default:
title = `Invalid key for EasyQuery!`;
body = `The EasyQuery product key is either invalid or was issued for a different version of the library.
The version you are using now is ${eqVersion},
so please <a href="https://account.korzh.com">login to your account</a> to get a proper key for version ${eqVersion}`;
buttonTitle = 'Get key';
buttonUrl = 'https://account.korzh.com';
break;
}
const ds = new ui.DefaultDialogService();
const dlg = ds.open({
closable: false,
cancelable: false,
submitable: false,
title: title,
body: body
});
const footer = dlg.getRootElement().querySelector('footer');
ui.domel(footer)
.removeClass('align-right')
.setStyle('justify-content', 'center')
.addChild('button', b => b
.addClass('kfrm-button', 'is-info')
.addText(buttonTitle)
.on('click', (e) => {
window.location.href = buttonUrl;
}));
if (lcv.__kt == 1) {
ui.domel(footer)
.addChild('button', b => b
.addClass('kfrm-button')
.addText('Extend trial')
.on('click', (e) => {
window.location.href = 'https://account.korzh.com';
}));
}
}
}
class EnterpriseEqContext extends core.EqContext {
useEnterprise(keyOrInitCallback) {
const func = (key) => {
lcv.ck(key);
if (lcv.__kt > 1) {
const services = this.getServices();
services.registerDataModelResolver(context => new DataModelEx());
services.registerQueryResolver(context => new QueryEx(context.getModel(), { context: context }));
services.registerQueryStorageResolver(context => new EqServerQueryStorage(context));
services.registerAggregatesCalculator(context => new DataTableAggregatesCalculator(context));
if (lcv.__kt === 2) {
console.warn('EasyQuery.JS is working in the TRIAL MODE!\n'
+ 'Please order a license (https://korzh.com/easyquery) to get a proper product key.');
this.createTrialWM();
setTimeout(() => {
this.showTrialWM();
setTimeout(() => { this.hideTrialWM(); }, 6000);
}, 3000);
}
}
else {
showNoLicenseAlert(this);
}
};
if (typeof (keyOrInitCallback) === "string") {
func(keyOrInitCallback);
}
else if (typeof (keyOrInitCallback) === "function") {
const http = this.getServices().getHttpClient();
let url = core.equtils.combinePath(this.getBaseEndpoint(), 'lck2');
http.get(url)
.then(result => {
func(result.key.split("").reverse().join(""));
this.useBackend({
type: result.backendType,
subType: result.appType
});
keyOrInitCallback();
})
.catch(error => {
if (error.status == 401) {
//if the stutus is Not Autorized
func('');
}
else {
//otherwise try the old way
url = core.equtils.combinePath(this.getBaseEndpoint(), 'lck');
http.get(url)
.then(result => {
func(result.split("").reverse().join(""));
keyOrInitCallback();
})
.catch(error => this.throwError({
action: "LCK",
sourceError: error
}));
}
});
}
else {
throw new Error("Wrong type of 'keyOrInitCallback' parameter. It must be a string with a license key or a callback function.");
}
}
createTrialWM() {
// we can rewrite it using shadow dom
// to make it impossible to hide using JS :)
let trialDiv = document.createElement("div");
trialDiv.style.position = "fixed";
trialDiv.style.bottom = "0";
trialDiv.style.right = "-400px";
trialDiv.style.width = "400px";
trialDiv.style.height = "100px";
trialDiv.style.color = "grey";
trialDiv.style.textAlign = "center";
trialDiv.style.opacity = "0.7";
trialDiv.style.font = "bold 1em Trebuchet MS, Tahoma, Verdana, Geneva, Arial, Helvetica, sans-serif";
trialDiv.style.transition = "right 3s ease-out";
const header = document.createElement("div");
const eq = document.createElement("span");
eq.innerText = "EasyQuery";
eq.style.color = "#3A94D4";
eq.style.lineHeight = "50px";
header.appendChild(eq);
const korzh = document.createElement("span");
korzh.innerText = "by Korzh.com";
korzh.style.marginLeft = "10px";
header.appendChild(korzh);
trialDiv.appendChild(header);
const trialOnly = document.createElement("div");
trialOnly.innerText = "FOR TRIAL USE ONLY";
trialOnly.style.fontSize = "1.2em";
trialOnly.style.fontWeight = "1000";
trialDiv.appendChild(trialOnly);
document.body.appendChild(trialDiv);
this.trialDivElement = trialDiv;
}
showTrialWM() {
if (this.trialDivElement) {
this.trialDivElement.style.right = "0";
}
}
hideTrialWM() {
if (this.trialDivElement) {
this.trialDivElement.style.right = "-400px";
setTimeout(() => {
this.trialDivElement.parentNode.removeChild(this.trialDivElement);
}, 5000);
}
}
}
core.registerEqContextResolver(() => new EnterpriseEqContext());
class EqServerAggregatesCalculator {
constructor(context) {
this.context = context;
this._needRecalculation = true;
this.aggrContainer = new core.EqAggregatesContainer(context);
}
getAggrContainer() {
return this.aggrContainer;
}
calculate(options) {
this._needRecalculation = false;
this.aggrContainer.clear();
options = options || {};
options.maxLevel = options.maxLevel >= 0
? options.maxLevel : 0;
const levelPromises = [];
const query = this.context.createQuery();
query.loadFromData(this.context.getQuery().toJSONData());
const settings = this.context.getQuery().getAggregationSettings();
const aggregates = settings.getAggregates();
const aggrColIds = settings.getAggregates().map(a => a.colId);
const aggrCols = query.getColumns()
.filter(col => aggrColIds.indexOf(col.id) >= 0);
for (const col of aggrCols) {
query.changeColumnType(col, core.ExprTag.AggregateFunction, { funcId: aggregates.filter(a => a.colId == col.id)[0].funcId });
}
//get all non-aggregate columns
const queryCols = query.getColumns()
.filter(c => c.expr.tag !== core.ExprTag.AggregateFunction);
for (const col of queryCols) {
col.setHidden(true);
}
if (settings.hasRecordCount()) {
const col = query.createColumn();
col.caption = settings.COUNT_FIELD_NAME;
col['_id'] = settings.COUNT_FIELD_NAME;
const sqlText = 'COUNT(*)';
const customSqlExpr = new core.Expression(col);
customSqlExpr.tag = core.ExprTag.CustomSql;
customSqlExpr.sql = sqlText;
customSqlExpr.baseAttrId = null;
col.expr = customSqlExpr;
query.getColumns().push(col);
}
if (settings.hasGrandTotals()) {
levelPromises.push(this.processLevel({
query: query,
level: 0,
groupName: 'Grand Totals',
resultObtainedCallback: options.resultObtained,
errorOccurredCallback: options.errorOccurred
}));
}
const groups = settings.getGroups();
for (let level = 1; level <= groups.length; level++) {
const group = groups[level - 1];
for (const col of queryCols) {
col.setHidden(group.columns.indexOf(col.id) < 0);
}
levelPromises.push(this.processLevel({
query: query,
level: level,
groupName: group.name,
resultObtainedCallback: options.resultObtained,
errorOccurredCallback: options.errorOccurred
}));
}
return Promise.all(levelPromises)
.then(() => {
return;
})
.catch((error) => console.error(error));
}
processLevel(options) {
const fetcher = this.context.getDataFetcher();
let fetchOptions = {
aux: true,
query: options.query
};
if (this.context.debugMode) {
fetchOptions.debug = `Fetching group data. Group: '${options.groupName}', level: ${options.level}`;
}
const resultPromise = fetcher.fetchData(fetchOptions)
.then((result) => {
const dataTable = new core$1.EasyDataTable({
elasticChunks: true
});
const resultSet = result.resultSet;
for (const col of resultSet.cols) {
dataTable.columns.add(col);
}
for (const row of resultSet.rows) {
dataTable.addRow(row);
}
const levelData = this.buildLevelData(options.level, dataTable);
this.aggrContainer.setAggregateData(options.level, levelData);
if (options.resultObtainedCallback) {
options.resultObtainedCallback(result, options.level);
}
})
.catch((error) => {
if (options.errorOccurredCallback) {
options.errorOccurredCallback(Object.assign(Object.assign({}, error), { level: options.level }));
}
});
return resultPromise;
}
buildLevelData(level, dataTable) {
const aggrSettings = this.context.getQuery().getAggregationSettings();
const keyColumns = level > 0
? aggrSettings.getGroups()[level - 1].columns
: [];
const valueColumns = aggrSettings.getAggregates().map(a => a.colId);
if (aggrSettings.hasRecordCount()) {
valueColumns.push(aggrSettings.COUNT_FIELD_NAME);
}
const data = new Map();
for (const row of dataTable.getCachedRows()) {
const key = {};
const value = {};
for (const keyCol of keyColumns) {
const colIdx = dataTable.columns.getIndex(keyCol);
if (colIdx >= 0) {
let keyVal = row.getValue(keyCol);
if (!aggrSettings.caseSensitiveGroups && typeof (keyVal) === 'string') {
keyVal = keyVal.toLowerCase();
}
key[keyCol] = keyVal;
}
}
for (const valueCol of valueColumns) {
value[valueCol] = row.getValue(valueCol);
}
data.set(JSON.stringify(key), value);
}
return data;
}
needRecalculation() {
return this._needRecalculation;
}
reset() {
this._needRecalculation = true;
}
}
exports.ConditionEx = ConditionEx;
exports.DataModelEx = DataModelEx;
exports.EqServerAggregatesCalculator = EqServerAggregatesCalculator;
exports.EqServerQueryStorage = EqServerQueryStorage;
exports.QueryColumnEx = QueryColumnEx;
exports.QueryEx = QueryEx;