@easyquery/enterprise 7.2.5-beta01 → 7.2.5-rc01
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/easyquery.enterprise.cjs.js +1218 -0
- package/dist/easyquery.enterprise.esm.js +1211 -0
- package/dist/types/dm/model_ex.d.ts +3 -0
- package/dist/types/extensions.d.ts +1 -0
- package/dist/{lib → types}/query/query_ex.d.ts +5 -1
- package/package.json +16 -36
- package/api-eq-enterprise.js +0 -15
- package/dist/browser/eq.enterprise.js +0 -37130
- package/dist/browser/eq.enterprise.js.map +0 -1
- package/dist/browser/eq.enterprise.min.js +0 -2
- package/dist/browser/eq.enterprise.min.js.LICENSE.txt +0 -11
- package/dist/browser/eq.enterprise.min.js.map +0 -1
- package/dist/bundles/easyquery.enterprise.js +0 -8107
- package/dist/bundles/easyquery.enterprise.js.map +0 -1
- package/dist/bundles/easyquery.enterprise.min.js +0 -3
- package/dist/bundles/easyquery.enterprise.min.js.LICENSE.txt +0 -1
- package/dist/bundles/easyquery.enterprise.min.js.map +0 -1
- package/dist/lib/data/data_table_aggr_calculator.js +0 -164
- package/dist/lib/data/data_table_aggr_calculator.js.map +0 -1
- package/dist/lib/data/eqs_aggr_calculator.js +0 -173
- package/dist/lib/data/eqs_aggr_calculator.js.map +0 -1
- package/dist/lib/dm/model_ex.d.ts +0 -9
- package/dist/lib/dm/model_ex.js +0 -152
- package/dist/lib/dm/model_ex.js.map +0 -1
- package/dist/lib/extensions.d.ts +0 -26
- package/dist/lib/extensions.js +0 -115
- package/dist/lib/extensions.js.map +0 -1
- package/dist/lib/license/lc-dialog.js +0 -315
- package/dist/lib/license/lc-dialog.js.map +0 -1
- package/dist/lib/main/eqs_query_storage.js +0 -106
- package/dist/lib/main/eqs_query_storage.js.map +0 -1
- package/dist/lib/public_api.js +0 -8
- package/dist/lib/public_api.js.map +0 -1
- package/dist/lib/query/condition_ex.js +0 -98
- package/dist/lib/query/condition_ex.js.map +0 -1
- package/dist/lib/query/query_column_ex.js +0 -58
- package/dist/lib/query/query_column_ex.js.map +0 -1
- package/dist/lib/query/query_ex.js +0 -78
- package/dist/lib/query/query_ex.js.map +0 -1
- package/dist/lib/utils/lcv.js +0 -103
- package/dist/lib/utils/lcv.js.map +0 -1
- package/tsconfig.json +0 -22
- package/webpack.config.js +0 -118
- /package/dist/{lib → types}/data/data_table_aggr_calculator.d.ts +0 -0
- /package/dist/{lib → types}/data/eqs_aggr_calculator.d.ts +0 -0
- /package/dist/{lib → types}/license/lc-dialog.d.ts +0 -0
- /package/dist/{lib → types}/main/eqs_query_storage.d.ts +0 -0
- /package/dist/{lib → types}/public_api.d.ts +0 -0
- /package/dist/{lib → types}/query/condition_ex.d.ts +0 -0
- /package/dist/{lib → types}/query/query_column_ex.d.ts +0 -0
- /package/dist/{lib → types}/utils/lcv.d.ts +0 -0
|
@@ -0,0 +1,1211 @@
|
|
|
1
|
+
import { Condition, CondTag, QueryColumn, Query, Tree, LinkType, DataModel, EqAggregatesContainer, equtils, registerEqContextResolver, EqContext, ExprTag, Expression } from '@easyquery/core';
|
|
2
|
+
import { HttpClient, EasyDataTable } from '@easydata/core';
|
|
3
|
+
import { DefaultDialogService, domel } from '@easydata/ui';
|
|
4
|
+
|
|
5
|
+
const majVer = 7;
|
|
6
|
+
const minVer = 2;
|
|
7
|
+
const magics = [45, 128, 231];
|
|
8
|
+
Math.trunc = Math.trunc || function (x) {
|
|
9
|
+
if (isNaN(x)) {
|
|
10
|
+
return NaN;
|
|
11
|
+
}
|
|
12
|
+
if (x > 0) {
|
|
13
|
+
return Math.floor(x);
|
|
14
|
+
}
|
|
15
|
+
return Math.ceil(x);
|
|
16
|
+
};
|
|
17
|
+
const lcv = {
|
|
18
|
+
__kt: 0,
|
|
19
|
+
versionNum: '' + majVer + '.' + minVer,
|
|
20
|
+
ck: function (key) {
|
|
21
|
+
if (!key || !key.length) {
|
|
22
|
+
this.__kt = -3;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
var part1 = key.slice(0, key.length - 12);
|
|
27
|
+
var infoBytes = _bs(part1);
|
|
28
|
+
var part2 = key.slice(key.length - 12);
|
|
29
|
+
let ism = false;
|
|
30
|
+
for (const magic of magics) {
|
|
31
|
+
var edc = t36(magic);
|
|
32
|
+
if (part2[0] === edc[0] && part2[2] === edc[1]) {
|
|
33
|
+
ism = true;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!ism) {
|
|
38
|
+
lcv.__kt = -1;
|
|
39
|
+
}
|
|
40
|
+
var idx = minVer % 4;
|
|
41
|
+
var shift = majVer + minVer;
|
|
42
|
+
if (part2[6 + idx] != encChar(shift, 19)) {
|
|
43
|
+
lcv.__kt = -2;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (part2[1] != encChar(infoBytes[3])) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
lcv.__kt = part2[3] != encChar(infoBytes[5]) ? 2 : 3;
|
|
50
|
+
if (lcv.__kt === 2) {
|
|
51
|
+
var eds = `${f36(part2.substring(4, 6) + part2.substring(10))}`;
|
|
52
|
+
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);
|
|
53
|
+
if (Date.now() > ed.getTime()) {
|
|
54
|
+
lcv.__kt = 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function encChar(x, b = 20) {
|
|
63
|
+
return String.fromCharCode(65 + x % b);
|
|
64
|
+
}
|
|
65
|
+
function _bs(str) {
|
|
66
|
+
var binary_string = urlatob(str);
|
|
67
|
+
var len = binary_string.length;
|
|
68
|
+
var bytes = new Uint8Array(len);
|
|
69
|
+
for (var i = 0; i < len; i++) {
|
|
70
|
+
bytes[i] = binary_string.charCodeAt(i);
|
|
71
|
+
}
|
|
72
|
+
return bytes;
|
|
73
|
+
}
|
|
74
|
+
function urlatob(str) {
|
|
75
|
+
var s = str;
|
|
76
|
+
s = s.replace(/-/g, '+');
|
|
77
|
+
s = s.replace(/_/g, '/');
|
|
78
|
+
switch (s.length % 4) {
|
|
79
|
+
case 0:
|
|
80
|
+
break;
|
|
81
|
+
case 2:
|
|
82
|
+
s += "==";
|
|
83
|
+
break;
|
|
84
|
+
case 3:
|
|
85
|
+
s += "=";
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
return window.atob(s);
|
|
89
|
+
}
|
|
90
|
+
const tokens = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
91
|
+
function t36(val) {
|
|
92
|
+
var result = "";
|
|
93
|
+
while (val > 0) {
|
|
94
|
+
result = tokens[val % tokens.length] + result;
|
|
95
|
+
val /= tokens.length;
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
function f36(val) {
|
|
100
|
+
var d = 0;
|
|
101
|
+
for (var i = 0; i < val.length; ++i)
|
|
102
|
+
d += tokens.indexOf(val[i]) * Math.pow(tokens.length, val.length - i - 1);
|
|
103
|
+
return d;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class ConditionEx extends Condition {
|
|
107
|
+
constructor() {
|
|
108
|
+
super(...arguments);
|
|
109
|
+
this.readOnly = false;
|
|
110
|
+
this.parameterized = false;
|
|
111
|
+
this.inJoin = false;
|
|
112
|
+
}
|
|
113
|
+
isReadOnly() {
|
|
114
|
+
return this.readOnly || (this.getParent() && this.getParent().isReadOnly());
|
|
115
|
+
}
|
|
116
|
+
setReadOnly(value) {
|
|
117
|
+
this.readOnly = value || (this.getParent() && this.getParent().isReadOnly());
|
|
118
|
+
this.conditions && this.conditions.forEach((cond) => {
|
|
119
|
+
cond.setReadOnly(value);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
isParameterized() {
|
|
123
|
+
return this.parameterized;
|
|
124
|
+
}
|
|
125
|
+
setParameterized(value) {
|
|
126
|
+
this.parameterized = value;
|
|
127
|
+
}
|
|
128
|
+
isInJoin() {
|
|
129
|
+
return this.inJoin;
|
|
130
|
+
}
|
|
131
|
+
setInJoin(value) {
|
|
132
|
+
this.inJoin = value;
|
|
133
|
+
}
|
|
134
|
+
loadFromData(model, data) {
|
|
135
|
+
super.loadFromData(model, data);
|
|
136
|
+
if (lcv.__kt <= 1)
|
|
137
|
+
return;
|
|
138
|
+
if (typeof data.readOnly !== 'undefined') {
|
|
139
|
+
this.setReadOnly(data.readOnly);
|
|
140
|
+
}
|
|
141
|
+
if (typeof data.inJoin !== 'undefined') {
|
|
142
|
+
this.setInJoin(data.inJoin);
|
|
143
|
+
}
|
|
144
|
+
if (typeof data.parameterized !== 'undefined') {
|
|
145
|
+
this.setParameterized(data.parameterized);
|
|
146
|
+
}
|
|
147
|
+
//if condition group
|
|
148
|
+
//this.linkType = data.linking;
|
|
149
|
+
if (data.conds) {
|
|
150
|
+
for (let i = 0; i < data.conds.length; i++) {
|
|
151
|
+
let newCond = this.query.createCondition();
|
|
152
|
+
newCond.loadFromData(model, data.conds[i]);
|
|
153
|
+
this.conditions.push(newCond);
|
|
154
|
+
newCond.setParent(this);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
saveToData() {
|
|
159
|
+
let obj = super.saveToData();
|
|
160
|
+
if (lcv.__kt <= 1)
|
|
161
|
+
return obj;
|
|
162
|
+
if (this.isReadOnly()) {
|
|
163
|
+
obj.readOnly = this.isReadOnly();
|
|
164
|
+
}
|
|
165
|
+
if (this.isParameterized()) {
|
|
166
|
+
obj.parameterized = this.isParameterized();
|
|
167
|
+
}
|
|
168
|
+
if (this.isInJoin()) {
|
|
169
|
+
obj.inJoin = this.isInJoin();
|
|
170
|
+
}
|
|
171
|
+
if (this.tag == CondTag.Group) {
|
|
172
|
+
//if condition group
|
|
173
|
+
//obj.linking = this.linkType;
|
|
174
|
+
obj.conds = [];
|
|
175
|
+
for (let i = 0; i < this.conditions.length; i++) {
|
|
176
|
+
obj.conds.push(this.conditions[i].saveToData());
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return obj;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
class QueryColumnEx extends QueryColumn {
|
|
184
|
+
constructor() {
|
|
185
|
+
super(...arguments);
|
|
186
|
+
this.readOnly = false;
|
|
187
|
+
}
|
|
188
|
+
isReadOnly() {
|
|
189
|
+
return this.readOnly;
|
|
190
|
+
}
|
|
191
|
+
setReadOnly(value) {
|
|
192
|
+
this.readOnly = value;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Loads column from its JSON representation object.
|
|
196
|
+
* @param model The Data Model.
|
|
197
|
+
* @param colData The JSON representation object.
|
|
198
|
+
*/
|
|
199
|
+
loadFromData(model, colData) {
|
|
200
|
+
super.loadFromData(model, colData);
|
|
201
|
+
if (lcv.__kt <= 2)
|
|
202
|
+
return;
|
|
203
|
+
if (colData) {
|
|
204
|
+
if (typeof colData.readOnly != 'undefined') {
|
|
205
|
+
this.readOnly = colData.readOnly;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
saveToData() {
|
|
210
|
+
let colData = super.saveToData();
|
|
211
|
+
if (lcv.__kt <= 2)
|
|
212
|
+
return colData;
|
|
213
|
+
if (this.isReadOnly()) {
|
|
214
|
+
colData.readOnly = this.isReadOnly();
|
|
215
|
+
}
|
|
216
|
+
return colData;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
class QueryEx extends Query {
|
|
221
|
+
constructor(model, options) {
|
|
222
|
+
super(model, null, options);
|
|
223
|
+
}
|
|
224
|
+
isEx() {
|
|
225
|
+
return lcv.__kt > 1;
|
|
226
|
+
}
|
|
227
|
+
createSubQuery() {
|
|
228
|
+
return new QueryEx(this.model, { context: this.context });
|
|
229
|
+
}
|
|
230
|
+
createCondition(tag = CondTag.Simple) {
|
|
231
|
+
if (lcv.__kt <= 1)
|
|
232
|
+
return super.createCondition(tag);
|
|
233
|
+
return new ConditionEx(this, tag);
|
|
234
|
+
}
|
|
235
|
+
createColumn(justsorted = false) {
|
|
236
|
+
if (lcv.__kt <= 1)
|
|
237
|
+
return super.createColumn(justsorted);
|
|
238
|
+
return new QueryColumnEx(this, justsorted);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Adds a condition group - a group of simple conditions (predicates) linked by AND or OR
|
|
242
|
+
* @param descriptor The descriptor of the new condition group.
|
|
243
|
+
* @returns The new search condition.
|
|
244
|
+
*/
|
|
245
|
+
addConditionGroup(descriptor, addChildCondition = true) {
|
|
246
|
+
if (lcv.__kt <= 1)
|
|
247
|
+
return super.addConditionGroup(descriptor, addChildCondition);
|
|
248
|
+
let parent = descriptor.parent || this.getRootCondition();
|
|
249
|
+
let lType = descriptor.linking || (parent.linkType === LinkType.All ? LinkType.Any : LinkType.All);
|
|
250
|
+
let group = this.createCondition(CondTag.Group);
|
|
251
|
+
group.linkType = lType;
|
|
252
|
+
if (addChildCondition) {
|
|
253
|
+
let model = this.getModel();
|
|
254
|
+
let attr = model.getFirstUICAttr();
|
|
255
|
+
if (attr) {
|
|
256
|
+
let op = model.getDefaultOperatorForAttr(attr);
|
|
257
|
+
let cond = this.createSimpleConditionObject(attr, op, "");
|
|
258
|
+
group.addCondition(cond);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
parent.addCondition(group);
|
|
262
|
+
return group;
|
|
263
|
+
}
|
|
264
|
+
addExtraConditionGroup(descriptor, addChildCondition = true) {
|
|
265
|
+
descriptor.parent = descriptor.parent || this.extraConditions;
|
|
266
|
+
if (lcv.__kt <= 1)
|
|
267
|
+
return super.addExtraConditionGroup(descriptor, addChildCondition);
|
|
268
|
+
return this.addConditionGroup(descriptor);
|
|
269
|
+
}
|
|
270
|
+
buildQueryPath() {
|
|
271
|
+
const model = this.getModel();
|
|
272
|
+
if (lcv.__kt <= 1)
|
|
273
|
+
return this.buildQueryPath();
|
|
274
|
+
if (model.getMainEntity())
|
|
275
|
+
return this.buildQueryPath();
|
|
276
|
+
const entities = this.getEntitiesInQuery();
|
|
277
|
+
if (entities.length == 0) {
|
|
278
|
+
throw Error("Cannon build path. Path is empty");
|
|
279
|
+
}
|
|
280
|
+
let tree = new Tree(entities[0]);
|
|
281
|
+
for (let i = 1; i < entities.length; i++) {
|
|
282
|
+
const entity = entities[i];
|
|
283
|
+
if (tree.contains(entity)) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
let path = this.findPath(tree.value, entity);
|
|
287
|
+
if (path != null) {
|
|
288
|
+
//Add path to tree
|
|
289
|
+
tree = this.addPathToTree(tree, (path[0] === tree.value) ? path.slice(1) : path);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
throw Error("Unable to build query. Cannot build path.");
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
tree.setParents();
|
|
296
|
+
return tree;
|
|
297
|
+
}
|
|
298
|
+
addPathToTree(tree, path) {
|
|
299
|
+
if (path.length == 0) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
let pathAdded = false;
|
|
303
|
+
for (let child of tree.childs) {
|
|
304
|
+
if (child.value === path[0]) {
|
|
305
|
+
pathAdded = true;
|
|
306
|
+
if (path.length > 1)
|
|
307
|
+
child = this.addPathToTree(child, path.slice(1));
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!pathAdded) {
|
|
312
|
+
let link = this.getModel().findLink(tree.value, path[0]);
|
|
313
|
+
if (link) {
|
|
314
|
+
let newNode = new Tree(path[0]);
|
|
315
|
+
tree.addChild(newNode);
|
|
316
|
+
if (path.length > 1)
|
|
317
|
+
newNode = this.addPathToTree(newNode, path.slice(1));
|
|
318
|
+
}
|
|
319
|
+
else if (!tree.parent) {
|
|
320
|
+
let node = new Tree(tree);
|
|
321
|
+
tree = new Tree(path[0]);
|
|
322
|
+
tree.addChild(node);
|
|
323
|
+
if (path.length > 1)
|
|
324
|
+
tree = this.addPathToTree(tree, path.slice(1));
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
throw Error("Unable to build query. Cannot build path.");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return tree;
|
|
331
|
+
}
|
|
332
|
+
findPath(entityFrom, entityTo) {
|
|
333
|
+
let curPath = [];
|
|
334
|
+
let curStep = [];
|
|
335
|
+
let nextStep = [];
|
|
336
|
+
let passedEntities = [];
|
|
337
|
+
let pathFound = false;
|
|
338
|
+
curPath.push(entityFrom);
|
|
339
|
+
curStep.push(curPath);
|
|
340
|
+
passedEntities.push(entityFrom);
|
|
341
|
+
while (!pathFound) {
|
|
342
|
+
nextStep = [];
|
|
343
|
+
for (let path of curStep) {
|
|
344
|
+
pathFound = this.checkPath(path, entityTo, nextStep, passedEntities);
|
|
345
|
+
if (pathFound) {
|
|
346
|
+
path.push(entityTo);
|
|
347
|
+
curPath = path;
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
curStep = [];
|
|
352
|
+
if (!pathFound) {
|
|
353
|
+
if (nextStep.length == 0)
|
|
354
|
+
return null;
|
|
355
|
+
//copy nextStep to curStep
|
|
356
|
+
for (let path of nextStep)
|
|
357
|
+
curStep.push(path);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return curPath;
|
|
361
|
+
}
|
|
362
|
+
checkPath(path, entityTo, nextStep, passedEntities) {
|
|
363
|
+
const endPoint = path[path.length - 1];
|
|
364
|
+
const entityLinks = this.getModel().getLinksByEntity(endPoint);
|
|
365
|
+
for (let link of entityLinks) {
|
|
366
|
+
let entity2 = null;
|
|
367
|
+
if (link.entityFrom == endPoint) {
|
|
368
|
+
entity2 = link.entityTo;
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
entity2 = link.entityFrom;
|
|
372
|
+
}
|
|
373
|
+
if (entity2 == entityTo) { //if reach the destination
|
|
374
|
+
nextStep = [];
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
//if destination is not reached yet we add current node (entity2) to the path and proceed
|
|
378
|
+
if (path.indexOf(entity2) < 0 && passedEntities.indexOf(entity2) < 0) { //to prevent cycling
|
|
379
|
+
passedEntities.push(entity2);
|
|
380
|
+
let newPath = new Array();
|
|
381
|
+
newPath = newPath.concat(path);
|
|
382
|
+
newPath.push(entity2);
|
|
383
|
+
nextStep.push(newPath);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
class EqServerQueryStorage {
|
|
391
|
+
constructor(context) {
|
|
392
|
+
this.context = context;
|
|
393
|
+
}
|
|
394
|
+
init() {
|
|
395
|
+
}
|
|
396
|
+
newQuery(options) {
|
|
397
|
+
options = options || {};
|
|
398
|
+
const query = options.query || this.context.getQuery();
|
|
399
|
+
const model = this.context.getModel();
|
|
400
|
+
const modelId = options.modelId || (model ? model.getId() : "");
|
|
401
|
+
if (options.queryId) {
|
|
402
|
+
query.setId(options.queryId);
|
|
403
|
+
}
|
|
404
|
+
if (options.name) {
|
|
405
|
+
query.setName(options.name);
|
|
406
|
+
}
|
|
407
|
+
if (options.description) {
|
|
408
|
+
query.setDescription(options.description);
|
|
409
|
+
}
|
|
410
|
+
let requestData = {
|
|
411
|
+
'query': query.toJSONData()
|
|
412
|
+
};
|
|
413
|
+
if (options.data) {
|
|
414
|
+
requestData['data'] = options.data;
|
|
415
|
+
}
|
|
416
|
+
const url = this.context.resolveEndpoint('NewQuery', { modelId: modelId });
|
|
417
|
+
const http = this.context.getServices().getHttpClient();
|
|
418
|
+
return http.post(url, requestData)
|
|
419
|
+
.then((responseData) => {
|
|
420
|
+
return responseData.query;
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
getQueryList(options) {
|
|
424
|
+
options = options || {};
|
|
425
|
+
const modelId = options.modelId || this.context.getModel().getId();
|
|
426
|
+
const url = this.context.resolveEndpoint('GetQueryList', { modelId: modelId });
|
|
427
|
+
const http = this.context.getServices().getHttpClient();
|
|
428
|
+
return http.get(url)
|
|
429
|
+
.then((responseData) => {
|
|
430
|
+
if (!responseData.queries) {
|
|
431
|
+
return Promise.reject({
|
|
432
|
+
message: 'Wrong response format'
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
return responseData.queries;
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
loadQuery(options) {
|
|
439
|
+
options = options || {};
|
|
440
|
+
const model = this.context.getModel();
|
|
441
|
+
const query = this.context.getQuery();
|
|
442
|
+
const modelId = options.modelId || model.getId();
|
|
443
|
+
const queryId = options.queryId || query.getId();
|
|
444
|
+
const url = this.context.resolveEndpoint('GetQuery', { modelId: modelId, queryId: queryId });
|
|
445
|
+
const http = this.context.getServices().getHttpClient();
|
|
446
|
+
return http.get(url)
|
|
447
|
+
.then((responseData) => {
|
|
448
|
+
return responseData.query;
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
saveQuery(options) {
|
|
452
|
+
options = options || {};
|
|
453
|
+
const query = options.query || this.context.getQuery();
|
|
454
|
+
const queryId = options.queryId || query.getId();
|
|
455
|
+
if (options.queryId) {
|
|
456
|
+
query.setId(options.queryId);
|
|
457
|
+
}
|
|
458
|
+
const modelId = options.modelId || query.getModel().getId();
|
|
459
|
+
if (options.queryId) {
|
|
460
|
+
query.setId(options.queryId);
|
|
461
|
+
}
|
|
462
|
+
let requestData = {
|
|
463
|
+
'query': query.toJSONData()
|
|
464
|
+
};
|
|
465
|
+
if (options.data) {
|
|
466
|
+
requestData['data'] = options.data;
|
|
467
|
+
}
|
|
468
|
+
const url = this.context.resolveEndpoint('SaveQuery', { modelId: modelId, queryId: queryId });
|
|
469
|
+
const http = this.context.getServices().getHttpClient();
|
|
470
|
+
return http.put(url, requestData)
|
|
471
|
+
.then((responseData) => {
|
|
472
|
+
return responseData.query;
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
removeQuery(options) {
|
|
476
|
+
options = options || {};
|
|
477
|
+
const context = this.context;
|
|
478
|
+
const query = context.getQuery();
|
|
479
|
+
const modelId = options.modelId || query.getModel().getId();
|
|
480
|
+
const queryId = options.queryId || query.getId();
|
|
481
|
+
let requestData = {
|
|
482
|
+
'modelId': modelId,
|
|
483
|
+
'queryId': queryId
|
|
484
|
+
};
|
|
485
|
+
if (options.data) {
|
|
486
|
+
requestData['data'] = options.data;
|
|
487
|
+
}
|
|
488
|
+
const url = this.context.resolveEndpoint('RemoveQuery', { modelId: modelId, queryId: queryId });
|
|
489
|
+
const http = this.context.getServices().getHttpClient();
|
|
490
|
+
return http.delete(url, requestData).getPromise();
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
class DataModelEx extends DataModel {
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
class DataTableAggregatesCalculator {
|
|
498
|
+
constructor(context) {
|
|
499
|
+
this.context = context;
|
|
500
|
+
//stores current totals by level (group) number
|
|
501
|
+
this.levelsTotals = [];
|
|
502
|
+
this.prevRow = null;
|
|
503
|
+
this.aggrContainer = new EqAggregatesContainer(context);
|
|
504
|
+
}
|
|
505
|
+
getAggrContainer() {
|
|
506
|
+
return this.aggrContainer;
|
|
507
|
+
}
|
|
508
|
+
initObjects() {
|
|
509
|
+
this.aggrSettings = this.context.getQuery().getAggregationSettings();
|
|
510
|
+
this.groups = this.aggrSettings.getGroups();
|
|
511
|
+
this.aggregates = this.aggrSettings.getAggregates();
|
|
512
|
+
this.aggrColIds = this.aggrSettings.getAggregates().map(a => a.colId);
|
|
513
|
+
this.aggrCols = this.context.resultTable.columns.getItems()
|
|
514
|
+
.filter(col => this.aggrColIds.indexOf(col.id) >= 0);
|
|
515
|
+
this.levelsTotals = [];
|
|
516
|
+
this.prevRow = null;
|
|
517
|
+
}
|
|
518
|
+
createColumnAggregatesObject() {
|
|
519
|
+
return {
|
|
520
|
+
sum: 0,
|
|
521
|
+
min: Number.MAX_VALUE,
|
|
522
|
+
max: Number.MIN_VALUE
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
calculate(options) {
|
|
526
|
+
this.initObjects();
|
|
527
|
+
this.aggrContainer.clear();
|
|
528
|
+
options = options || {};
|
|
529
|
+
options.maxLevel = options.maxLevel >= 0
|
|
530
|
+
? options.maxLevel : 0;
|
|
531
|
+
var levelNumber = this.groups.length + 1; //number of groups plus grand totals
|
|
532
|
+
for (let levelIndex = 0; levelIndex < levelNumber; levelIndex++) {
|
|
533
|
+
let levelTotals = { count: 0, columns: {} };
|
|
534
|
+
this.resetLevelTotals(levelTotals);
|
|
535
|
+
this.levelsTotals.push(levelTotals);
|
|
536
|
+
}
|
|
537
|
+
const allRows = this.context.resultTable.getCachedRows();
|
|
538
|
+
if (allRows.length > 0) {
|
|
539
|
+
for (const row of allRows) {
|
|
540
|
+
this.processDataRow(row);
|
|
541
|
+
}
|
|
542
|
+
//flusing the totals for all group levels
|
|
543
|
+
for (let levelIndex = 1; levelIndex < levelNumber; levelIndex++) {
|
|
544
|
+
this.flushLevelTotals(levelIndex);
|
|
545
|
+
}
|
|
546
|
+
//flusing the grand totals (if they are turned on)
|
|
547
|
+
if (this.aggrSettings.hasGrandTotals()) {
|
|
548
|
+
this.flushLevelTotals(0);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return Promise.resolve();
|
|
552
|
+
}
|
|
553
|
+
resetLevelTotals(rowTotals) {
|
|
554
|
+
for (const aggrCol of this.aggrCols) {
|
|
555
|
+
rowTotals.columns[aggrCol.id] = this.createColumnAggregatesObject();
|
|
556
|
+
}
|
|
557
|
+
rowTotals.count = 0;
|
|
558
|
+
}
|
|
559
|
+
processDataRow(row) {
|
|
560
|
+
const levelIndexChanged = this.checkLevelChange(row);
|
|
561
|
+
if (levelIndexChanged >= 0) {
|
|
562
|
+
for (let levelIndex = levelIndexChanged; levelIndex < this.levelsTotals.length; levelIndex++) {
|
|
563
|
+
this.flushLevelTotals(levelIndex);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (this.aggrSettings.hasGrandTotals()) {
|
|
567
|
+
this.updateLevelTotals(0, row);
|
|
568
|
+
}
|
|
569
|
+
let levelIndex = 1;
|
|
570
|
+
for (const group of this.groups) {
|
|
571
|
+
this.updateLevelTotals(levelIndex, row);
|
|
572
|
+
levelIndex++;
|
|
573
|
+
}
|
|
574
|
+
this.prevRow = row;
|
|
575
|
+
}
|
|
576
|
+
/** Checks if the values in group columns were changed
|
|
577
|
+
and return the level number they were */
|
|
578
|
+
checkLevelChange(row) {
|
|
579
|
+
if (this.prevRow == null)
|
|
580
|
+
return -1;
|
|
581
|
+
for (let groupIndex = 0; groupIndex < this.groups.length; groupIndex++) {
|
|
582
|
+
var group = this.groups[groupIndex];
|
|
583
|
+
for (const colId of group.columns) {
|
|
584
|
+
const value = row.getValue(colId);
|
|
585
|
+
const prevValue = this.prevRow.getValue(colId);
|
|
586
|
+
if (!this.aggrSettings.compareValues(prevValue, value)) {
|
|
587
|
+
return groupIndex + 1;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return -1;
|
|
592
|
+
}
|
|
593
|
+
/** Saves the current values in levelData for the specified level to AggregateContainer
|
|
594
|
+
and then reset the data row for that level
|
|
595
|
+
*/
|
|
596
|
+
flushLevelTotals(levelIndex) {
|
|
597
|
+
let levelTotals = this.levelsTotals[levelIndex];
|
|
598
|
+
const group = levelIndex > 0 ? this.groups[levelIndex - 1] : null;
|
|
599
|
+
let groupKey = this.aggrSettings.buildGroupKey(group, this.prevRow);
|
|
600
|
+
var groupTotals = {};
|
|
601
|
+
for (const aggr of this.aggregates) {
|
|
602
|
+
const columnTotals = levelTotals.columns[aggr.colId];
|
|
603
|
+
groupTotals[aggr.colId] = this.applyAggrFunc(aggr.funcId, columnTotals, levelTotals);
|
|
604
|
+
}
|
|
605
|
+
if (this.aggrSettings.hasRecordCount()) {
|
|
606
|
+
groupTotals[this.aggrSettings.COUNT_FIELD_NAME] = levelTotals.count;
|
|
607
|
+
}
|
|
608
|
+
this.aggrContainer.updateAggregateData(levelIndex, groupKey, groupTotals);
|
|
609
|
+
this.resetLevelTotals(levelTotals);
|
|
610
|
+
}
|
|
611
|
+
applyAggrFunc(funcId, columnTotals, levelTotals) {
|
|
612
|
+
switch (funcId) {
|
|
613
|
+
case "SUM":
|
|
614
|
+
return columnTotals.sum;
|
|
615
|
+
case "AVG":
|
|
616
|
+
return columnTotals.sum / levelTotals.count;
|
|
617
|
+
case "COUNT":
|
|
618
|
+
case "CNTDST":
|
|
619
|
+
return levelTotals.count;
|
|
620
|
+
case "MIN":
|
|
621
|
+
return columnTotals.min;
|
|
622
|
+
case "MAX":
|
|
623
|
+
return columnTotals.max;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
/** Updates the totals by values in the current DataRow
|
|
627
|
+
* and according to the specified aggregate
|
|
628
|
+
*/
|
|
629
|
+
updateLevelTotals(levelIndex, row) {
|
|
630
|
+
const levelTotals = this.levelsTotals[levelIndex];
|
|
631
|
+
levelTotals.count += 1;
|
|
632
|
+
for (const aggr of this.aggregates) {
|
|
633
|
+
const value = row.getValue(aggr.colId);
|
|
634
|
+
const columnTotals = levelTotals.columns[aggr.colId];
|
|
635
|
+
columnTotals.sum += value;
|
|
636
|
+
if (value < columnTotals.min) {
|
|
637
|
+
columnTotals.min = value;
|
|
638
|
+
}
|
|
639
|
+
if (value > columnTotals.max) {
|
|
640
|
+
columnTotals.max = value;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
needRecalculation() {
|
|
645
|
+
return true;
|
|
646
|
+
}
|
|
647
|
+
reset() {
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function strIsEmpty(str) {
|
|
652
|
+
if (str) {
|
|
653
|
+
return str.trim() === '';
|
|
654
|
+
}
|
|
655
|
+
else
|
|
656
|
+
return true;
|
|
657
|
+
}
|
|
658
|
+
const baseLicApiUrl = 'https://account.korzh.com/api/license';
|
|
659
|
+
const eqVersion = lcv.versionNum;
|
|
660
|
+
class LCDialog {
|
|
661
|
+
constructor(context) {
|
|
662
|
+
this.http = new HttpClient();
|
|
663
|
+
this.context = context;
|
|
664
|
+
}
|
|
665
|
+
show() {
|
|
666
|
+
const dialogService = new DefaultDialogService();
|
|
667
|
+
this.dialogSet = dialogService.createSet([
|
|
668
|
+
{
|
|
669
|
+
closable: false,
|
|
670
|
+
cancelable: false,
|
|
671
|
+
submitOnEnter: true,
|
|
672
|
+
title: 'No license key for EasyQuery',
|
|
673
|
+
body: this.buildStartPage(),
|
|
674
|
+
submitButtonText: 'Submit',
|
|
675
|
+
onInput: this.validateForm.bind(this),
|
|
676
|
+
onSubmit: this.startPageOnSubmit.bind(this)
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
closable: false,
|
|
680
|
+
cancelable: false,
|
|
681
|
+
submitOnEnter: true,
|
|
682
|
+
title: 'Please check your inbox',
|
|
683
|
+
body: this.buildCodePage(),
|
|
684
|
+
submitButtonText: 'Get License Key',
|
|
685
|
+
onInput: this.validateForm.bind(this),
|
|
686
|
+
onSubmit: this.codePageOnSubmit.bind(this)
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
closable: false,
|
|
690
|
+
cancelable: false,
|
|
691
|
+
submitable: false,
|
|
692
|
+
title: 'Success',
|
|
693
|
+
body: this.buildSuccessPage()
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
closable: false,
|
|
697
|
+
cancelable: false,
|
|
698
|
+
submitable: false,
|
|
699
|
+
title: 'Failure',
|
|
700
|
+
body: this.buildFailurePage()
|
|
701
|
+
},
|
|
702
|
+
]);
|
|
703
|
+
const dialog1 = this.dialogSet.open(0);
|
|
704
|
+
setTimeout(() => {
|
|
705
|
+
this.validateForm(dialog1);
|
|
706
|
+
const emailInput = document.getElementById('eqAuthEmail');
|
|
707
|
+
if (emailInput) {
|
|
708
|
+
emailInput.focus();
|
|
709
|
+
}
|
|
710
|
+
}, 200);
|
|
711
|
+
}
|
|
712
|
+
isValidForm(form) {
|
|
713
|
+
const emailInput = form.querySelector('#eqAuthEmail'); //form.querySelector('[name="email"]') as HTMLInputElement;
|
|
714
|
+
if (emailInput) {
|
|
715
|
+
return !strIsEmpty(emailInput.value) &&
|
|
716
|
+
emailInput.value
|
|
717
|
+
.toLowerCase()
|
|
718
|
+
.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,}))$/);
|
|
719
|
+
}
|
|
720
|
+
const codeInput = form.querySelector('#eqAuthCode'); //form.querySelector('[name="code"]') as HTMLInputElement;
|
|
721
|
+
if (codeInput) {
|
|
722
|
+
return !strIsEmpty(codeInput.value) &&
|
|
723
|
+
!isNaN(+codeInput.value) &&
|
|
724
|
+
codeInput.value == codeInput.value.trim() &&
|
|
725
|
+
codeInput.value.length === 6;
|
|
726
|
+
}
|
|
727
|
+
return true;
|
|
728
|
+
}
|
|
729
|
+
validateForm(dialog) {
|
|
730
|
+
const submitButton = dialog.getSubmitButtonElement();
|
|
731
|
+
submitButton.disabled = !this.isValidForm(dialog.getRootElement());
|
|
732
|
+
}
|
|
733
|
+
addInputField(parentBuilder, inputOptions) {
|
|
734
|
+
parentBuilder
|
|
735
|
+
.addChild('label', b => b
|
|
736
|
+
.attr('for', inputOptions.id)
|
|
737
|
+
.addHtml(`${inputOptions.label} ${inputOptions.required ? '<sup style="color: red">*</sup>' : ''}: `))
|
|
738
|
+
.addChild('input', b => {
|
|
739
|
+
b.id(inputOptions.id);
|
|
740
|
+
b.name(inputOptions.name || inputOptions.id);
|
|
741
|
+
b.type(inputOptions.type || 'text');
|
|
742
|
+
if (typeof (inputOptions.value) !== 'undefined') {
|
|
743
|
+
b.value(inputOptions.value);
|
|
744
|
+
}
|
|
745
|
+
if (inputOptions.onInput) {
|
|
746
|
+
b.on('input', inputOptions.onInput);
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
buildStartPage() {
|
|
751
|
+
let form;
|
|
752
|
+
let controlsPanelBuilder;
|
|
753
|
+
const formBuilder = domel('div');
|
|
754
|
+
formBuilder.addChild('div', b => b
|
|
755
|
+
.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>' +
|
|
756
|
+
'<div style="font-size:1.2em">Please fill out the form to obtain a valid trial license key.</div>'));
|
|
757
|
+
formBuilder
|
|
758
|
+
.addClass('kfrm-form')
|
|
759
|
+
.addChild('div', b => {
|
|
760
|
+
controlsPanelBuilder = b;
|
|
761
|
+
b.addClass('kfrm-fields label-above');
|
|
762
|
+
b.addClass('kfrm-break-20');
|
|
763
|
+
});
|
|
764
|
+
this.addInputField(controlsPanelBuilder, {
|
|
765
|
+
id: 'eqAuthEmail',
|
|
766
|
+
name: 'email',
|
|
767
|
+
label: 'Email',
|
|
768
|
+
required: true
|
|
769
|
+
});
|
|
770
|
+
this.addInputField(controlsPanelBuilder, {
|
|
771
|
+
id: 'eqAuthName',
|
|
772
|
+
name: 'contactName',
|
|
773
|
+
label: 'Name (optional)',
|
|
774
|
+
required: false
|
|
775
|
+
});
|
|
776
|
+
formBuilder.addChild('div', b => b
|
|
777
|
+
.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>' +
|
|
778
|
+
' and <a href="https://korzh.com/privacy">Privacy policy</a>.</div>' +
|
|
779
|
+
'<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>'));
|
|
780
|
+
form = formBuilder.toDOM();
|
|
781
|
+
return form;
|
|
782
|
+
}
|
|
783
|
+
buildCodePage() {
|
|
784
|
+
let form;
|
|
785
|
+
let controlsPanelBuilder;
|
|
786
|
+
const formBuilder = domel('div');
|
|
787
|
+
formBuilder.addChild('div', b => b
|
|
788
|
+
.html('<div style="font-size:1.2em">We sent a confirmation code to <strong>{{email}}</strong>.</div>' +
|
|
789
|
+
'<div style="font-size:1.2em">Please find it in the email and enter to the text box below</div>'));
|
|
790
|
+
formBuilder
|
|
791
|
+
.addClass('kfrm-form')
|
|
792
|
+
.addChild('div', b => {
|
|
793
|
+
controlsPanelBuilder = b;
|
|
794
|
+
b.addClass('kfrm-fields label-above');
|
|
795
|
+
b.addClass('kfrm-break-20');
|
|
796
|
+
});
|
|
797
|
+
this.addInputField(controlsPanelBuilder, {
|
|
798
|
+
id: 'eqAuthCode',
|
|
799
|
+
name: 'code',
|
|
800
|
+
label: 'Confirmation code',
|
|
801
|
+
required: true
|
|
802
|
+
});
|
|
803
|
+
formBuilder.addChild('div', b => b
|
|
804
|
+
.html('<div style="margin-top:20px;font-size:0.9em">NB: Don\'t forget to check your SPAM folder ' +
|
|
805
|
+
'if the message does not arrive within the next 5 minutes, and mark it as "Not Spam" if it\'s found there.</div>'));
|
|
806
|
+
form = formBuilder.toDOM();
|
|
807
|
+
return form.outerHTML;
|
|
808
|
+
}
|
|
809
|
+
buildSuccessPage() {
|
|
810
|
+
let form;
|
|
811
|
+
const formBuilder = domel('div');
|
|
812
|
+
formBuilder.addChild('div', b => b
|
|
813
|
+
.html('<div style="font-size:1.2em">You have successfully completed the registration.</div>' + '{{message}}'));
|
|
814
|
+
form = formBuilder.toDOM();
|
|
815
|
+
return form.outerHTML;
|
|
816
|
+
}
|
|
817
|
+
buildFailurePage() {
|
|
818
|
+
let form;
|
|
819
|
+
const formBuilder = domel('div');
|
|
820
|
+
formBuilder.addChild('div', b => b
|
|
821
|
+
.html('{{message}}'));
|
|
822
|
+
form = formBuilder.toDOM();
|
|
823
|
+
return form.outerHTML;
|
|
824
|
+
}
|
|
825
|
+
startPageOnSubmit(dlg) {
|
|
826
|
+
const emailInput = document.getElementById('eqAuthEmail');
|
|
827
|
+
const nameInput = document.getElementById('eqAuthName');
|
|
828
|
+
const authEmail = emailInput.value;
|
|
829
|
+
const authName = nameInput.value;
|
|
830
|
+
dlg.disableButtons();
|
|
831
|
+
this.http.post(equtils.combinePath(baseLicApiUrl, 'get-code'), {
|
|
832
|
+
email: authEmail,
|
|
833
|
+
name: authName,
|
|
834
|
+
data: {
|
|
835
|
+
ptag: this.context.backendInfo.type,
|
|
836
|
+
apptype: this.context.backendInfo.subType,
|
|
837
|
+
}
|
|
838
|
+
}, { dataType: 'json' })
|
|
839
|
+
.then(result => {
|
|
840
|
+
if (result.status !== 0) {
|
|
841
|
+
throw new Error(result.message);
|
|
842
|
+
}
|
|
843
|
+
const dlg = this.dialogSet.openNext({ email: authEmail });
|
|
844
|
+
setTimeout(() => {
|
|
845
|
+
this.validateForm(dlg);
|
|
846
|
+
const codeInput = document.getElementById('eqAuthCode');
|
|
847
|
+
if (codeInput) {
|
|
848
|
+
codeInput.focus();
|
|
849
|
+
}
|
|
850
|
+
}, 200);
|
|
851
|
+
})
|
|
852
|
+
.catch(error => {
|
|
853
|
+
dlg.showAlert(error.message, "error", true);
|
|
854
|
+
dlg.enableButtons();
|
|
855
|
+
});
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
codePageOnSubmit(dlg) {
|
|
859
|
+
const codeInput = document.getElementById('eqAuthCode');
|
|
860
|
+
const authCode = codeInput.value;
|
|
861
|
+
dlg.disableButtons();
|
|
862
|
+
this.http.post(equtils.combinePath(baseLicApiUrl, 'get-key'), {
|
|
863
|
+
token: authCode,
|
|
864
|
+
ptag: this.context.backendInfo.type,
|
|
865
|
+
version: eqVersion
|
|
866
|
+
}, { dataType: 'json' })
|
|
867
|
+
.then(result => {
|
|
868
|
+
switch (result.status) {
|
|
869
|
+
case 0:
|
|
870
|
+
const url = equtils.combinePath(this.context.getBaseEndpoint(), 'lck');
|
|
871
|
+
this.http.post(url, {
|
|
872
|
+
version: eqVersion,
|
|
873
|
+
key: result.key
|
|
874
|
+
}, { dataType: 'json' })
|
|
875
|
+
.then(_ => this.dialogSet.open(2, {
|
|
876
|
+
message: '<div style="font-size:1.2em">Please restart your web application to get the key applied.</div>'
|
|
877
|
+
}), _ => this.dialogSet.open(2, {
|
|
878
|
+
message: '<div style="font-size:1.2em">' +
|
|
879
|
+
'Please visit <a href="https://account.korzh.com">your account page on Korzh.com</a> to get the key ' +
|
|
880
|
+
'and then add it to the <i>appsettings.json</i> file (in the <i>EasyQuery/LicenseKey</i> option).</div>'
|
|
881
|
+
}));
|
|
882
|
+
break;
|
|
883
|
+
case 2:
|
|
884
|
+
this.dialogSet.open(3, {
|
|
885
|
+
message: '<div style="font-size:1.2em">Your trial license for EasyQuery has expired.</div>' +
|
|
886
|
+
'<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>'
|
|
887
|
+
});
|
|
888
|
+
break;
|
|
889
|
+
case 3:
|
|
890
|
+
this.dialogSet.open(3, {
|
|
891
|
+
message: '<div style="font-size:1.2em">The maintenance subscription for your EasyQuery license has expired.</div>' +
|
|
892
|
+
'<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>'
|
|
893
|
+
});
|
|
894
|
+
break;
|
|
895
|
+
default:
|
|
896
|
+
throw new Error(result.message);
|
|
897
|
+
}
|
|
898
|
+
})
|
|
899
|
+
.catch(error => {
|
|
900
|
+
dlg.showAlert(error.message, "error", true);
|
|
901
|
+
dlg.enableButtons();
|
|
902
|
+
});
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
function showNoLicenseAlert(context) {
|
|
907
|
+
if (lcv.__kt == -3) {
|
|
908
|
+
const lcd = new LCDialog(context);
|
|
909
|
+
lcd.show();
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
let title, body, buttonTitle, buttonUrl;
|
|
913
|
+
switch (lcv.__kt) {
|
|
914
|
+
case 1:
|
|
915
|
+
title = 'EasyQuery trial has expired';
|
|
916
|
+
body = `Your trial period for EasyQuery has expired.
|
|
917
|
+
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.`;
|
|
918
|
+
buttonTitle = 'Buy a license';
|
|
919
|
+
buttonUrl = '#licensing';
|
|
920
|
+
break;
|
|
921
|
+
default:
|
|
922
|
+
title = `Invalid key for EasyQuery!`;
|
|
923
|
+
body = `The EasyQuery product key is either invalid or was issued for a different version of the library.
|
|
924
|
+
The version you are using now is ${eqVersion},
|
|
925
|
+
so please <a href="https://account.korzh.com">login to your account</a> to get a proper key for version ${eqVersion}`;
|
|
926
|
+
buttonTitle = 'Get key';
|
|
927
|
+
buttonUrl = 'https://account.korzh.com';
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
const ds = new DefaultDialogService();
|
|
931
|
+
const dlg = ds.open({
|
|
932
|
+
closable: false,
|
|
933
|
+
cancelable: false,
|
|
934
|
+
submitable: false,
|
|
935
|
+
title: title,
|
|
936
|
+
body: body
|
|
937
|
+
});
|
|
938
|
+
const footer = dlg.getRootElement().querySelector('footer');
|
|
939
|
+
domel(footer)
|
|
940
|
+
.removeClass('align-right')
|
|
941
|
+
.setStyle('justify-content', 'center')
|
|
942
|
+
.addChild('button', b => b
|
|
943
|
+
.addClass('kfrm-button', 'is-info')
|
|
944
|
+
.addText(buttonTitle)
|
|
945
|
+
.on('click', (e) => {
|
|
946
|
+
window.location.href = buttonUrl;
|
|
947
|
+
}));
|
|
948
|
+
if (lcv.__kt == 1) {
|
|
949
|
+
domel(footer)
|
|
950
|
+
.addChild('button', b => b
|
|
951
|
+
.addClass('kfrm-button')
|
|
952
|
+
.addText('Extend trial')
|
|
953
|
+
.on('click', (e) => {
|
|
954
|
+
window.location.href = 'https://account.korzh.com';
|
|
955
|
+
}));
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
class EnterpriseEqContext extends EqContext {
|
|
961
|
+
useEnterprise(keyOrInitCallback) {
|
|
962
|
+
const func = (key) => {
|
|
963
|
+
lcv.ck(key);
|
|
964
|
+
if (lcv.__kt > 1) {
|
|
965
|
+
const services = this.getServices();
|
|
966
|
+
services.registerDataModelResolver(context => new DataModelEx());
|
|
967
|
+
services.registerQueryResolver(context => new QueryEx(context.getModel(), { context }));
|
|
968
|
+
services.registerQueryStorageResolver(context => new EqServerQueryStorage(context));
|
|
969
|
+
services.registerAggregatesCalculator(context => new DataTableAggregatesCalculator(context));
|
|
970
|
+
if (lcv.__kt === 2) {
|
|
971
|
+
console.warn('EasyQuery.JS is working in the TRIAL MODE!\n'
|
|
972
|
+
+ 'Please order a license (https://korzh.com/eq) to get a proper product key.');
|
|
973
|
+
this.createTrialWM();
|
|
974
|
+
setTimeout(() => {
|
|
975
|
+
this.showTrialWM();
|
|
976
|
+
setTimeout(() => { this.hideTrialWM(); }, 6000);
|
|
977
|
+
}, 3000);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
showNoLicenseAlert(this);
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
if (typeof (keyOrInitCallback) === "string") {
|
|
985
|
+
func(keyOrInitCallback);
|
|
986
|
+
}
|
|
987
|
+
else if (typeof (keyOrInitCallback) === "function") {
|
|
988
|
+
const http = this.getServices().getHttpClient();
|
|
989
|
+
let url = equtils.combinePath(this.getBaseEndpoint(), 'lck2');
|
|
990
|
+
http.get(url)
|
|
991
|
+
.then(result => {
|
|
992
|
+
func(result.key.split("").reverse().join(""));
|
|
993
|
+
this.useBackend({
|
|
994
|
+
type: result.backendType,
|
|
995
|
+
subType: result.appType
|
|
996
|
+
});
|
|
997
|
+
keyOrInitCallback();
|
|
998
|
+
})
|
|
999
|
+
.catch(error => {
|
|
1000
|
+
url = equtils.combinePath(this.getBaseEndpoint(), 'lck');
|
|
1001
|
+
http.get(url)
|
|
1002
|
+
.then(result => {
|
|
1003
|
+
func(result.split("").reverse().join(""));
|
|
1004
|
+
keyOrInitCallback();
|
|
1005
|
+
})
|
|
1006
|
+
.catch(error => this.throwError({
|
|
1007
|
+
action: "LCK",
|
|
1008
|
+
sourceError: error
|
|
1009
|
+
}));
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
throw new Error("Wrong type of 'keyOrInitCallback' parameter. It must be a string with a license key or a callback function.");
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
createTrialWM() {
|
|
1017
|
+
// we can rewrite it using shadow dom
|
|
1018
|
+
// to make it impossible to hide using JS :)
|
|
1019
|
+
let trialDiv = document.createElement("div");
|
|
1020
|
+
trialDiv.style.position = "fixed";
|
|
1021
|
+
trialDiv.style.bottom = "0";
|
|
1022
|
+
trialDiv.style.right = "-400px";
|
|
1023
|
+
trialDiv.style.width = "400px";
|
|
1024
|
+
trialDiv.style.height = "100px";
|
|
1025
|
+
trialDiv.style.color = "grey";
|
|
1026
|
+
trialDiv.style.textAlign = "center";
|
|
1027
|
+
trialDiv.style.opacity = "0.7";
|
|
1028
|
+
trialDiv.style.font = "bold 1em Trebuchet MS, Tahoma, Verdana, Geneva, Arial, Helvetica, sans-serif";
|
|
1029
|
+
trialDiv.style.transition = "right 3s ease-out";
|
|
1030
|
+
const header = document.createElement("div");
|
|
1031
|
+
const eq = document.createElement("span");
|
|
1032
|
+
eq.innerText = "EasyQuery";
|
|
1033
|
+
eq.style.color = "#3A94D4";
|
|
1034
|
+
eq.style.lineHeight = "50px";
|
|
1035
|
+
header.appendChild(eq);
|
|
1036
|
+
const korzh = document.createElement("span");
|
|
1037
|
+
korzh.innerText = "by Korzh.com";
|
|
1038
|
+
korzh.style.marginLeft = "10px";
|
|
1039
|
+
header.appendChild(korzh);
|
|
1040
|
+
trialDiv.appendChild(header);
|
|
1041
|
+
const trialOnly = document.createElement("div");
|
|
1042
|
+
trialOnly.innerText = "FOR TRIAL USE ONLY";
|
|
1043
|
+
trialOnly.style.fontSize = "1.2em";
|
|
1044
|
+
trialOnly.style.fontWeight = "1000";
|
|
1045
|
+
trialDiv.appendChild(trialOnly);
|
|
1046
|
+
document.body.appendChild(trialDiv);
|
|
1047
|
+
this.trialDivElement = trialDiv;
|
|
1048
|
+
}
|
|
1049
|
+
showTrialWM() {
|
|
1050
|
+
if (this.trialDivElement) {
|
|
1051
|
+
this.trialDivElement.style.right = "0";
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
hideTrialWM() {
|
|
1055
|
+
if (this.trialDivElement) {
|
|
1056
|
+
this.trialDivElement.style.right = "-400px";
|
|
1057
|
+
setTimeout(() => {
|
|
1058
|
+
this.trialDivElement.parentNode.removeChild(this.trialDivElement);
|
|
1059
|
+
}, 5000);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
registerEqContextResolver(() => new EnterpriseEqContext());
|
|
1064
|
+
|
|
1065
|
+
class EqServerAggregatesCalculator {
|
|
1066
|
+
constructor(context) {
|
|
1067
|
+
this.context = context;
|
|
1068
|
+
this._needRecalculation = true;
|
|
1069
|
+
this.aggrContainer = new EqAggregatesContainer(context);
|
|
1070
|
+
}
|
|
1071
|
+
getAggrContainer() {
|
|
1072
|
+
return this.aggrContainer;
|
|
1073
|
+
}
|
|
1074
|
+
calculate(options) {
|
|
1075
|
+
this._needRecalculation = false;
|
|
1076
|
+
this.aggrContainer.clear();
|
|
1077
|
+
options = options || {};
|
|
1078
|
+
options.maxLevel = options.maxLevel >= 0
|
|
1079
|
+
? options.maxLevel : 0;
|
|
1080
|
+
const levelPromises = [];
|
|
1081
|
+
const query = this.context.createQuery();
|
|
1082
|
+
query.loadFromData(this.context.getQuery().toJSONData());
|
|
1083
|
+
const settings = this.context.getQuery().getAggregationSettings();
|
|
1084
|
+
const aggregates = settings.getAggregates();
|
|
1085
|
+
const aggrColIds = settings.getAggregates().map(a => a.colId);
|
|
1086
|
+
const aggrCols = query.getColumns()
|
|
1087
|
+
.filter(col => aggrColIds.indexOf(col.id) >= 0);
|
|
1088
|
+
for (const col of aggrCols) {
|
|
1089
|
+
query.changeColumnType(col, ExprTag.AggregateFunction, { funcId: aggregates.filter(a => a.colId == col.id)[0].funcId });
|
|
1090
|
+
}
|
|
1091
|
+
//get all non-aggregate columns
|
|
1092
|
+
const queryCols = query.getColumns()
|
|
1093
|
+
.filter(c => c.expr.tag !== ExprTag.AggregateFunction);
|
|
1094
|
+
for (const col of queryCols) {
|
|
1095
|
+
col.setHidden(true);
|
|
1096
|
+
}
|
|
1097
|
+
if (settings.hasRecordCount()) {
|
|
1098
|
+
const col = query.createColumn();
|
|
1099
|
+
col.caption = settings.COUNT_FIELD_NAME;
|
|
1100
|
+
col['_id'] = settings.COUNT_FIELD_NAME;
|
|
1101
|
+
const sqlText = 'COUNT(*)';
|
|
1102
|
+
const customSqlExpr = new Expression(col);
|
|
1103
|
+
customSqlExpr.tag = ExprTag.CustomSql;
|
|
1104
|
+
customSqlExpr.sql = sqlText;
|
|
1105
|
+
customSqlExpr.baseAttrId = null;
|
|
1106
|
+
col.expr = customSqlExpr;
|
|
1107
|
+
query.getColumns().push(col);
|
|
1108
|
+
}
|
|
1109
|
+
if (settings.hasGrandTotals()) {
|
|
1110
|
+
levelPromises.push(this.processLevel({
|
|
1111
|
+
query: query,
|
|
1112
|
+
level: 0,
|
|
1113
|
+
groupName: 'Grand Totals',
|
|
1114
|
+
resultObtainedCallback: options.resultObtained,
|
|
1115
|
+
errorOccurredCallback: options.errorOccurred
|
|
1116
|
+
}));
|
|
1117
|
+
}
|
|
1118
|
+
const groups = settings.getGroups();
|
|
1119
|
+
for (let level = 1; level <= groups.length; level++) {
|
|
1120
|
+
const group = groups[level - 1];
|
|
1121
|
+
for (const col of queryCols) {
|
|
1122
|
+
col.setHidden(group.columns.indexOf(col.id) < 0);
|
|
1123
|
+
}
|
|
1124
|
+
levelPromises.push(this.processLevel({
|
|
1125
|
+
query: query,
|
|
1126
|
+
level: level,
|
|
1127
|
+
groupName: group.name,
|
|
1128
|
+
resultObtainedCallback: options.resultObtained,
|
|
1129
|
+
errorOccurredCallback: options.errorOccurred
|
|
1130
|
+
}));
|
|
1131
|
+
}
|
|
1132
|
+
return Promise.all(levelPromises)
|
|
1133
|
+
.then(() => {
|
|
1134
|
+
return;
|
|
1135
|
+
})
|
|
1136
|
+
.catch((error) => console.error(error));
|
|
1137
|
+
}
|
|
1138
|
+
processLevel(options) {
|
|
1139
|
+
const fetcher = this.context.getServices()
|
|
1140
|
+
.getDataFetcher(this.context);
|
|
1141
|
+
let fetchOptions = {
|
|
1142
|
+
aux: true,
|
|
1143
|
+
query: options.query
|
|
1144
|
+
};
|
|
1145
|
+
if (this.context.debugMode) {
|
|
1146
|
+
fetchOptions.debug = `Fetching group data. Group: '${options.groupName}', level: ${options.level}`;
|
|
1147
|
+
}
|
|
1148
|
+
const resultPromise = fetcher.fetchData(fetchOptions)
|
|
1149
|
+
.then((result) => {
|
|
1150
|
+
const dataTable = new EasyDataTable({
|
|
1151
|
+
elasticChunks: true
|
|
1152
|
+
});
|
|
1153
|
+
const resultSet = result.resultSet;
|
|
1154
|
+
for (const col of resultSet.cols) {
|
|
1155
|
+
dataTable.columns.add(col);
|
|
1156
|
+
}
|
|
1157
|
+
for (const row of resultSet.rows) {
|
|
1158
|
+
dataTable.addRow(row);
|
|
1159
|
+
}
|
|
1160
|
+
const levelData = this.buildLevelData(options.level, dataTable);
|
|
1161
|
+
this.aggrContainer.setAggregateData(options.level, levelData);
|
|
1162
|
+
if (options.resultObtainedCallback) {
|
|
1163
|
+
options.resultObtainedCallback(result, options.level);
|
|
1164
|
+
}
|
|
1165
|
+
})
|
|
1166
|
+
.catch((error) => {
|
|
1167
|
+
if (options.errorOccurredCallback) {
|
|
1168
|
+
options.errorOccurredCallback(Object.assign(Object.assign({}, error), { level: options.level }));
|
|
1169
|
+
}
|
|
1170
|
+
});
|
|
1171
|
+
return resultPromise;
|
|
1172
|
+
}
|
|
1173
|
+
buildLevelData(level, dataTable) {
|
|
1174
|
+
const aggrSettings = this.context.getQuery().getAggregationSettings();
|
|
1175
|
+
const keyColumns = level > 0
|
|
1176
|
+
? aggrSettings.getGroups()[level - 1].columns
|
|
1177
|
+
: [];
|
|
1178
|
+
const valueColumns = aggrSettings.getAggregates().map(a => a.colId);
|
|
1179
|
+
if (aggrSettings.hasRecordCount()) {
|
|
1180
|
+
valueColumns.push(aggrSettings.COUNT_FIELD_NAME);
|
|
1181
|
+
}
|
|
1182
|
+
const data = new Map();
|
|
1183
|
+
for (const row of dataTable.getCachedRows()) {
|
|
1184
|
+
const key = {};
|
|
1185
|
+
const value = {};
|
|
1186
|
+
for (const keyCol of keyColumns) {
|
|
1187
|
+
const colIdx = dataTable.columns.getIndex(keyCol);
|
|
1188
|
+
if (colIdx >= 0) {
|
|
1189
|
+
let keyVal = row.getValue(keyCol);
|
|
1190
|
+
if (!aggrSettings.caseSensitiveGroups && typeof (keyVal) === 'string') {
|
|
1191
|
+
keyVal = keyVal.toLowerCase();
|
|
1192
|
+
}
|
|
1193
|
+
key[keyCol] = keyVal;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
for (const valueCol of valueColumns) {
|
|
1197
|
+
value[valueCol] = row.getValue(valueCol);
|
|
1198
|
+
}
|
|
1199
|
+
data.set(JSON.stringify(key), value);
|
|
1200
|
+
}
|
|
1201
|
+
return data;
|
|
1202
|
+
}
|
|
1203
|
+
needRecalculation() {
|
|
1204
|
+
return this._needRecalculation;
|
|
1205
|
+
}
|
|
1206
|
+
reset() {
|
|
1207
|
+
this._needRecalculation = true;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
export { ConditionEx, DataModelEx, EqServerAggregatesCalculator, EqServerQueryStorage, QueryColumnEx, QueryEx };
|