agentlang 0.7.9 → 0.7.11
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/out/api/http.d.ts.map +1 -1
- package/out/api/http.js +8 -1
- package/out/api/http.js.map +1 -1
- package/out/cli/main.d.ts.map +1 -1
- package/out/cli/main.js +33 -2
- package/out/cli/main.js.map +1 -1
- package/out/extension/main.cjs +250 -250
- package/out/extension/main.cjs.map +2 -2
- package/out/language/agentlang-validator.d.ts +1 -2
- package/out/language/agentlang-validator.d.ts.map +1 -1
- package/out/language/agentlang-validator.js +0 -39
- package/out/language/agentlang-validator.js.map +1 -1
- package/out/language/generated/ast.d.ts +62 -11
- package/out/language/generated/ast.d.ts.map +1 -1
- package/out/language/generated/ast.js +75 -3
- package/out/language/generated/ast.js.map +1 -1
- package/out/language/generated/grammar.d.ts.map +1 -1
- package/out/language/generated/grammar.js +758 -239
- package/out/language/generated/grammar.js.map +1 -1
- package/out/language/main.cjs +1370 -824
- package/out/language/main.cjs.map +4 -4
- package/out/language/parser.d.ts +1 -0
- package/out/language/parser.d.ts.map +1 -1
- package/out/language/parser.js +44 -7
- package/out/language/parser.js.map +1 -1
- package/out/language/syntax.d.ts +1 -1
- package/out/language/syntax.d.ts.map +1 -1
- package/out/language/syntax.js +22 -13
- package/out/language/syntax.js.map +1 -1
- package/out/runtime/api.d.ts +2 -0
- package/out/runtime/api.d.ts.map +1 -1
- package/out/runtime/api.js +5 -0
- package/out/runtime/api.js.map +1 -1
- package/out/runtime/auth/cognito.d.ts.map +1 -1
- package/out/runtime/auth/cognito.js +4 -4
- package/out/runtime/auth/cognito.js.map +1 -1
- package/out/runtime/defs.d.ts +5 -0
- package/out/runtime/defs.d.ts.map +1 -1
- package/out/runtime/defs.js +16 -0
- package/out/runtime/defs.js.map +1 -1
- package/out/runtime/exec-graph.js +1 -1
- package/out/runtime/exec-graph.js.map +1 -1
- package/out/runtime/interpreter.d.ts +6 -1
- package/out/runtime/interpreter.d.ts.map +1 -1
- package/out/runtime/interpreter.js +144 -112
- package/out/runtime/interpreter.js.map +1 -1
- package/out/runtime/loader.d.ts +1 -1
- package/out/runtime/loader.d.ts.map +1 -1
- package/out/runtime/loader.js +74 -27
- package/out/runtime/loader.js.map +1 -1
- package/out/runtime/module.d.ts +41 -11
- package/out/runtime/module.d.ts.map +1 -1
- package/out/runtime/module.js +238 -50
- package/out/runtime/module.js.map +1 -1
- package/out/runtime/modules/ai.d.ts.map +1 -1
- package/out/runtime/modules/ai.js +13 -6
- package/out/runtime/modules/ai.js.map +1 -1
- package/out/runtime/modules/auth.d.ts +2 -1
- package/out/runtime/modules/auth.d.ts.map +1 -1
- package/out/runtime/modules/auth.js +93 -3
- package/out/runtime/modules/auth.js.map +1 -1
- package/out/runtime/modules/core.d.ts +7 -5
- package/out/runtime/modules/core.d.ts.map +1 -1
- package/out/runtime/modules/core.js +93 -16
- package/out/runtime/modules/core.js.map +1 -1
- package/out/runtime/monitor.d.ts.map +1 -1
- package/out/runtime/monitor.js +1 -0
- package/out/runtime/monitor.js.map +1 -1
- package/out/runtime/resolvers/interface.d.ts +6 -1
- package/out/runtime/resolvers/interface.d.ts.map +1 -1
- package/out/runtime/resolvers/interface.js +2 -2
- package/out/runtime/resolvers/interface.js.map +1 -1
- package/out/runtime/resolvers/sqldb/database.d.ts +19 -2
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/database.js +107 -21
- package/out/runtime/resolvers/sqldb/database.js.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.d.ts +1 -0
- package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/dbutil.js +25 -3
- package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.d.ts +3 -2
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
- package/out/runtime/resolvers/sqldb/impl.js +80 -6
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
- package/out/runtime/state.d.ts +58 -0
- package/out/runtime/state.d.ts.map +1 -1
- package/out/runtime/state.js +12 -0
- package/out/runtime/state.js.map +1 -1
- package/out/runtime/util.d.ts +1 -1
- package/out/runtime/util.d.ts.map +1 -1
- package/out/runtime/util.js +27 -13
- package/out/runtime/util.js.map +1 -1
- package/out/setupClassic.d.ts +98 -0
- package/out/setupClassic.d.ts.map +1 -0
- package/out/setupClassic.js +38 -0
- package/out/setupClassic.js.map +1 -0
- package/out/setupCommon.d.ts +2 -0
- package/out/setupCommon.d.ts.map +1 -0
- package/out/setupCommon.js +33 -0
- package/out/setupCommon.js.map +1 -0
- package/out/setupExtended.d.ts +40 -0
- package/out/setupExtended.d.ts.map +1 -0
- package/out/setupExtended.js +67 -0
- package/out/setupExtended.js.map +1 -0
- package/out/syntaxes/agentlang.monarch.js +1 -1
- package/out/syntaxes/agentlang.monarch.js.map +1 -1
- package/package.json +187 -185
- package/src/api/http.ts +8 -0
- package/src/cli/main.ts +38 -2
- package/src/language/agentlang-validator.ts +1 -51
- package/src/language/agentlang.langium +17 -4
- package/src/language/generated/ast.ts +147 -13
- package/src/language/generated/grammar.ts +758 -239
- package/src/language/parser.ts +43 -8
- package/src/language/syntax.ts +25 -12
- package/src/runtime/api.ts +8 -0
- package/src/runtime/defs.ts +8 -0
- package/src/runtime/interpreter.ts +104 -76
- package/src/runtime/loader.ts +75 -25
- package/src/runtime/module.ts +194 -32
- package/src/runtime/modules/ai.ts +10 -4
- package/src/runtime/modules/auth.ts +1 -0
- package/src/runtime/modules/core.ts +99 -23
- package/src/runtime/monitor.ts +1 -0
- package/src/runtime/resolvers/interface.ts +9 -2
- package/src/runtime/resolvers/sqldb/database.ts +68 -17
- package/src/runtime/resolvers/sqldb/dbutil.ts +28 -6
- package/src/runtime/resolvers/sqldb/impl.ts +86 -14
- package/src/runtime/state.ts +14 -0
- package/src/runtime/util.ts +25 -12
- package/src/syntaxes/agentlang.monarch.ts +1 -1
package/src/language/parser.ts
CHANGED
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
Statement,
|
|
34
34
|
WorkflowDefinition,
|
|
35
35
|
} from './generated/ast.js';
|
|
36
|
-
import { firstAliasSpec, firstCatchSpec, QuerySuffix } from '../runtime/util.js';
|
|
36
|
+
import { firstAliasSpec, firstCatchSpec, isString, QuerySuffix } from '../runtime/util.js';
|
|
37
37
|
import {
|
|
38
38
|
BasePattern,
|
|
39
39
|
CrudPattern,
|
|
@@ -291,7 +291,7 @@ function introspectPattern(pat: Pattern): BasePattern {
|
|
|
291
291
|
|
|
292
292
|
function introspectInto(intoSpec: SelectIntoSpec, p: CrudPattern): CrudPattern {
|
|
293
293
|
intoSpec.entries.forEach((se: SelectIntoEntry) => {
|
|
294
|
-
p.addInto(se.alias, se.attribute);
|
|
294
|
+
if (se.attribute) p.addInto(se.alias, se.attribute);
|
|
295
295
|
});
|
|
296
296
|
return p;
|
|
297
297
|
}
|
|
@@ -340,12 +340,14 @@ function introspectPrimExpr(expr: PrimExpr): BasePattern {
|
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
-
function introspectExpression(expr: Expr |
|
|
344
|
-
if (
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
343
|
+
function introspectExpression(expr: Expr | undefined): BasePattern {
|
|
344
|
+
if (expr !== undefined) {
|
|
345
|
+
if (isPrimExpr(expr)) {
|
|
346
|
+
return introspectPrimExpr(expr);
|
|
347
|
+
}
|
|
348
|
+
if (expr.$cstNode) {
|
|
349
|
+
return new ExpressionPattern(expr.$cstNode.text);
|
|
350
|
+
}
|
|
349
351
|
}
|
|
350
352
|
throw new Error('Failed to introspect expression - ' + expr);
|
|
351
353
|
}
|
|
@@ -507,3 +509,36 @@ export function canParse(s: string): boolean {
|
|
|
507
509
|
}
|
|
508
510
|
return false;
|
|
509
511
|
}
|
|
512
|
+
|
|
513
|
+
export function objectToQueryPattern(obj: any): string {
|
|
514
|
+
const strs = new Array<string>();
|
|
515
|
+
Object.keys(obj).forEach((k: string) => {
|
|
516
|
+
if (k.startsWith('@')) {
|
|
517
|
+
const xs: any = obj[k];
|
|
518
|
+
if (k.endsWith('join')) {
|
|
519
|
+
xs.forEach((x: any[]) => {
|
|
520
|
+
strs.push(`${k} ${x[0]} ${objectToQuerySpecPattern(x[1], true)}`);
|
|
521
|
+
});
|
|
522
|
+
} else if (k === '@groupBy' || k === '@orderBy') {
|
|
523
|
+
strs.push(`${k} ( ${xs.join(', ')} )`);
|
|
524
|
+
} else {
|
|
525
|
+
strs.push(`${k} ${objectToQuerySpecPattern(xs, true)}`);
|
|
526
|
+
}
|
|
527
|
+
} else {
|
|
528
|
+
strs.push(`${k} ${objectToQuerySpecPattern(obj[k])}`);
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
return `{${strs.join(',\n')}}`;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function objectToQuerySpecPattern(obj: any, refMode: boolean = false): string {
|
|
535
|
+
const strs = new Array<string>();
|
|
536
|
+
Object.keys(obj).forEach((k: string) => {
|
|
537
|
+
let v = obj[k];
|
|
538
|
+
if (!refMode && isString(v) && !v.startsWith('@')) {
|
|
539
|
+
v = `"${v}"`;
|
|
540
|
+
}
|
|
541
|
+
strs.push(`${k} ${v}`);
|
|
542
|
+
});
|
|
543
|
+
return `{${strs.join(', ')}}`;
|
|
544
|
+
}
|
package/src/language/syntax.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { parseHelper } from 'langium/test';
|
|
2
2
|
import { escapeQueryName, trimQuotes } from '../runtime/util.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
FlowEntry,
|
|
5
|
+
isDecisionDefinition,
|
|
6
|
+
isFlowDefinition,
|
|
7
|
+
ModuleDefinition,
|
|
8
|
+
} from './generated/ast.js';
|
|
4
9
|
import { createAgentlangServices } from './agentlang-module.js';
|
|
5
10
|
import { EmptyFileSystem } from 'langium';
|
|
6
11
|
import { introspect, parseModule } from './parser.js';
|
|
@@ -811,18 +816,26 @@ export class FlowStepPattern extends BasePattern {
|
|
|
811
816
|
this.condition = condition ? trimQuotes(condition) : undefined;
|
|
812
817
|
}
|
|
813
818
|
|
|
814
|
-
static Parse(s: string): FlowStepPattern {
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
819
|
+
static async Parse(s: string): Promise<FlowStepPattern> {
|
|
820
|
+
const p = await parseModule(`module Temp
|
|
821
|
+
flow tempFlow {
|
|
822
|
+
${s}
|
|
823
|
+
}`);
|
|
824
|
+
let result: FlowStepPattern | undefined;
|
|
825
|
+
const d = p.defs[0];
|
|
826
|
+
if (isFlowDefinition(d)) {
|
|
827
|
+
d.body?.entries.forEach((fe: FlowEntry) => {
|
|
828
|
+
if (fe.cond) {
|
|
829
|
+
result = new FlowStepPattern(fe.root, fe.cond.next.$cstNode?.text || '', fe.cond.expr);
|
|
830
|
+
} else {
|
|
831
|
+
result = new FlowStepPattern(fe.root, fe.next?.$cstNode?.text || '');
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
if (result !== undefined) {
|
|
836
|
+
return result;
|
|
825
837
|
}
|
|
838
|
+
throw new Error(`Failed to parse flow-step - ${s}`);
|
|
826
839
|
}
|
|
827
840
|
|
|
828
841
|
override toString(): string {
|
package/src/runtime/api.ts
CHANGED
|
@@ -4,11 +4,14 @@ import {
|
|
|
4
4
|
isInstanceOfType as al_isInstanceOfType,
|
|
5
5
|
} from './module.js';
|
|
6
6
|
import { getLocalEnv as al_getLocalEnv, setLocalEnv as al_setLocalEnv } from './auth/defs.js';
|
|
7
|
+
import { now } from './util.js';
|
|
7
8
|
|
|
8
9
|
declare global {
|
|
9
10
|
var agentlang: any | undefined;
|
|
10
11
|
function getLocalEnv(k: string, defaultValue?: string): string | undefined;
|
|
11
12
|
function setLocalEnv(k: string, v: string): string;
|
|
13
|
+
function uuid(): string;
|
|
14
|
+
function now(): string;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
let ApiInited = false;
|
|
@@ -20,6 +23,11 @@ export function initGlobalApi() {
|
|
|
20
23
|
globalThis.agentlang.isInstanceOfType = al_isInstanceOfType;
|
|
21
24
|
globalThis.agentlang.fetchConfig = al_fetchConfig;
|
|
22
25
|
|
|
26
|
+
globalThis.uuid = () => {
|
|
27
|
+
return crypto.randomUUID();
|
|
28
|
+
};
|
|
29
|
+
globalThis.now = now;
|
|
30
|
+
|
|
23
31
|
// Expose environment variable functions globally (like readSecret pattern)
|
|
24
32
|
globalThis.getLocalEnv = al_getLocalEnv;
|
|
25
33
|
globalThis.setLocalEnv = al_setLocalEnv;
|
package/src/runtime/defs.ts
CHANGED
|
@@ -419,6 +419,7 @@ export function isRuntimeMode_undo_migration(): boolean {
|
|
|
419
419
|
|
|
420
420
|
let UpdateEventEndpoints: Function | undefined;
|
|
421
421
|
let UpdateEntityEndpoints: Function | undefined;
|
|
422
|
+
let UpdateRelationshipEndpoints: Function | undefined;
|
|
422
423
|
|
|
423
424
|
export function setEventEndpointsUpdater(f: Function) {
|
|
424
425
|
UpdateEventEndpoints = f;
|
|
@@ -428,6 +429,10 @@ export function setEntityEndpointsUpdater(f: Function) {
|
|
|
428
429
|
UpdateEntityEndpoints = f;
|
|
429
430
|
}
|
|
430
431
|
|
|
432
|
+
export function setRelationshipEndpointsUpdater(f: Function) {
|
|
433
|
+
UpdateRelationshipEndpoints = f;
|
|
434
|
+
}
|
|
435
|
+
|
|
431
436
|
export function updateEndpoints(moduleName: string) {
|
|
432
437
|
if (UpdateEventEndpoints !== undefined) {
|
|
433
438
|
UpdateEventEndpoints(moduleName);
|
|
@@ -435,6 +440,9 @@ export function updateEndpoints(moduleName: string) {
|
|
|
435
440
|
if (UpdateEntityEndpoints !== undefined) {
|
|
436
441
|
UpdateEntityEndpoints(moduleName);
|
|
437
442
|
}
|
|
443
|
+
if (UpdateRelationshipEndpoints !== undefined) {
|
|
444
|
+
UpdateRelationshipEndpoints(moduleName);
|
|
445
|
+
}
|
|
438
446
|
}
|
|
439
447
|
|
|
440
448
|
export let InternDynamicModule: Function | undefined;
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
SetAttribute,
|
|
29
29
|
Statement,
|
|
30
30
|
ThrowError,
|
|
31
|
+
WhereSpec,
|
|
31
32
|
} from '../language/generated/ast.js';
|
|
32
33
|
import {
|
|
33
34
|
maybeInstanceAsString,
|
|
@@ -52,7 +53,7 @@ import {
|
|
|
52
53
|
Workflow,
|
|
53
54
|
setMetaAttributes,
|
|
54
55
|
} from './module.js';
|
|
55
|
-
import { JoinInfo, Resolver } from './resolvers/interface.js';
|
|
56
|
+
import { JoinInfo, Resolver, WhereClause } from './resolvers/interface.js';
|
|
56
57
|
import { ResolverAuthInfo } from './resolvers/authinfo.js';
|
|
57
58
|
import { SqlDbResolver } from './resolvers/sqldb/impl.js';
|
|
58
59
|
import {
|
|
@@ -97,8 +98,7 @@ import {
|
|
|
97
98
|
addUpdateAudit,
|
|
98
99
|
createSuspension,
|
|
99
100
|
flushMonitoringData,
|
|
100
|
-
|
|
101
|
-
setTimerRunning,
|
|
101
|
+
triggerTimer,
|
|
102
102
|
} from './modules/core.js';
|
|
103
103
|
import { invokeModuleFn } from './jsmodules.js';
|
|
104
104
|
import { invokeOpenApiEvent, isOpenApiEventInstance } from './openapi.js';
|
|
@@ -106,6 +106,7 @@ import { fetchDoc } from './docs.js';
|
|
|
106
106
|
import { FlowSpec, FlowStep, getAgentFlow } from './agents/flows.js';
|
|
107
107
|
import { isMonitoringEnabled } from './state.js';
|
|
108
108
|
import { Monitor, MonitorEntry } from './monitor.js';
|
|
109
|
+
import { detailedDiff } from 'deep-object-diff';
|
|
109
110
|
|
|
110
111
|
export type Result = any;
|
|
111
112
|
|
|
@@ -1341,6 +1342,11 @@ async function lookupOneOfVals(fqName: string, env: Environment): Promise<Instan
|
|
|
1341
1342
|
return await parseAndEvaluateStatement(`{${fqName}? {}}`, undefined, env);
|
|
1342
1343
|
}
|
|
1343
1344
|
|
|
1345
|
+
export type AggregateFunctionCall = {
|
|
1346
|
+
name: string;
|
|
1347
|
+
args: string[];
|
|
1348
|
+
};
|
|
1349
|
+
|
|
1344
1350
|
async function patternToInstance(
|
|
1345
1351
|
entryName: string,
|
|
1346
1352
|
attributes: SetAttribute[] | undefined,
|
|
@@ -1349,6 +1355,7 @@ async function patternToInstance(
|
|
|
1349
1355
|
const attrs: InstanceAttributes = newInstanceAttributes();
|
|
1350
1356
|
let qattrs: InstanceAttributes | undefined;
|
|
1351
1357
|
let qattrVals: InstanceAttributes | undefined;
|
|
1358
|
+
let aggregates: Map<string, AggregateFunctionCall> | undefined;
|
|
1352
1359
|
const isQueryAll: boolean = entryName.endsWith(QuerySuffix);
|
|
1353
1360
|
if (isQueryAll) {
|
|
1354
1361
|
entryName = entryName.slice(0, entryName.length - 1);
|
|
@@ -1356,20 +1363,25 @@ async function patternToInstance(
|
|
|
1356
1363
|
if (attributes) {
|
|
1357
1364
|
for (let i = 0; i < attributes.length; ++i) {
|
|
1358
1365
|
const a: SetAttribute = attributes[i];
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
if (
|
|
1364
|
-
|
|
1366
|
+
if (a.value !== undefined) {
|
|
1367
|
+
await evaluateExpression(a.value, env);
|
|
1368
|
+
const v: Result = env.getLastResult();
|
|
1369
|
+
let aname: string = a.name;
|
|
1370
|
+
if (aname.endsWith(QuerySuffix)) {
|
|
1371
|
+
if (isQueryAll) {
|
|
1372
|
+
throw new Error(`Cannot specifiy query attribute ${aname} here`);
|
|
1373
|
+
}
|
|
1374
|
+
if (qattrs === undefined) qattrs = newInstanceAttributes();
|
|
1375
|
+
if (qattrVals === undefined) qattrVals = newInstanceAttributes();
|
|
1376
|
+
aname = aname.slice(0, aname.length - 1);
|
|
1377
|
+
qattrs.set(aname, a.op === undefined ? '=' : a.op);
|
|
1378
|
+
qattrVals.set(aname, v);
|
|
1379
|
+
} else {
|
|
1380
|
+
attrs.set(aname, v);
|
|
1365
1381
|
}
|
|
1366
|
-
|
|
1367
|
-
if (
|
|
1368
|
-
|
|
1369
|
-
qattrs.set(aname, a.op === undefined ? '=' : a.op);
|
|
1370
|
-
qattrVals.set(aname, v);
|
|
1371
|
-
} else {
|
|
1372
|
-
attrs.set(aname, v);
|
|
1382
|
+
} else if (a.aggregate !== undefined) {
|
|
1383
|
+
if (aggregates === undefined) aggregates = new Map<string, AggregateFunctionCall>();
|
|
1384
|
+
aggregates.set(escapeQueryName(a.name), { name: a.aggregate.name, args: a.aggregate.args });
|
|
1373
1385
|
}
|
|
1374
1386
|
}
|
|
1375
1387
|
}
|
|
@@ -1379,7 +1391,11 @@ async function patternToInstance(
|
|
|
1379
1391
|
if (p.hasModule()) moduleName = p.getModuleName();
|
|
1380
1392
|
if (p.hasEntry()) entryName = p.getEntryName();
|
|
1381
1393
|
}
|
|
1382
|
-
|
|
1394
|
+
const inst = makeInstance(moduleName, entryName, attrs, qattrs, qattrVals, isQueryAll);
|
|
1395
|
+
if (aggregates !== undefined) {
|
|
1396
|
+
return inst.setAggregates(aggregates);
|
|
1397
|
+
}
|
|
1398
|
+
return inst;
|
|
1383
1399
|
}
|
|
1384
1400
|
|
|
1385
1401
|
async function instanceFromSource(crud: CrudMap, env: Environment): Promise<Instance> {
|
|
@@ -1431,6 +1447,15 @@ async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
|
1431
1447
|
}
|
|
1432
1448
|
}
|
|
1433
1449
|
|
|
1450
|
+
function maybeSetQueryClauses(inst: Instance, crud: CrudMap) {
|
|
1451
|
+
if (crud.groupByClause) {
|
|
1452
|
+
inst.setGroupBy(crud.groupByClause.colNames);
|
|
1453
|
+
}
|
|
1454
|
+
if (crud.orderByClause) {
|
|
1455
|
+
inst.setOrderBy(crud.orderByClause.colNames, crud.orderByClause.order === '@desc');
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1434
1459
|
async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
1435
1460
|
if (!env.isInUpsertMode() && crud.upsert.length > 0) {
|
|
1436
1461
|
return await evaluateUpsert(crud, env);
|
|
@@ -1442,8 +1467,10 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1442
1467
|
const moduleName = inst.moduleName;
|
|
1443
1468
|
const attrs = inst.attributes;
|
|
1444
1469
|
const qattrs = inst.queryAttributes;
|
|
1445
|
-
const
|
|
1470
|
+
const onlyAggregates = inst.aggregates !== undefined && qattrs === undefined;
|
|
1471
|
+
const isQueryAll = onlyAggregates || crud.name.endsWith(QuerySuffix);
|
|
1446
1472
|
const distinct: boolean = crud.distinct.length > 0;
|
|
1473
|
+
maybeSetQueryClauses(inst, crud);
|
|
1447
1474
|
if (attrs.size > 0) {
|
|
1448
1475
|
await maybeValidateOneOfRefs(inst, env);
|
|
1449
1476
|
}
|
|
@@ -1456,8 +1483,8 @@ async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
|
1456
1483
|
if (qattrs === undefined && !isQueryAll) {
|
|
1457
1484
|
throw new Error(`Pattern for ${entryName} with 'into' clause must be a query`);
|
|
1458
1485
|
}
|
|
1459
|
-
if (crud.
|
|
1460
|
-
await evaluateJoinQuery(crud.
|
|
1486
|
+
if (crud.joins.length > 0) {
|
|
1487
|
+
await evaluateJoinQuery(crud.joins, crud.into, crud.where, inst, distinct, env);
|
|
1461
1488
|
} else {
|
|
1462
1489
|
await evaluateJoinQueryWithRelationships(crud.into, inst, crud.relationships, distinct, env);
|
|
1463
1490
|
}
|
|
@@ -1671,51 +1698,6 @@ async function handleDocEvent(inst: Instance, env: Environment): Promise<void> {
|
|
|
1671
1698
|
}
|
|
1672
1699
|
}
|
|
1673
1700
|
|
|
1674
|
-
function triggerTimer(timerInst: Instance): Instance {
|
|
1675
|
-
const dur = timerInst.lookup('duration');
|
|
1676
|
-
const unit = timerInst.lookup('unit');
|
|
1677
|
-
let millisecs = 0;
|
|
1678
|
-
switch (unit) {
|
|
1679
|
-
case 'millisecond': {
|
|
1680
|
-
millisecs = dur;
|
|
1681
|
-
break;
|
|
1682
|
-
}
|
|
1683
|
-
case 'second': {
|
|
1684
|
-
millisecs = dur * 1000;
|
|
1685
|
-
break;
|
|
1686
|
-
}
|
|
1687
|
-
case 'minute': {
|
|
1688
|
-
millisecs = dur * 60 * 1000;
|
|
1689
|
-
break;
|
|
1690
|
-
}
|
|
1691
|
-
case 'hour': {
|
|
1692
|
-
millisecs = dur * 60 * 60 * 1000;
|
|
1693
|
-
break;
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
|
-
const eventName = nameToPath(timerInst.lookup('trigger'));
|
|
1697
|
-
const m = eventName.hasModule() ? eventName.getModuleName() : timerInst.moduleName;
|
|
1698
|
-
const n = eventName.getEntryName();
|
|
1699
|
-
const inst = makeInstance(m, n, newInstanceAttributes());
|
|
1700
|
-
const name = timerInst.lookup('name');
|
|
1701
|
-
const timer = setInterval(async () => {
|
|
1702
|
-
const env = new Environment();
|
|
1703
|
-
try {
|
|
1704
|
-
await evaluate(
|
|
1705
|
-
inst,
|
|
1706
|
-
(result: Result) => logger.debug(`Timer ${name} ran with result ${result}`),
|
|
1707
|
-
env
|
|
1708
|
-
);
|
|
1709
|
-
await env.commitAllTransactions();
|
|
1710
|
-
await maybeCancelTimer(name, timer, env);
|
|
1711
|
-
} catch (reason: any) {
|
|
1712
|
-
logger.error(`Timer ${name} raised error: ${reason}`);
|
|
1713
|
-
}
|
|
1714
|
-
}, millisecs);
|
|
1715
|
-
setTimerRunning(timerInst);
|
|
1716
|
-
return timerInst;
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
1701
|
async function computeExprAttributes(
|
|
1720
1702
|
inst: Instance,
|
|
1721
1703
|
origAttrs: SetAttribute[] | undefined,
|
|
@@ -1749,7 +1731,7 @@ async function computeExprAttributes(
|
|
|
1749
1731
|
for (let i = 0; i < origAttrs.length; ++i) {
|
|
1750
1732
|
const a: SetAttribute = origAttrs[i];
|
|
1751
1733
|
const n = a.name;
|
|
1752
|
-
if (!n.endsWith(QuerySuffix) && updatedAttrs.has(n)) {
|
|
1734
|
+
if (!n.endsWith(QuerySuffix) && updatedAttrs.has(n) && a.value !== undefined) {
|
|
1753
1735
|
await evaluateExpression(a.value, newEnv);
|
|
1754
1736
|
const v: Result = newEnv.getLastResult();
|
|
1755
1737
|
updatedAttrs.set(n, v);
|
|
@@ -1760,19 +1742,51 @@ async function computeExprAttributes(
|
|
|
1760
1742
|
}
|
|
1761
1743
|
}
|
|
1762
1744
|
|
|
1745
|
+
async function evalWhereClauses(whereSpec: WhereSpec, env: Environment): Promise<WhereClause[]> {
|
|
1746
|
+
const result = new Array<WhereClause>();
|
|
1747
|
+
const e = new Environment(undefined, env);
|
|
1748
|
+
for (let i = 0; i < whereSpec.clauses.length; ++i) {
|
|
1749
|
+
const c = whereSpec.clauses[i];
|
|
1750
|
+
await evaluateExpression(c.rhs, e);
|
|
1751
|
+
result.push({
|
|
1752
|
+
attrName: escapeQueryName(c.lhs),
|
|
1753
|
+
op: c.op === undefined ? '=' : c.op,
|
|
1754
|
+
qval: e.getLastResult(),
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
return result;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1763
1760
|
async function evaluateJoinQuery(
|
|
1764
|
-
joinSpec: JoinSpec,
|
|
1761
|
+
joinSpec: JoinSpec[],
|
|
1765
1762
|
intoSpec: SelectIntoSpec,
|
|
1763
|
+
whereSpec: WhereSpec | undefined,
|
|
1766
1764
|
inst: Instance,
|
|
1767
1765
|
distinct: boolean,
|
|
1768
1766
|
env: Environment
|
|
1769
1767
|
): Promise<void> {
|
|
1770
1768
|
const normIntoSpec = new Map<string, string>();
|
|
1769
|
+
let aggregates: Map<string, AggregateFunctionCall> | undefined;
|
|
1771
1770
|
intoSpec.entries.forEach((entry: SelectIntoEntry) => {
|
|
1772
|
-
normIntoSpec.set(entry.alias, entry.attribute);
|
|
1771
|
+
if (entry.attribute !== undefined) normIntoSpec.set(entry.alias, entry.attribute);
|
|
1772
|
+
else {
|
|
1773
|
+
if (aggregates === undefined) aggregates = new Map<string, AggregateFunctionCall>();
|
|
1774
|
+
if (entry.aggregate !== undefined) aggregates?.set(entry.alias, entry.aggregate);
|
|
1775
|
+
}
|
|
1773
1776
|
});
|
|
1777
|
+
if (aggregates !== undefined) {
|
|
1778
|
+
inst.setAggregates(aggregates);
|
|
1779
|
+
}
|
|
1780
|
+
const clauses = whereSpec ? await evalWhereClauses(whereSpec, env) : undefined;
|
|
1774
1781
|
const resolver = await getResolverForPath(inst.name, inst.moduleName, env);
|
|
1775
|
-
const result: Result = await resolver.queryByJoin(
|
|
1782
|
+
const result: Result = await resolver.queryByJoin(
|
|
1783
|
+
inst,
|
|
1784
|
+
[],
|
|
1785
|
+
normIntoSpec,
|
|
1786
|
+
distinct,
|
|
1787
|
+
joinSpec,
|
|
1788
|
+
clauses
|
|
1789
|
+
);
|
|
1776
1790
|
|
|
1777
1791
|
const transformedResult = transformDateFieldsInJoinResult(result);
|
|
1778
1792
|
|
|
@@ -1787,9 +1801,17 @@ async function evaluateJoinQueryWithRelationships(
|
|
|
1787
1801
|
env: Environment
|
|
1788
1802
|
): Promise<void> {
|
|
1789
1803
|
const normIntoSpec = new Map<string, string>();
|
|
1804
|
+
let aggregates: Map<string, AggregateFunctionCall> | undefined;
|
|
1790
1805
|
intoSpec.entries.forEach((entry: SelectIntoEntry) => {
|
|
1791
|
-
normIntoSpec.set(entry.alias, entry.attribute);
|
|
1806
|
+
if (entry.attribute !== undefined) normIntoSpec.set(entry.alias, entry.attribute);
|
|
1807
|
+
else {
|
|
1808
|
+
if (aggregates === undefined) aggregates = new Map<string, AggregateFunctionCall>();
|
|
1809
|
+
if (entry.aggregate !== undefined) aggregates?.set(entry.alias, entry.aggregate);
|
|
1810
|
+
}
|
|
1792
1811
|
});
|
|
1812
|
+
if (aggregates !== undefined) {
|
|
1813
|
+
inst.setAggregates(aggregates);
|
|
1814
|
+
}
|
|
1793
1815
|
const moduleName = inst.moduleName;
|
|
1794
1816
|
let joinsSpec = new Array<JoinInfo>();
|
|
1795
1817
|
for (let i = 0; i < relationships.length; ++i) {
|
|
@@ -2126,7 +2148,7 @@ async function preprocessStep(spec: string, env: Environment): Promise<string> {
|
|
|
2126
2148
|
const step = crudMap.name;
|
|
2127
2149
|
if (crudMap.body) {
|
|
2128
2150
|
crudMap.body.attributes.forEach((sa: SetAttribute) => {
|
|
2129
|
-
const v = sa.value
|
|
2151
|
+
const v = sa.value?.$cstNode?.text;
|
|
2130
2152
|
if (v) env.setTemplateMapping(sa.name, v);
|
|
2131
2153
|
});
|
|
2132
2154
|
}
|
|
@@ -2202,7 +2224,7 @@ export async function maybeDeleteQueriedInstances(
|
|
|
2202
2224
|
const inst: Instance[] | Instance = queryEnv.getLastResult();
|
|
2203
2225
|
let resolver: Resolver = Resolver.Default;
|
|
2204
2226
|
if (inst instanceof Array) {
|
|
2205
|
-
if (inst.length > 0
|
|
2227
|
+
if (inst.length > 0) {
|
|
2206
2228
|
resolver = await getResolverForPath(inst[0].name, inst[0].moduleName, queryEnv);
|
|
2207
2229
|
const finalResult: Array<any> = new Array<any>();
|
|
2208
2230
|
for (let i = 0; i < inst.length; ++i) {
|
|
@@ -2215,7 +2237,7 @@ export async function maybeDeleteQueriedInstances(
|
|
|
2215
2237
|
} else {
|
|
2216
2238
|
queryEnv.setLastResult(inst);
|
|
2217
2239
|
}
|
|
2218
|
-
} else
|
|
2240
|
+
} else {
|
|
2219
2241
|
resolver = await getResolverForPath(inst.name, inst.moduleName, queryEnv);
|
|
2220
2242
|
await runPreDeleteEvents(inst, env);
|
|
2221
2243
|
const r: Instance | null = await resolver.deleteInstance(inst, purge);
|
|
@@ -2479,7 +2501,7 @@ async function runPreCreateEvents(inst: Instance, env: Environment) {
|
|
|
2479
2501
|
|
|
2480
2502
|
export async function runPostCreateEvents(inst: Instance, env: Environment) {
|
|
2481
2503
|
if (inst.requireAudit()) {
|
|
2482
|
-
await addCreateAudit(inst.getPath(), env);
|
|
2504
|
+
await addCreateAudit(inst.getPath(), env, { original: inst.userAttributesAsObject() });
|
|
2483
2505
|
}
|
|
2484
2506
|
await runPrePostEvents(CrudType.CREATE, false, inst, env);
|
|
2485
2507
|
}
|
|
@@ -2494,7 +2516,13 @@ export async function runPostUpdateEvents(
|
|
|
2494
2516
|
env: Environment
|
|
2495
2517
|
) {
|
|
2496
2518
|
if (inst.requireAudit()) {
|
|
2497
|
-
|
|
2519
|
+
let diff: object | undefined;
|
|
2520
|
+
if (oldInst !== undefined) {
|
|
2521
|
+
const oldAttrs = oldInst.userAttributesAsObject();
|
|
2522
|
+
const d = detailedDiff(oldAttrs, inst.userAttributesAsObject());
|
|
2523
|
+
diff = { original: oldAttrs, updated: d.updated };
|
|
2524
|
+
}
|
|
2525
|
+
await addUpdateAudit(inst.getPath(), diff, env);
|
|
2498
2526
|
}
|
|
2499
2527
|
await runPrePostEvents(CrudType.UPDATE, false, inst, env);
|
|
2500
2528
|
}
|
|
@@ -2505,7 +2533,7 @@ async function runPreDeleteEvents(inst: Instance, env: Environment) {
|
|
|
2505
2533
|
|
|
2506
2534
|
export async function runPostDeleteEvents(inst: Instance, env: Environment) {
|
|
2507
2535
|
if (inst.requireAudit()) {
|
|
2508
|
-
await addDeleteAudit(inst.getPath(), inst, env);
|
|
2536
|
+
await addDeleteAudit(inst.getPath(), { deleted: inst.userAttributesAsObject() }, env);
|
|
2509
2537
|
}
|
|
2510
2538
|
await runPrePostEvents(CrudType.DELETE, false, inst, env);
|
|
2511
2539
|
}
|
package/src/runtime/loader.ts
CHANGED
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
addAgent,
|
|
70
70
|
fetchModule,
|
|
71
71
|
Retry,
|
|
72
|
+
addGlobalRetry,
|
|
72
73
|
} from './module.js';
|
|
73
74
|
import {
|
|
74
75
|
asStringLiteralsMap,
|
|
@@ -81,6 +82,7 @@ import {
|
|
|
81
82
|
preprocessRawConfig,
|
|
82
83
|
registerInitFunction,
|
|
83
84
|
rootRef,
|
|
85
|
+
ScratchModuleName,
|
|
84
86
|
} from './util.js';
|
|
85
87
|
import { getFileSystem, toFsPath, readFile, readdir, exists } from '../utils/fs-utils.js';
|
|
86
88
|
import { URI } from 'vscode-uri';
|
|
@@ -348,10 +350,14 @@ async function evaluateConfigPatterns(cfgPats: string): Promise<any> {
|
|
|
348
350
|
const wf = await parseWorkflow(cfgWf);
|
|
349
351
|
const cfgStmts = new Array<Statement>();
|
|
350
352
|
const initInsts = new Array<Statement>();
|
|
353
|
+
const deleted = new Set<string>();
|
|
351
354
|
for (let i = 0; i < wf.statements.length; ++i) {
|
|
352
355
|
const stmt: Statement = wf.statements[i];
|
|
353
356
|
if (stmt.pattern.crudMap) {
|
|
354
|
-
|
|
357
|
+
if (!deleted.has(stmt.pattern.crudMap?.name)) {
|
|
358
|
+
initInsts.push(await makeDeleteAllConfigStatement(stmt.pattern.crudMap));
|
|
359
|
+
deleted.add(stmt.pattern.crudMap.name);
|
|
360
|
+
}
|
|
355
361
|
initInsts.push(stmt);
|
|
356
362
|
} else {
|
|
357
363
|
cfgStmts.push(stmt);
|
|
@@ -377,20 +383,37 @@ async function evaluateConfigPatterns(cfgPats: string): Promise<any> {
|
|
|
377
383
|
return undefined;
|
|
378
384
|
}
|
|
379
385
|
|
|
380
|
-
|
|
386
|
+
function isStringContent(content: string): boolean {
|
|
387
|
+
return content.includes('{');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export async function loadAppConfig(configDirOrContent: string): Promise<Config> {
|
|
391
|
+
const stringContent = isStringContent(configDirOrContent);
|
|
392
|
+
|
|
381
393
|
let cfgObj: any = undefined;
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const
|
|
386
|
-
if (
|
|
387
|
-
|
|
394
|
+
|
|
395
|
+
if (!stringContent) {
|
|
396
|
+
const fs = await getFileSystem();
|
|
397
|
+
const alCfgFile = `${configDirOrContent}${path.sep}config.al`;
|
|
398
|
+
if (await fs.exists(alCfgFile)) {
|
|
399
|
+
configDirOrContent = await fs.readFile(alCfgFile);
|
|
388
400
|
}
|
|
389
401
|
}
|
|
402
|
+
|
|
403
|
+
if (canParse(configDirOrContent)) {
|
|
404
|
+
cfgObj = await evaluateConfigPatterns(configDirOrContent);
|
|
405
|
+
}
|
|
406
|
+
|
|
390
407
|
try {
|
|
391
|
-
|
|
408
|
+
let cfg = cfgObj
|
|
392
409
|
? await configFromObject(cfgObj)
|
|
393
|
-
: await loadRawConfig(`${
|
|
410
|
+
: await loadRawConfig(`${configDirOrContent}${path.sep}app.config.json`);
|
|
411
|
+
|
|
412
|
+
const envAppConfig = typeof process !== 'undefined' ? process.env.APP_CONFIG : undefined;
|
|
413
|
+
if (envAppConfig) {
|
|
414
|
+
const envConfig = JSON.parse(envAppConfig);
|
|
415
|
+
cfg = { ...cfg, ...envConfig };
|
|
416
|
+
}
|
|
394
417
|
return setAppConfig(cfg);
|
|
395
418
|
} catch (err: any) {
|
|
396
419
|
if (err instanceof z.ZodError) {
|
|
@@ -891,7 +914,7 @@ function addFlowDefinition(def: FlowDefinition, moduleName: string) {
|
|
|
891
914
|
f = sdef;
|
|
892
915
|
}
|
|
893
916
|
}
|
|
894
|
-
m.addFlow(def.name,
|
|
917
|
+
m.addFlow(def.name, def);
|
|
895
918
|
registerFlow(`${moduleName}/${def.name}`, f);
|
|
896
919
|
}
|
|
897
920
|
|
|
@@ -1161,6 +1184,7 @@ export async function internModule(
|
|
|
1161
1184
|
// Process imports sequentially to ensure all JS modules are loaded before definitions
|
|
1162
1185
|
for (const imp of module.imports as Import[]) {
|
|
1163
1186
|
await importModule(imp.path, imp.name, moduleFileName);
|
|
1187
|
+
r.addImport({ name: imp.name, path: imp.path });
|
|
1164
1188
|
}
|
|
1165
1189
|
for (let i = 0; i < module.defs.length; ++i) {
|
|
1166
1190
|
const def = module.defs[i];
|
|
@@ -1186,31 +1210,57 @@ export async function loadRawConfig(
|
|
|
1186
1210
|
}
|
|
1187
1211
|
}
|
|
1188
1212
|
|
|
1189
|
-
function filterConfigEntityInstances(rawConfig: any): [any,
|
|
1190
|
-
|
|
1191
|
-
const insts = new
|
|
1192
|
-
Object.
|
|
1193
|
-
|
|
1194
|
-
insts.set(key, value);
|
|
1195
|
-
} else {
|
|
1196
|
-
cfg.set(key, value);
|
|
1197
|
-
}
|
|
1213
|
+
function filterConfigEntityInstances(rawConfig: any): [any, Array<any>] {
|
|
1214
|
+
let cfg: any = undefined;
|
|
1215
|
+
const insts = new Array<any>();
|
|
1216
|
+
const oldFormat = Object.keys(rawConfig).some((k: string) => {
|
|
1217
|
+
return k === 'store' || k === 'service';
|
|
1198
1218
|
});
|
|
1199
|
-
|
|
1219
|
+
const newFormat = !oldFormat;
|
|
1220
|
+
if (newFormat) {
|
|
1221
|
+
Object.entries(rawConfig).forEach(([key, value]: [string, any]) => {
|
|
1222
|
+
if (key === 'agentlang') {
|
|
1223
|
+
cfg = value;
|
|
1224
|
+
} else {
|
|
1225
|
+
if (value instanceof Array) {
|
|
1226
|
+
value.forEach((v: any) => {
|
|
1227
|
+
insts.push(v);
|
|
1228
|
+
});
|
|
1229
|
+
} else {
|
|
1230
|
+
insts.push(value);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
if (cfg === undefined) cfg = {};
|
|
1235
|
+
return [cfg, insts];
|
|
1236
|
+
} else {
|
|
1237
|
+
return [rawConfig, insts];
|
|
1238
|
+
}
|
|
1200
1239
|
}
|
|
1201
1240
|
|
|
1202
1241
|
async function configFromObject(cfgObj: any, validate: boolean = true): Promise<any> {
|
|
1203
1242
|
const rawConfig = preprocessRawConfig(cfgObj);
|
|
1204
|
-
if (validate) {
|
|
1243
|
+
if (validate && rawConfig) {
|
|
1205
1244
|
const [cfg, insts] = filterConfigEntityInstances(rawConfig);
|
|
1206
1245
|
const pats = new Array<string>();
|
|
1207
|
-
insts.forEach((v: any
|
|
1208
|
-
|
|
1246
|
+
insts.forEach((v: any) => {
|
|
1247
|
+
const n = Object.keys(v)[0];
|
|
1248
|
+
const attrs = v[n];
|
|
1249
|
+
pats.push(`{${n} ${objectAsString(attrs)}}`);
|
|
1209
1250
|
});
|
|
1210
1251
|
if (pats.length > 0) {
|
|
1211
1252
|
await evaluateConfigPatterns(pats.join('\n'));
|
|
1212
1253
|
}
|
|
1213
|
-
|
|
1254
|
+
const result = ConfigSchema.parse(cfg);
|
|
1255
|
+
cfg.retry?.forEach((r: any) => {
|
|
1256
|
+
const retry: Retry = new Retry(r.name, ScratchModuleName, r.attempts)
|
|
1257
|
+
.setBackoffDelay(r.backoff.delay)
|
|
1258
|
+
.setBackoffFactor(r.backoff.factor)
|
|
1259
|
+
.setBackoffStrategy(r.backoff.strategy[0])
|
|
1260
|
+
.setBackoffMagnitude(r.backoff.magnitude);
|
|
1261
|
+
addGlobalRetry(retry);
|
|
1262
|
+
});
|
|
1263
|
+
return result;
|
|
1214
1264
|
}
|
|
1215
1265
|
return rawConfig;
|
|
1216
1266
|
}
|