@hpcc-js/marshaller 2.28.7 → 2.28.9

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.
Files changed (55) hide show
  1. package/LICENSE +43 -43
  2. package/dist/index.es6.js +25 -13
  3. package/dist/index.es6.js.map +1 -1
  4. package/dist/index.js +25 -13
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.min.js +2 -2
  7. package/dist/index.min.js.map +1 -1
  8. package/package.json +14 -14
  9. package/src/__package__.ts +3 -3
  10. package/src/dashy.css +239 -239
  11. package/src/dashy.ts +521 -521
  12. package/src/ddl1/DDLApi.ts +229 -229
  13. package/src/ddl1/FlyoutButton.ts +120 -120
  14. package/src/ddl1/Graph.ts +93 -93
  15. package/src/ddl1/HTML.ts +77 -77
  16. package/src/ddl1/HipieDDL.ts +2437 -2437
  17. package/src/ddl1/HipieDDLMixin.ts +380 -380
  18. package/src/ddl1/Tabbed.ts +91 -91
  19. package/src/ddl1/TargetMarshaller.ts +57 -57
  20. package/src/ddl2/PopupManager.ts +89 -89
  21. package/src/ddl2/activities/activity.ts +431 -431
  22. package/src/ddl2/activities/databomb.ts +237 -237
  23. package/src/ddl2/activities/datasource.ts +52 -52
  24. package/src/ddl2/activities/dspicker.ts +106 -106
  25. package/src/ddl2/activities/filter.ts +542 -542
  26. package/src/ddl2/activities/form.ts +153 -153
  27. package/src/ddl2/activities/groupby.ts +439 -439
  28. package/src/ddl2/activities/hipiepipeline.ts +114 -114
  29. package/src/ddl2/activities/limit.ts +49 -49
  30. package/src/ddl2/activities/logicalfile.ts +62 -62
  31. package/src/ddl2/activities/nullview.ts +12 -12
  32. package/src/ddl2/activities/project.ts +764 -764
  33. package/src/ddl2/activities/rest.ts +568 -568
  34. package/src/ddl2/activities/roxie.ts +490 -490
  35. package/src/ddl2/activities/sampledata.json +16264 -16264
  36. package/src/ddl2/activities/sort.ts +176 -176
  37. package/src/ddl2/activities/wuresult.ts +395 -395
  38. package/src/ddl2/dashboard.css +13 -13
  39. package/src/ddl2/dashboard.ts +330 -330
  40. package/src/ddl2/dashboardDockPanel.ts +123 -123
  41. package/src/ddl2/dashboardGrid.ts +202 -202
  42. package/src/ddl2/ddl.ts +410 -410
  43. package/src/ddl2/ddleditor.ts +60 -60
  44. package/src/ddl2/dsTable.ts +238 -238
  45. package/src/ddl2/dvTable.ts +31 -31
  46. package/src/ddl2/graphadapter.ts +297 -297
  47. package/src/ddl2/javascriptadapter.ts +354 -354
  48. package/src/ddl2/model/element.ts +398 -398
  49. package/src/ddl2/model/visualization.ts +351 -351
  50. package/src/ddl2/model/vizChartPanel.ts +149 -149
  51. package/src/ddl2/pipelinePanel.css +4 -4
  52. package/src/ddl2/pipelinePanel.ts +465 -465
  53. package/src/index.ts +26 -26
  54. package/types/__package__.d.ts +2 -2
  55. package/types-3.4/__package__.d.ts +2 -2
@@ -1,764 +1,764 @@
1
- import { PropertyExt, publish, Utility } from "@hpcc-js/common";
2
- import { DDL2 } from "@hpcc-js/ddl-shim";
3
- import { hashSum, isArray } from "@hpcc-js/util";
4
- import { Activity, IActivityError, ReferencedFields } from "./activity";
5
-
6
- export class ComputedMapping extends PropertyExt {
7
- protected _owner: ComputedField;
8
-
9
- @publish(null, "any", "Compare Value", undefined, {
10
- validate: (w: ComputedMapping): boolean => (!w.value() && !w.newValue()) || (!!w.value() && !!w.newValue())
11
- })
12
- value: publish<this, any>;
13
- value_valid: () => boolean;
14
- @publish(null, "any", "New Value", undefined, {
15
- validate: (w: ComputedMapping): boolean => (!w.value() && !w.newValue()) || (!!w.value() && !!w.newValue())
16
- })
17
- newValue: publish<this, any>;
18
- newValue_valid: () => boolean;
19
-
20
- validate(prefix: string): IActivityError[] {
21
- const retVal: IActivityError[] = [];
22
- if (!this.value_valid()) {
23
- retVal.push({
24
- source: `${prefix}.value`,
25
- msg: `Invalid value: "${this.value()}"`,
26
- hint: 'expected: "any"'
27
- });
28
- }
29
- if (!this.newValue_valid()) {
30
- retVal.push({
31
- source: `${prefix}.newValue`,
32
- msg: `Invalid value: "${this.newValue()}"`,
33
- hint: 'expected: "any"'
34
- });
35
- }
36
- return retVal;
37
- }
38
-
39
- constructor() {
40
- super();
41
- }
42
-
43
- owner(): ComputedField;
44
- owner(_: ComputedField): this;
45
- owner(_?: ComputedField): ComputedField | this {
46
- if (!arguments.length) return this._owner;
47
- this._owner = _;
48
- return this;
49
- }
50
-
51
- valid(): boolean {
52
- return !!this.value() && !!this.newValue();
53
- }
54
-
55
- toDDL(): DDL2.IMapMapping {
56
- return {
57
- value: this.value(),
58
- newValue: this.newValue()
59
- };
60
- }
61
-
62
- fromDDL(ddl: DDL2.IMapMapping): this {
63
- return this
64
- .value(ddl.value)
65
- .newValue(ddl.newValue)
66
- ;
67
- }
68
-
69
- static fromDDL(ddl: DDL2.IMapMapping): ComputedMapping {
70
- return new ComputedMapping().fromDDL(ddl);
71
- }
72
- }
73
- ComputedMapping.prototype._class += " ComputedMapping";
74
-
75
- export type ComputedType = "=" | "*" | "/" | "+" | "-" | "scale" | "template" | "map";
76
-
77
- export interface IComputedFieldOwner extends PropertyExt {
78
- fieldIDs(): string[];
79
- field(fieldID: string): DDL2.IField | null;
80
- }
81
-
82
- export class ComputedField extends PropertyExt {
83
- private _owner: IComputedFieldOwner;
84
-
85
- @publish(null, "string", "Label", null, { optional: true })
86
- label: publish<this, string>;
87
- @publish("mapping", "set", "Project type", ["=", "*", "/", "+", "-", "scale", "template", "map"], { optional: true, disable: w => !w.label() })
88
- type: publish<this, ComputedType>;
89
- @publish(null, "set", "Param 1", function (this: ComputedField) { return this.columns(); }, {
90
- optional: true,
91
- disable: (w: ComputedField) => w.disableColumn1(),
92
- validate: (w: ComputedField): boolean => w.columns().indexOf(w.column1()) >= 0
93
- })
94
- column1: publish<this, string>;
95
- column1_valid: () => boolean;
96
- @publish(null, "set", "Param 2", function (this: ComputedField) { return this.columns(); }, {
97
- optional: true,
98
- disable: (w: ComputedField) => w.disableColumn2(),
99
- validate: (w: ComputedField): boolean => w.columns().indexOf(w.column2()) >= 0
100
- })
101
- column2: publish<this, string>;
102
- column2_valid: () => boolean;
103
- @publish(null, "number", "Const value", null, { optional: true, disable: (w: ComputedField) => !w.label() || ["scale"].indexOf(w.type()) < 0 })
104
- constValue: publish<this, number>;
105
- @publish(null, "string", "template", null, { optional: true, disable: (w: ComputedField) => !w.label() || ["template"].indexOf(w.type()) < 0 })
106
- template: publish<this, string>;
107
- @publish(null, "any", "Default Value", null, { optional: true, disable: (w: ComputedField) => !w.label() || ["map"].indexOf(w.type()) < 0 })
108
- default: publish<this, any>;
109
- @publish([], "propertyArray", "Mapped Values", null, { autoExpand: ComputedMapping, disable: (w: ComputedField) => w.disableMapping() })
110
- mapping: publish<this, ComputedMapping[]>;
111
- @publish([], "propertyArray", "Child Fields", null, { autoExpand: ComputedField, disable: (w: ComputedField) => w.disableChildField() })
112
- childField: publish<this, ComputedField[]>;
113
-
114
- disableColumn1(): boolean {
115
- return !this.label() || ["=", "*", "/", "+", "-", "scale", "map"].indexOf(this.type()) < 0;
116
- }
117
-
118
- disableColumn2(): boolean {
119
- return !this.label() || ["*", "/", "+", "-"].indexOf(this.type()) < 0;
120
- }
121
-
122
- disableMapping(): boolean {
123
- return !this.label() || ["map"].indexOf(this.type()) < 0;
124
- }
125
-
126
- disableChildField(): boolean {
127
- return !this.hasChildren();
128
- }
129
-
130
- validate(prefix: string): IActivityError[] {
131
- const retVal: IActivityError[] = [];
132
- if (!this.column1_valid()) {
133
- retVal.push({
134
- source: `${prefix}.${this.label()}`,
135
- msg: `Invalid column1: "${this.column1()}"`,
136
- hint: `expected: ${JSON.stringify(this.columns())}`
137
- });
138
- }
139
- if (!this.column2_valid()) {
140
- retVal.push({
141
- source: `${prefix}.${this.label()}`,
142
- msg: `Invalid column2: "${this.column2()}"`,
143
- hint: `expected: ${JSON.stringify(this.columns())}`
144
- });
145
- }
146
- if (!this.disableMapping()) {
147
- this.validComputedMappings().forEach(cm => cm.validate(`${prefix}.mapping`));
148
- }
149
- if (!this.disableChildField()) {
150
- this.validChildFields().forEach(cf => cf.validate(`${prefix}.childField`));
151
- }
152
- return retVal;
153
- }
154
-
155
- hasChildren() {
156
- if (!this.label()) return false;
157
- if (this.type() !== "=") return false;
158
- if (!this.column1()) return false;
159
- const field = (this._owner as ProjectBase).field(this.column1());
160
- if (field && field.type === "dataset" && field.children) {
161
- return true;
162
- }
163
- return false;
164
- }
165
-
166
- children(): DDL2.IField[] {
167
- const field = (this._owner as ProjectBase).field(this.column1());
168
- if (field && field.type === "dataset") {
169
- return field.children;
170
- }
171
- return [];
172
- }
173
-
174
- constructor() {
175
- super();
176
- }
177
-
178
- owner(): IComputedFieldOwner;
179
- owner(_: IComputedFieldOwner): this;
180
- owner(_?: IComputedFieldOwner): IComputedFieldOwner | this {
181
- if (!arguments.length) return this._owner;
182
- this._owner = _;
183
- return this;
184
- }
185
-
186
- valid(): boolean {
187
- return !!this.label();
188
- }
189
-
190
- validComputedMappings(): ComputedMapping[] {
191
- return this.mapping().filter(cf => cf.valid());
192
- }
193
-
194
- validChildFields() {
195
- return this.childField().filter(cf => cf.valid());
196
- }
197
-
198
- hasChildFields() {
199
- return this.validChildFields().length;
200
- }
201
-
202
- toDDL(): DDL2.MultiTransformationType {
203
- switch (this.type()) {
204
- case "scale":
205
- return {
206
- fieldID: this.label(),
207
- type: "scale",
208
- sourceFieldID: this.column1(),
209
- factor: this.constValue()
210
- };
211
- case "template":
212
- return {
213
- fieldID: this.label(),
214
- type: "template",
215
- template: this.template()
216
- };
217
- case "=":
218
- const transformations = this.validChildFields().map(cf => cf.toDDL());
219
- return {
220
- fieldID: this.label(),
221
- type: "=",
222
- sourceFieldID: this.column1(),
223
- transformations: transformations.length ? transformations : undefined
224
- };
225
- case "map":
226
- return {
227
- fieldID: this.label(),
228
- type: "map",
229
- sourceFieldID: this.column1(),
230
- default: this.default(),
231
- mappings: this.validComputedMappings().map(cm => cm.toDDL())
232
- };
233
- default:
234
- return {
235
- fieldID: this.label(),
236
- type: this.type() as DDL2.ICalculatedType,
237
- sourceFieldID1: this.column1(),
238
- sourceFieldID2: this.column2()
239
- };
240
- }
241
- }
242
-
243
- fromDDL(ddl: DDL2.MultiTransformationType): this {
244
- const retVal = this
245
- .label(ddl.fieldID)
246
- .type(ddl.type)
247
- ;
248
- switch (ddl.type) {
249
- case "scale":
250
- retVal
251
- .column1(ddl.sourceFieldID)
252
- .constValue(ddl.factor)
253
- ;
254
- break;
255
- case "template":
256
- retVal
257
- .template(ddl.template)
258
- ;
259
- break;
260
- case "=":
261
- retVal
262
- .column1(ddl.sourceFieldID)
263
- .childField(ddl.transformations ? ddl.transformations.map(transformation => ComputedField.fromDDL(transformation)) : [])
264
- ;
265
- break;
266
- case "map":
267
- retVal
268
- .column1(ddl.sourceFieldID)
269
- .default(ddl.default)
270
- .mapping(ddl.mappings ? ddl.mappings.map(mapping => ComputedMapping.fromDDL(mapping)) : [])
271
- ;
272
- break;
273
- default:
274
- retVal
275
- .column1(ddl.sourceFieldID1)
276
- .column2(ddl.sourceFieldID2)
277
- ;
278
- }
279
- return retVal;
280
- }
281
-
282
- static fromDDL(ddl: DDL2.MultiTransformationType): ComputedField {
283
- return new ComputedField().fromDDL(ddl);
284
- }
285
-
286
- hash(): string {
287
- return hashSum(this.toDDL());
288
- }
289
-
290
- columns(): string[] {
291
- return this._owner.fieldIDs();
292
- }
293
-
294
- computedField(): DDL2.IField {
295
- switch (this.type()) {
296
- case "=":
297
- let validChildFields = this.validChildFields();
298
- if (validChildFields.length === 0 && this.hasChildren()) {
299
- // Has children but no mappings - include all children by default...
300
- validChildFields = this.children().map((child: DDL2.IField) => {
301
- return new ComputedField()
302
- .owner(this)
303
- .label(child.id)
304
- .type("=")
305
- .column1(child.id)
306
- ;
307
- });
308
- }
309
- return {
310
- ...this._owner.field(this.column1()),
311
- id: this.label(),
312
- children: validChildFields.length ? validChildFields.map(cf => cf.computedField()) : undefined
313
- } as DDL2.IField;
314
- case "*":
315
- case "/":
316
- case "+":
317
- case "-":
318
- case "scale":
319
- return { id: this.label(), type: "number" };
320
- case "template":
321
- return { id: this.label(), type: "string" };
322
- case "map":
323
- return { id: this.label(), type: "object" } as DDL2.IFieldObject;
324
- }
325
- return { id: this.label(), type: "string" };
326
- }
327
-
328
- projection(trim: boolean): (row: object) => object {
329
- const hasComputedFields = this.hasChildFields();
330
- const computedFields = this.validChildFields().map(cf => {
331
- return {
332
- label: cf.label(),
333
- func: cf.computeFunc(trim)
334
- };
335
- });
336
- return (row: object) => {
337
- const retVal = trim && hasComputedFields ? {} : { ...row };
338
- for (const cf of computedFields) {
339
- retVal[cf.label] = cf.func(row);
340
- }
341
- if (trim && hasComputedFields) {
342
- retVal["__lparam"] = row;
343
- }
344
- return retVal;
345
- };
346
- }
347
-
348
- computeFunc(trim: boolean): (row: any) => any {
349
- const column1 = this.column1();
350
- const column2 = this.column2();
351
- switch (this.type()) {
352
- case "=":
353
- if (this.hasChildFields()) {
354
- return (row: object) => {
355
- // TODO Move to function factory ---
356
- const r = row[column1].Row && isArray(row[column1].Row) ? row[column1].Row : row[column1];
357
- return r.map(this.projection(trim));
358
- };
359
- }
360
- return (row: object) => {
361
- return row[column1];
362
- };
363
- case "*":
364
- return (row: any) => {
365
- return +row[column1] * +row[column2];
366
- };
367
- case "/":
368
- return (row: any) => {
369
- return +row[column1] / +row[column2];
370
- };
371
- case "+":
372
- return (row: any) => {
373
- return +row[column1] + +row[column2];
374
- };
375
- case "-":
376
- return (row: any) => {
377
- return +row[column1] - +row[column2];
378
- };
379
- case "scale":
380
- const constValue = this.constValue();
381
- return (row: any) => {
382
- return +row[column1] * constValue;
383
- };
384
- case "template":
385
- const template = this.template();
386
- return (row: any) => {
387
- return Utility.template(template, row);
388
- };
389
- case "map":
390
- const defValue = this.default();
391
- const mappings = {};
392
- for (const mapping of this.mapping()) {
393
- mappings[mapping.value()] = mapping.newValue();
394
- }
395
- return (row: any) => {
396
- return mappings[row[column1]] || defValue;
397
- };
398
- default:
399
- return (row: any) => {
400
- return row[column1];
401
- };
402
- }
403
- }
404
-
405
- // IComputedFieldOwner ---
406
- fieldIDs(): string[] {
407
- const field = (this._owner as ProjectBase).field(this.column1());
408
- if (field) {
409
- switch (field.type) {
410
- case "dataset":
411
- return field.children.map(field => field.id);
412
- case "object":
413
- return Object.keys(field.fields);
414
- }
415
- }
416
- return [];
417
- }
418
-
419
- field(fieldID: string): DDL2.IField | undefined {
420
- const field = (this._owner as ProjectBase).field(this.column1());
421
- if (field) {
422
- switch (field.type) {
423
- case "dataset":
424
- for (const f of field.children) {
425
- if (f.id === fieldID) {
426
- return f;
427
- }
428
- }
429
- break;
430
- case "object":
431
- return field.fields[fieldID];
432
- }
433
- }
434
- return undefined;
435
- }
436
- }
437
- ComputedField.prototype._class += " ComputedField";
438
- // ===========================================================================
439
- export class MultiField extends PropertyExt implements IComputedFieldOwner {
440
- private _owner: IComputedFieldOwner;
441
-
442
- @publish("", "string", "Label")
443
- label: publish<this, string>;
444
- @publish([], "propertyArray", "Multi Fields", null, { autoExpand: ComputedField })
445
- multiFields: publish<this, ComputedField[]>;
446
-
447
- constructor() {
448
- super();
449
- }
450
-
451
- hash() {
452
- return hashSum(this.toDDL());
453
- }
454
-
455
- owner(): IComputedFieldOwner;
456
- owner(_: IComputedFieldOwner): this;
457
- owner(_?: IComputedFieldOwner): IComputedFieldOwner | this {
458
- if (!arguments.length) return this._owner;
459
- this._owner = _;
460
- return this;
461
- }
462
-
463
- valid(): boolean {
464
- return !!this.label() && this.validMultiFields().length > 0;
465
- }
466
-
467
- validate(prefix: string): IActivityError[] {
468
- let retVal: IActivityError[] = [];
469
- for (const cf of this.validMultiFields()) {
470
- retVal = retVal.concat(cf.validate(`${prefix}.computedFields`));
471
- }
472
- return retVal;
473
- }
474
-
475
- toDDL(): DDL2.IMulti {
476
- return {
477
- fieldID: this.label(),
478
- type: "multi",
479
- transformations: this.transformations()
480
- };
481
- }
482
-
483
- fromDDL(ddl: DDL2.IMulti): this {
484
- return this
485
- .label(ddl.fieldID)
486
- .transformations(ddl.transformations)
487
- ;
488
- }
489
-
490
- static fromDDL(ddl: DDL2.IMulti): MultiField {
491
- return new MultiField().fromDDL(ddl);
492
- }
493
-
494
- validMultiFields(): ComputedField[] {
495
- return this.multiFields().filter(computedField => computedField.valid());
496
- }
497
-
498
- transformations(): DDL2.MultiTransformationType[];
499
- transformations(_: DDL2.MultiTransformationType[]): this;
500
- transformations(_?: DDL2.MultiTransformationType[]): DDL2.MultiTransformationType[] | this {
501
- if (!arguments.length) return this.validMultiFields().map(cf => cf.toDDL());
502
- this.multiFields(_.map(transformation => ComputedField.fromDDL(transformation)));
503
- return this;
504
- }
505
-
506
- // IComputedFieldOwner ---
507
- fieldIDs(): string[] {
508
- return this._owner.fieldIDs();
509
- }
510
-
511
- field(fieldID: string): DDL2.IField | null {
512
- return this._owner.field(fieldID);
513
- }
514
- }
515
- MultiField.prototype._class += " MultiField";
516
- // ===========================================================================
517
- export class ProjectBase extends Activity {
518
- static ComputedField = ComputedField;
519
-
520
- _includeLParam = false;
521
- _trim = false;
522
-
523
- @publish([], "propertyArray", "Computed Fields", null, { autoExpand: ComputedField, noDeserialize: true })
524
- computedFields: publish<this, Array<ComputedField | MultiField>>;
525
-
526
- validate(): IActivityError[] {
527
- let retVal: IActivityError[] = [];
528
- for (const cf of this.validComputedFields()) {
529
- retVal = retVal.concat(cf.validate(`${this.classID()}.computedFields`));
530
- }
531
- return retVal;
532
- }
533
-
534
- constructor() {
535
- super();
536
- }
537
-
538
- transformations(): DDL2.ProjectTransformationType[];
539
- transformations(_: DDL2.ProjectTransformationType[]): this;
540
- transformations(_?: DDL2.ProjectTransformationType[]): DDL2.ProjectTransformationType[] | this {
541
- if (!arguments.length) return this.validComputedFields().map(cf => cf.toDDL());
542
- this.computedFields(_.map(transformation => {
543
- switch (transformation.type) {
544
- case "multi":
545
- return MultiField.fromDDL(transformation);
546
- default:
547
- return ComputedField.fromDDL(transformation);
548
- }
549
- }));
550
- return this;
551
- }
552
-
553
- exists(): boolean {
554
- return this.validComputedFields().length > 0;
555
- }
556
-
557
- // IComputedFieldOwner ---
558
- fieldIDs(): string[] {
559
- return this.inFields().map(field => field.id);
560
- }
561
-
562
- field(fieldID: string): DDL2.IField | null {
563
- for (const field of this.inFields()) {
564
- if (field.id === fieldID) {
565
- return field;
566
- }
567
- }
568
- return null;
569
- }
570
- // ---
571
-
572
- clearComputedFields() {
573
- this.computedFields([]);
574
- }
575
-
576
- appendComputedFields(computedFields: [{ label: string, type: ComputedType, column?: string }]): this {
577
- for (const aggregateField of computedFields) {
578
- const aggrField = new ComputedField()
579
- .owner(this)
580
- .label(aggregateField.label)
581
- .type(aggregateField.type)
582
- ;
583
- if (aggregateField.column !== void 0) {
584
- aggrField.column1(aggregateField.column);
585
- }
586
- this.computedFields().push(aggrField);
587
- }
588
- return this;
589
- }
590
-
591
- validComputedFields() {
592
- return this.computedFields().filter(computedField => computedField.valid());
593
- }
594
-
595
- hasComputedFields() {
596
- return this.validComputedFields().length;
597
- }
598
-
599
- computeFields(inFields: ReadonlyArray<DDL2.IField>): () => ReadonlyArray<DDL2.IField> {
600
- if (!this.exists()) return super.computeFields(inFields);
601
- let retVal: DDL2.IField[] = [];
602
- const retValMap: { [key: string]: boolean } = {};
603
- for (const cf of this.validComputedFields()) {
604
- if (cf instanceof MultiField) {
605
- for (const cf2 of cf.validMultiFields()) {
606
- const computedField = cf2.computedField();
607
- retVal.push(computedField);
608
- retValMap[computedField.id] = true;
609
- }
610
- } else {
611
- const computedField = cf.computedField();
612
- retVal.push(computedField);
613
- retValMap[computedField.id] = true;
614
- }
615
- }
616
- if (this._trim && this.hasComputedFields()) {
617
- if (this._includeLParam) {
618
- const computedField = {
619
- id: "__lparam",
620
- type: "object"
621
- } as DDL2.IField;
622
- retVal.push(computedField);
623
- retValMap[computedField.id] = true;
624
- }
625
- } else {
626
- retVal = retVal.concat(inFields.filter(field => !retValMap[field.id]));
627
- }
628
- return () => retVal;
629
- }
630
-
631
- referencedFields(refs: ReferencedFields): void {
632
- super.referencedFields(refs);
633
- const fieldIDs: string[] = [];
634
- for (const cf of this.validComputedFields()) {
635
- if (cf instanceof MultiField) {
636
- for (const cf2 of cf.validMultiFields()) {
637
- fieldIDs.push(cf2.column1());
638
- if (cf2.column2()) {
639
- fieldIDs.push(cf2.column2());
640
- }
641
- }
642
- } else {
643
- if (cf.type() === "template") {
644
- for (const fieldID of Utility.templateFields(cf.template())) {
645
- fieldIDs.push(fieldID);
646
- }
647
- } else {
648
- fieldIDs.push(cf.column1());
649
- if (cf.column2()) {
650
- fieldIDs.push(cf.column2());
651
- }
652
- }
653
- }
654
- }
655
- super.resolveInFields(refs, fieldIDs);
656
- }
657
-
658
- projection(): (row: object) => object {
659
- const trim = this._trim;
660
- const hasComputedFields = this.hasComputedFields();
661
- const computedFields = [];
662
- for (const cf of this.validComputedFields()) {
663
- if (cf instanceof MultiField) {
664
- for (const cf2 of cf.validMultiFields()) {
665
- computedFields.push({
666
- label: cf2.label(),
667
- func: cf2.computeFunc(trim)
668
- });
669
- }
670
- } else {
671
- computedFields.push({
672
- label: cf.label(),
673
- func: cf.computeFunc(trim)
674
- });
675
- }
676
- }
677
- return (row: object) => {
678
- const retVal = trim && hasComputedFields ? {} : { ...row };
679
- for (const cf of computedFields) {
680
- retVal[cf.label] = cf.func(row);
681
- }
682
- if (trim && hasComputedFields) {
683
- if (this._includeLParam) {
684
- retVal["__lparam"] = row;
685
- }
686
- }
687
- return retVal;
688
- };
689
- }
690
-
691
- computeData(): ReadonlyArray<object> {
692
- const data = super.computeData();
693
- if (data.length === 0 || !this.exists()) return data;
694
- return data.map(this.projection());
695
- }
696
- }
697
-
698
- export class Project extends ProjectBase {
699
-
700
- toDDL(): DDL2.IProject {
701
- return {
702
- type: "project",
703
- transformations: this.transformations()
704
- };
705
- }
706
-
707
- fromDDL(ddl: DDL2.IProject): this {
708
- return this.transformations(ddl.transformations);
709
- }
710
-
711
- static fromDDL(ddl: DDL2.IProject): Project {
712
- return new Project().fromDDL(ddl);
713
- }
714
-
715
- hash(more: object = {}): string {
716
- return super.hash({
717
- ddl: this.toDDL(),
718
- ...more
719
- });
720
- }
721
- }
722
- Project.prototype._class += " Project";
723
-
724
- export class Mappings extends ProjectBase {
725
-
726
- constructor() {
727
- super();
728
- this._trim = true;
729
- this._includeLParam = true;
730
- }
731
-
732
- toDDL(): DDL2.IMappings {
733
- return {
734
- type: "mappings",
735
- transformations: this.transformations()
736
- };
737
- }
738
-
739
- fromDDL(_ddl: DDL2.IMappings): this {
740
- const ddl = _ddl || { transformations: [] };
741
- return this
742
- .transformations(ddl.transformations)
743
- ;
744
- }
745
-
746
- static fromDDL(ddl: DDL2.IMappings): Mappings {
747
- return new Mappings().fromDDL(ddl);
748
- }
749
-
750
- hash(more: object = {}): string {
751
- return super.hash({
752
- ddl: this.toDDL(),
753
- ...more
754
- });
755
- }
756
-
757
- referencedFields(refs: ReferencedFields): void {
758
- if (this.hasComputedFields()) {
759
- return super.referencedFields(refs);
760
- }
761
- this.resolveInFields(refs, this.inFields().filter(f => f.id !== "__lparam").map(f => f.id));
762
- }
763
- }
764
- Mappings.prototype._class += " Mappings";
1
+ import { PropertyExt, publish, Utility } from "@hpcc-js/common";
2
+ import { DDL2 } from "@hpcc-js/ddl-shim";
3
+ import { hashSum, isArray } from "@hpcc-js/util";
4
+ import { Activity, IActivityError, ReferencedFields } from "./activity";
5
+
6
+ export class ComputedMapping extends PropertyExt {
7
+ protected _owner: ComputedField;
8
+
9
+ @publish(null, "any", "Compare Value", undefined, {
10
+ validate: (w: ComputedMapping): boolean => (!w.value() && !w.newValue()) || (!!w.value() && !!w.newValue())
11
+ })
12
+ value: publish<this, any>;
13
+ value_valid: () => boolean;
14
+ @publish(null, "any", "New Value", undefined, {
15
+ validate: (w: ComputedMapping): boolean => (!w.value() && !w.newValue()) || (!!w.value() && !!w.newValue())
16
+ })
17
+ newValue: publish<this, any>;
18
+ newValue_valid: () => boolean;
19
+
20
+ validate(prefix: string): IActivityError[] {
21
+ const retVal: IActivityError[] = [];
22
+ if (!this.value_valid()) {
23
+ retVal.push({
24
+ source: `${prefix}.value`,
25
+ msg: `Invalid value: "${this.value()}"`,
26
+ hint: 'expected: "any"'
27
+ });
28
+ }
29
+ if (!this.newValue_valid()) {
30
+ retVal.push({
31
+ source: `${prefix}.newValue`,
32
+ msg: `Invalid value: "${this.newValue()}"`,
33
+ hint: 'expected: "any"'
34
+ });
35
+ }
36
+ return retVal;
37
+ }
38
+
39
+ constructor() {
40
+ super();
41
+ }
42
+
43
+ owner(): ComputedField;
44
+ owner(_: ComputedField): this;
45
+ owner(_?: ComputedField): ComputedField | this {
46
+ if (!arguments.length) return this._owner;
47
+ this._owner = _;
48
+ return this;
49
+ }
50
+
51
+ valid(): boolean {
52
+ return !!this.value() && !!this.newValue();
53
+ }
54
+
55
+ toDDL(): DDL2.IMapMapping {
56
+ return {
57
+ value: this.value(),
58
+ newValue: this.newValue()
59
+ };
60
+ }
61
+
62
+ fromDDL(ddl: DDL2.IMapMapping): this {
63
+ return this
64
+ .value(ddl.value)
65
+ .newValue(ddl.newValue)
66
+ ;
67
+ }
68
+
69
+ static fromDDL(ddl: DDL2.IMapMapping): ComputedMapping {
70
+ return new ComputedMapping().fromDDL(ddl);
71
+ }
72
+ }
73
+ ComputedMapping.prototype._class += " ComputedMapping";
74
+
75
+ export type ComputedType = "=" | "*" | "/" | "+" | "-" | "scale" | "template" | "map";
76
+
77
+ export interface IComputedFieldOwner extends PropertyExt {
78
+ fieldIDs(): string[];
79
+ field(fieldID: string): DDL2.IField | null;
80
+ }
81
+
82
+ export class ComputedField extends PropertyExt {
83
+ private _owner: IComputedFieldOwner;
84
+
85
+ @publish(null, "string", "Label", null, { optional: true })
86
+ label: publish<this, string>;
87
+ @publish("mapping", "set", "Project type", ["=", "*", "/", "+", "-", "scale", "template", "map"], { optional: true, disable: w => !w.label() })
88
+ type: publish<this, ComputedType>;
89
+ @publish(null, "set", "Param 1", function (this: ComputedField) { return this.columns(); }, {
90
+ optional: true,
91
+ disable: (w: ComputedField) => w.disableColumn1(),
92
+ validate: (w: ComputedField): boolean => w.columns().indexOf(w.column1()) >= 0
93
+ })
94
+ column1: publish<this, string>;
95
+ column1_valid: () => boolean;
96
+ @publish(null, "set", "Param 2", function (this: ComputedField) { return this.columns(); }, {
97
+ optional: true,
98
+ disable: (w: ComputedField) => w.disableColumn2(),
99
+ validate: (w: ComputedField): boolean => w.columns().indexOf(w.column2()) >= 0
100
+ })
101
+ column2: publish<this, string>;
102
+ column2_valid: () => boolean;
103
+ @publish(null, "number", "Const value", null, { optional: true, disable: (w: ComputedField) => !w.label() || ["scale"].indexOf(w.type()) < 0 })
104
+ constValue: publish<this, number>;
105
+ @publish(null, "string", "template", null, { optional: true, disable: (w: ComputedField) => !w.label() || ["template"].indexOf(w.type()) < 0 })
106
+ template: publish<this, string>;
107
+ @publish(null, "any", "Default Value", null, { optional: true, disable: (w: ComputedField) => !w.label() || ["map"].indexOf(w.type()) < 0 })
108
+ default: publish<this, any>;
109
+ @publish([], "propertyArray", "Mapped Values", null, { autoExpand: ComputedMapping, disable: (w: ComputedField) => w.disableMapping() })
110
+ mapping: publish<this, ComputedMapping[]>;
111
+ @publish([], "propertyArray", "Child Fields", null, { autoExpand: ComputedField, disable: (w: ComputedField) => w.disableChildField() })
112
+ childField: publish<this, ComputedField[]>;
113
+
114
+ disableColumn1(): boolean {
115
+ return !this.label() || ["=", "*", "/", "+", "-", "scale", "map"].indexOf(this.type()) < 0;
116
+ }
117
+
118
+ disableColumn2(): boolean {
119
+ return !this.label() || ["*", "/", "+", "-"].indexOf(this.type()) < 0;
120
+ }
121
+
122
+ disableMapping(): boolean {
123
+ return !this.label() || ["map"].indexOf(this.type()) < 0;
124
+ }
125
+
126
+ disableChildField(): boolean {
127
+ return !this.hasChildren();
128
+ }
129
+
130
+ validate(prefix: string): IActivityError[] {
131
+ const retVal: IActivityError[] = [];
132
+ if (!this.column1_valid()) {
133
+ retVal.push({
134
+ source: `${prefix}.${this.label()}`,
135
+ msg: `Invalid column1: "${this.column1()}"`,
136
+ hint: `expected: ${JSON.stringify(this.columns())}`
137
+ });
138
+ }
139
+ if (!this.column2_valid()) {
140
+ retVal.push({
141
+ source: `${prefix}.${this.label()}`,
142
+ msg: `Invalid column2: "${this.column2()}"`,
143
+ hint: `expected: ${JSON.stringify(this.columns())}`
144
+ });
145
+ }
146
+ if (!this.disableMapping()) {
147
+ this.validComputedMappings().forEach(cm => cm.validate(`${prefix}.mapping`));
148
+ }
149
+ if (!this.disableChildField()) {
150
+ this.validChildFields().forEach(cf => cf.validate(`${prefix}.childField`));
151
+ }
152
+ return retVal;
153
+ }
154
+
155
+ hasChildren() {
156
+ if (!this.label()) return false;
157
+ if (this.type() !== "=") return false;
158
+ if (!this.column1()) return false;
159
+ const field = (this._owner as ProjectBase).field(this.column1());
160
+ if (field && field.type === "dataset" && field.children) {
161
+ return true;
162
+ }
163
+ return false;
164
+ }
165
+
166
+ children(): DDL2.IField[] {
167
+ const field = (this._owner as ProjectBase).field(this.column1());
168
+ if (field && field.type === "dataset") {
169
+ return field.children;
170
+ }
171
+ return [];
172
+ }
173
+
174
+ constructor() {
175
+ super();
176
+ }
177
+
178
+ owner(): IComputedFieldOwner;
179
+ owner(_: IComputedFieldOwner): this;
180
+ owner(_?: IComputedFieldOwner): IComputedFieldOwner | this {
181
+ if (!arguments.length) return this._owner;
182
+ this._owner = _;
183
+ return this;
184
+ }
185
+
186
+ valid(): boolean {
187
+ return !!this.label();
188
+ }
189
+
190
+ validComputedMappings(): ComputedMapping[] {
191
+ return this.mapping().filter(cf => cf.valid());
192
+ }
193
+
194
+ validChildFields() {
195
+ return this.childField().filter(cf => cf.valid());
196
+ }
197
+
198
+ hasChildFields() {
199
+ return this.validChildFields().length;
200
+ }
201
+
202
+ toDDL(): DDL2.MultiTransformationType {
203
+ switch (this.type()) {
204
+ case "scale":
205
+ return {
206
+ fieldID: this.label(),
207
+ type: "scale",
208
+ sourceFieldID: this.column1(),
209
+ factor: this.constValue()
210
+ };
211
+ case "template":
212
+ return {
213
+ fieldID: this.label(),
214
+ type: "template",
215
+ template: this.template()
216
+ };
217
+ case "=":
218
+ const transformations = this.validChildFields().map(cf => cf.toDDL());
219
+ return {
220
+ fieldID: this.label(),
221
+ type: "=",
222
+ sourceFieldID: this.column1(),
223
+ transformations: transformations.length ? transformations : undefined
224
+ };
225
+ case "map":
226
+ return {
227
+ fieldID: this.label(),
228
+ type: "map",
229
+ sourceFieldID: this.column1(),
230
+ default: this.default(),
231
+ mappings: this.validComputedMappings().map(cm => cm.toDDL())
232
+ };
233
+ default:
234
+ return {
235
+ fieldID: this.label(),
236
+ type: this.type() as DDL2.ICalculatedType,
237
+ sourceFieldID1: this.column1(),
238
+ sourceFieldID2: this.column2()
239
+ };
240
+ }
241
+ }
242
+
243
+ fromDDL(ddl: DDL2.MultiTransformationType): this {
244
+ const retVal = this
245
+ .label(ddl.fieldID)
246
+ .type(ddl.type)
247
+ ;
248
+ switch (ddl.type) {
249
+ case "scale":
250
+ retVal
251
+ .column1(ddl.sourceFieldID)
252
+ .constValue(ddl.factor)
253
+ ;
254
+ break;
255
+ case "template":
256
+ retVal
257
+ .template(ddl.template)
258
+ ;
259
+ break;
260
+ case "=":
261
+ retVal
262
+ .column1(ddl.sourceFieldID)
263
+ .childField(ddl.transformations ? ddl.transformations.map(transformation => ComputedField.fromDDL(transformation)) : [])
264
+ ;
265
+ break;
266
+ case "map":
267
+ retVal
268
+ .column1(ddl.sourceFieldID)
269
+ .default(ddl.default)
270
+ .mapping(ddl.mappings ? ddl.mappings.map(mapping => ComputedMapping.fromDDL(mapping)) : [])
271
+ ;
272
+ break;
273
+ default:
274
+ retVal
275
+ .column1(ddl.sourceFieldID1)
276
+ .column2(ddl.sourceFieldID2)
277
+ ;
278
+ }
279
+ return retVal;
280
+ }
281
+
282
+ static fromDDL(ddl: DDL2.MultiTransformationType): ComputedField {
283
+ return new ComputedField().fromDDL(ddl);
284
+ }
285
+
286
+ hash(): string {
287
+ return hashSum(this.toDDL());
288
+ }
289
+
290
+ columns(): string[] {
291
+ return this._owner.fieldIDs();
292
+ }
293
+
294
+ computedField(): DDL2.IField {
295
+ switch (this.type()) {
296
+ case "=":
297
+ let validChildFields = this.validChildFields();
298
+ if (validChildFields.length === 0 && this.hasChildren()) {
299
+ // Has children but no mappings - include all children by default...
300
+ validChildFields = this.children().map((child: DDL2.IField) => {
301
+ return new ComputedField()
302
+ .owner(this)
303
+ .label(child.id)
304
+ .type("=")
305
+ .column1(child.id)
306
+ ;
307
+ });
308
+ }
309
+ return {
310
+ ...this._owner.field(this.column1()),
311
+ id: this.label(),
312
+ children: validChildFields.length ? validChildFields.map(cf => cf.computedField()) : undefined
313
+ } as DDL2.IField;
314
+ case "*":
315
+ case "/":
316
+ case "+":
317
+ case "-":
318
+ case "scale":
319
+ return { id: this.label(), type: "number" };
320
+ case "template":
321
+ return { id: this.label(), type: "string" };
322
+ case "map":
323
+ return { id: this.label(), type: "object" } as DDL2.IFieldObject;
324
+ }
325
+ return { id: this.label(), type: "string" };
326
+ }
327
+
328
+ projection(trim: boolean): (row: object) => object {
329
+ const hasComputedFields = this.hasChildFields();
330
+ const computedFields = this.validChildFields().map(cf => {
331
+ return {
332
+ label: cf.label(),
333
+ func: cf.computeFunc(trim)
334
+ };
335
+ });
336
+ return (row: object) => {
337
+ const retVal = trim && hasComputedFields ? {} : { ...row };
338
+ for (const cf of computedFields) {
339
+ retVal[cf.label] = cf.func(row);
340
+ }
341
+ if (trim && hasComputedFields) {
342
+ retVal["__lparam"] = row;
343
+ }
344
+ return retVal;
345
+ };
346
+ }
347
+
348
+ computeFunc(trim: boolean): (row: any) => any {
349
+ const column1 = this.column1();
350
+ const column2 = this.column2();
351
+ switch (this.type()) {
352
+ case "=":
353
+ if (this.hasChildFields()) {
354
+ return (row: object) => {
355
+ // TODO Move to function factory ---
356
+ const r = row[column1].Row && isArray(row[column1].Row) ? row[column1].Row : row[column1];
357
+ return r.map(this.projection(trim));
358
+ };
359
+ }
360
+ return (row: object) => {
361
+ return row[column1];
362
+ };
363
+ case "*":
364
+ return (row: any) => {
365
+ return +row[column1] * +row[column2];
366
+ };
367
+ case "/":
368
+ return (row: any) => {
369
+ return +row[column1] / +row[column2];
370
+ };
371
+ case "+":
372
+ return (row: any) => {
373
+ return +row[column1] + +row[column2];
374
+ };
375
+ case "-":
376
+ return (row: any) => {
377
+ return +row[column1] - +row[column2];
378
+ };
379
+ case "scale":
380
+ const constValue = this.constValue();
381
+ return (row: any) => {
382
+ return +row[column1] * constValue;
383
+ };
384
+ case "template":
385
+ const template = this.template();
386
+ return (row: any) => {
387
+ return Utility.template(template, row);
388
+ };
389
+ case "map":
390
+ const defValue = this.default();
391
+ const mappings = {};
392
+ for (const mapping of this.mapping()) {
393
+ mappings[mapping.value()] = mapping.newValue();
394
+ }
395
+ return (row: any) => {
396
+ return mappings[row[column1]] || defValue;
397
+ };
398
+ default:
399
+ return (row: any) => {
400
+ return row[column1];
401
+ };
402
+ }
403
+ }
404
+
405
+ // IComputedFieldOwner ---
406
+ fieldIDs(): string[] {
407
+ const field = (this._owner as ProjectBase).field(this.column1());
408
+ if (field) {
409
+ switch (field.type) {
410
+ case "dataset":
411
+ return field.children.map(field => field.id);
412
+ case "object":
413
+ return Object.keys(field.fields);
414
+ }
415
+ }
416
+ return [];
417
+ }
418
+
419
+ field(fieldID: string): DDL2.IField | undefined {
420
+ const field = (this._owner as ProjectBase).field(this.column1());
421
+ if (field) {
422
+ switch (field.type) {
423
+ case "dataset":
424
+ for (const f of field.children) {
425
+ if (f.id === fieldID) {
426
+ return f;
427
+ }
428
+ }
429
+ break;
430
+ case "object":
431
+ return field.fields[fieldID];
432
+ }
433
+ }
434
+ return undefined;
435
+ }
436
+ }
437
+ ComputedField.prototype._class += " ComputedField";
438
+ // ===========================================================================
439
+ export class MultiField extends PropertyExt implements IComputedFieldOwner {
440
+ private _owner: IComputedFieldOwner;
441
+
442
+ @publish("", "string", "Label")
443
+ label: publish<this, string>;
444
+ @publish([], "propertyArray", "Multi Fields", null, { autoExpand: ComputedField })
445
+ multiFields: publish<this, ComputedField[]>;
446
+
447
+ constructor() {
448
+ super();
449
+ }
450
+
451
+ hash() {
452
+ return hashSum(this.toDDL());
453
+ }
454
+
455
+ owner(): IComputedFieldOwner;
456
+ owner(_: IComputedFieldOwner): this;
457
+ owner(_?: IComputedFieldOwner): IComputedFieldOwner | this {
458
+ if (!arguments.length) return this._owner;
459
+ this._owner = _;
460
+ return this;
461
+ }
462
+
463
+ valid(): boolean {
464
+ return !!this.label() && this.validMultiFields().length > 0;
465
+ }
466
+
467
+ validate(prefix: string): IActivityError[] {
468
+ let retVal: IActivityError[] = [];
469
+ for (const cf of this.validMultiFields()) {
470
+ retVal = retVal.concat(cf.validate(`${prefix}.computedFields`));
471
+ }
472
+ return retVal;
473
+ }
474
+
475
+ toDDL(): DDL2.IMulti {
476
+ return {
477
+ fieldID: this.label(),
478
+ type: "multi",
479
+ transformations: this.transformations()
480
+ };
481
+ }
482
+
483
+ fromDDL(ddl: DDL2.IMulti): this {
484
+ return this
485
+ .label(ddl.fieldID)
486
+ .transformations(ddl.transformations)
487
+ ;
488
+ }
489
+
490
+ static fromDDL(ddl: DDL2.IMulti): MultiField {
491
+ return new MultiField().fromDDL(ddl);
492
+ }
493
+
494
+ validMultiFields(): ComputedField[] {
495
+ return this.multiFields().filter(computedField => computedField.valid());
496
+ }
497
+
498
+ transformations(): DDL2.MultiTransformationType[];
499
+ transformations(_: DDL2.MultiTransformationType[]): this;
500
+ transformations(_?: DDL2.MultiTransformationType[]): DDL2.MultiTransformationType[] | this {
501
+ if (!arguments.length) return this.validMultiFields().map(cf => cf.toDDL());
502
+ this.multiFields(_.map(transformation => ComputedField.fromDDL(transformation)));
503
+ return this;
504
+ }
505
+
506
+ // IComputedFieldOwner ---
507
+ fieldIDs(): string[] {
508
+ return this._owner.fieldIDs();
509
+ }
510
+
511
+ field(fieldID: string): DDL2.IField | null {
512
+ return this._owner.field(fieldID);
513
+ }
514
+ }
515
+ MultiField.prototype._class += " MultiField";
516
+ // ===========================================================================
517
+ export class ProjectBase extends Activity {
518
+ static ComputedField = ComputedField;
519
+
520
+ _includeLParam = false;
521
+ _trim = false;
522
+
523
+ @publish([], "propertyArray", "Computed Fields", null, { autoExpand: ComputedField, noDeserialize: true })
524
+ computedFields: publish<this, Array<ComputedField | MultiField>>;
525
+
526
+ validate(): IActivityError[] {
527
+ let retVal: IActivityError[] = [];
528
+ for (const cf of this.validComputedFields()) {
529
+ retVal = retVal.concat(cf.validate(`${this.classID()}.computedFields`));
530
+ }
531
+ return retVal;
532
+ }
533
+
534
+ constructor() {
535
+ super();
536
+ }
537
+
538
+ transformations(): DDL2.ProjectTransformationType[];
539
+ transformations(_: DDL2.ProjectTransformationType[]): this;
540
+ transformations(_?: DDL2.ProjectTransformationType[]): DDL2.ProjectTransformationType[] | this {
541
+ if (!arguments.length) return this.validComputedFields().map(cf => cf.toDDL());
542
+ this.computedFields(_.map(transformation => {
543
+ switch (transformation.type) {
544
+ case "multi":
545
+ return MultiField.fromDDL(transformation);
546
+ default:
547
+ return ComputedField.fromDDL(transformation);
548
+ }
549
+ }));
550
+ return this;
551
+ }
552
+
553
+ exists(): boolean {
554
+ return this.validComputedFields().length > 0;
555
+ }
556
+
557
+ // IComputedFieldOwner ---
558
+ fieldIDs(): string[] {
559
+ return this.inFields().map(field => field.id);
560
+ }
561
+
562
+ field(fieldID: string): DDL2.IField | null {
563
+ for (const field of this.inFields()) {
564
+ if (field.id === fieldID) {
565
+ return field;
566
+ }
567
+ }
568
+ return null;
569
+ }
570
+ // ---
571
+
572
+ clearComputedFields() {
573
+ this.computedFields([]);
574
+ }
575
+
576
+ appendComputedFields(computedFields: [{ label: string, type: ComputedType, column?: string }]): this {
577
+ for (const aggregateField of computedFields) {
578
+ const aggrField = new ComputedField()
579
+ .owner(this)
580
+ .label(aggregateField.label)
581
+ .type(aggregateField.type)
582
+ ;
583
+ if (aggregateField.column !== void 0) {
584
+ aggrField.column1(aggregateField.column);
585
+ }
586
+ this.computedFields().push(aggrField);
587
+ }
588
+ return this;
589
+ }
590
+
591
+ validComputedFields() {
592
+ return this.computedFields().filter(computedField => computedField.valid());
593
+ }
594
+
595
+ hasComputedFields() {
596
+ return this.validComputedFields().length;
597
+ }
598
+
599
+ computeFields(inFields: ReadonlyArray<DDL2.IField>): () => ReadonlyArray<DDL2.IField> {
600
+ if (!this.exists()) return super.computeFields(inFields);
601
+ let retVal: DDL2.IField[] = [];
602
+ const retValMap: { [key: string]: boolean } = {};
603
+ for (const cf of this.validComputedFields()) {
604
+ if (cf instanceof MultiField) {
605
+ for (const cf2 of cf.validMultiFields()) {
606
+ const computedField = cf2.computedField();
607
+ retVal.push(computedField);
608
+ retValMap[computedField.id] = true;
609
+ }
610
+ } else {
611
+ const computedField = cf.computedField();
612
+ retVal.push(computedField);
613
+ retValMap[computedField.id] = true;
614
+ }
615
+ }
616
+ if (this._trim && this.hasComputedFields()) {
617
+ if (this._includeLParam) {
618
+ const computedField = {
619
+ id: "__lparam",
620
+ type: "object"
621
+ } as DDL2.IField;
622
+ retVal.push(computedField);
623
+ retValMap[computedField.id] = true;
624
+ }
625
+ } else {
626
+ retVal = retVal.concat(inFields.filter(field => !retValMap[field.id]));
627
+ }
628
+ return () => retVal;
629
+ }
630
+
631
+ referencedFields(refs: ReferencedFields): void {
632
+ super.referencedFields(refs);
633
+ const fieldIDs: string[] = [];
634
+ for (const cf of this.validComputedFields()) {
635
+ if (cf instanceof MultiField) {
636
+ for (const cf2 of cf.validMultiFields()) {
637
+ fieldIDs.push(cf2.column1());
638
+ if (cf2.column2()) {
639
+ fieldIDs.push(cf2.column2());
640
+ }
641
+ }
642
+ } else {
643
+ if (cf.type() === "template") {
644
+ for (const fieldID of Utility.templateFields(cf.template())) {
645
+ fieldIDs.push(fieldID);
646
+ }
647
+ } else {
648
+ fieldIDs.push(cf.column1());
649
+ if (cf.column2()) {
650
+ fieldIDs.push(cf.column2());
651
+ }
652
+ }
653
+ }
654
+ }
655
+ super.resolveInFields(refs, fieldIDs);
656
+ }
657
+
658
+ projection(): (row: object) => object {
659
+ const trim = this._trim;
660
+ const hasComputedFields = this.hasComputedFields();
661
+ const computedFields = [];
662
+ for (const cf of this.validComputedFields()) {
663
+ if (cf instanceof MultiField) {
664
+ for (const cf2 of cf.validMultiFields()) {
665
+ computedFields.push({
666
+ label: cf2.label(),
667
+ func: cf2.computeFunc(trim)
668
+ });
669
+ }
670
+ } else {
671
+ computedFields.push({
672
+ label: cf.label(),
673
+ func: cf.computeFunc(trim)
674
+ });
675
+ }
676
+ }
677
+ return (row: object) => {
678
+ const retVal = trim && hasComputedFields ? {} : { ...row };
679
+ for (const cf of computedFields) {
680
+ retVal[cf.label] = cf.func(row);
681
+ }
682
+ if (trim && hasComputedFields) {
683
+ if (this._includeLParam) {
684
+ retVal["__lparam"] = row;
685
+ }
686
+ }
687
+ return retVal;
688
+ };
689
+ }
690
+
691
+ computeData(): ReadonlyArray<object> {
692
+ const data = super.computeData();
693
+ if (data.length === 0 || !this.exists()) return data;
694
+ return data.map(this.projection());
695
+ }
696
+ }
697
+
698
+ export class Project extends ProjectBase {
699
+
700
+ toDDL(): DDL2.IProject {
701
+ return {
702
+ type: "project",
703
+ transformations: this.transformations()
704
+ };
705
+ }
706
+
707
+ fromDDL(ddl: DDL2.IProject): this {
708
+ return this.transformations(ddl.transformations);
709
+ }
710
+
711
+ static fromDDL(ddl: DDL2.IProject): Project {
712
+ return new Project().fromDDL(ddl);
713
+ }
714
+
715
+ hash(more: object = {}): string {
716
+ return super.hash({
717
+ ddl: this.toDDL(),
718
+ ...more
719
+ });
720
+ }
721
+ }
722
+ Project.prototype._class += " Project";
723
+
724
+ export class Mappings extends ProjectBase {
725
+
726
+ constructor() {
727
+ super();
728
+ this._trim = true;
729
+ this._includeLParam = true;
730
+ }
731
+
732
+ toDDL(): DDL2.IMappings {
733
+ return {
734
+ type: "mappings",
735
+ transformations: this.transformations()
736
+ };
737
+ }
738
+
739
+ fromDDL(_ddl: DDL2.IMappings): this {
740
+ const ddl = _ddl || { transformations: [] };
741
+ return this
742
+ .transformations(ddl.transformations)
743
+ ;
744
+ }
745
+
746
+ static fromDDL(ddl: DDL2.IMappings): Mappings {
747
+ return new Mappings().fromDDL(ddl);
748
+ }
749
+
750
+ hash(more: object = {}): string {
751
+ return super.hash({
752
+ ddl: this.toDDL(),
753
+ ...more
754
+ });
755
+ }
756
+
757
+ referencedFields(refs: ReferencedFields): void {
758
+ if (this.hasComputedFields()) {
759
+ return super.referencedFields(refs);
760
+ }
761
+ this.resolveInFields(refs, this.inFields().filter(f => f.id !== "__lparam").map(f => f.id));
762
+ }
763
+ }
764
+ Mappings.prototype._class += " Mappings";