agentlang 0.0.2
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/LICENSE +83 -0
- package/README.md +120 -0
- package/bin/cli.js +4 -0
- package/out/api/http.d.ts +3 -0
- package/out/api/http.d.ts.map +1 -0
- package/out/api/http.js +290 -0
- package/out/api/http.js.map +1 -0
- package/out/cli/cli-util.d.ts +7 -0
- package/out/cli/cli-util.d.ts.map +1 -0
- package/out/cli/cli-util.js +9 -0
- package/out/cli/cli-util.js.map +1 -0
- package/out/cli/docs.d.ts +2 -0
- package/out/cli/docs.d.ts.map +1 -0
- package/out/cli/docs.js +236 -0
- package/out/cli/docs.js.map +1 -0
- package/out/cli/main.d.ts +288 -0
- package/out/cli/main.d.ts.map +1 -0
- package/out/cli/main.js +119 -0
- package/out/cli/main.js.map +1 -0
- package/out/cli/openapi-docs.yml +695 -0
- package/out/extension/main.cjs +18093 -0
- package/out/extension/main.cjs.map +7 -0
- package/out/extension/main.d.ts +4 -0
- package/out/extension/main.d.ts.map +1 -0
- package/out/extension/main.js +42 -0
- package/out/extension/main.js.map +1 -0
- package/out/language/agentlang-module.d.ts +42 -0
- package/out/language/agentlang-module.d.ts.map +1 -0
- package/out/language/agentlang-module.js +42 -0
- package/out/language/agentlang-module.js.map +1 -0
- package/out/language/agentlang-validator.d.ts +15 -0
- package/out/language/agentlang-validator.d.ts.map +1 -0
- package/out/language/agentlang-validator.js +50 -0
- package/out/language/agentlang-validator.js.map +1 -0
- package/out/language/generated/ast.d.ts +491 -0
- package/out/language/generated/ast.d.ts.map +1 -0
- package/out/language/generated/ast.js +934 -0
- package/out/language/generated/ast.js.map +1 -0
- package/out/language/generated/grammar.d.ts +7 -0
- package/out/language/generated/grammar.d.ts.map +1 -0
- package/out/language/generated/grammar.js +4475 -0
- package/out/language/generated/grammar.js.map +1 -0
- package/out/language/generated/module.d.ts +14 -0
- package/out/language/generated/module.d.ts.map +1 -0
- package/out/language/generated/module.js +21 -0
- package/out/language/generated/module.js.map +1 -0
- package/out/language/main-browser.d.ts +2 -0
- package/out/language/main-browser.d.ts.map +1 -0
- package/out/language/main-browser.js +10 -0
- package/out/language/main-browser.js.map +1 -0
- package/out/language/main.cjs +36229 -0
- package/out/language/main.cjs.map +7 -0
- package/out/language/main.d.ts +2 -0
- package/out/language/main.d.ts.map +1 -0
- package/out/language/main.js +11 -0
- package/out/language/main.js.map +1 -0
- package/out/language/parser.d.ts +9 -0
- package/out/language/parser.d.ts.map +1 -0
- package/out/language/parser.js +273 -0
- package/out/language/parser.js.map +1 -0
- package/out/language/syntax.d.ts +155 -0
- package/out/language/syntax.d.ts.map +1 -0
- package/out/language/syntax.js +527 -0
- package/out/language/syntax.js.map +1 -0
- package/out/runtime/agents/common.d.ts +2 -0
- package/out/runtime/agents/common.d.ts.map +1 -0
- package/out/runtime/agents/common.js +178 -0
- package/out/runtime/agents/common.js.map +1 -0
- package/out/runtime/agents/impl/openai.d.ts +8 -0
- package/out/runtime/agents/impl/openai.d.ts.map +1 -0
- package/out/runtime/agents/impl/openai.js +15 -0
- package/out/runtime/agents/impl/openai.js.map +1 -0
- package/out/runtime/agents/provider.d.ts +21 -0
- package/out/runtime/agents/provider.d.ts.map +1 -0
- package/out/runtime/agents/provider.js +32 -0
- package/out/runtime/agents/provider.js.map +1 -0
- package/out/runtime/agents/registry.d.ts +2 -0
- package/out/runtime/agents/registry.d.ts.map +1 -0
- package/out/runtime/agents/registry.js +10 -0
- package/out/runtime/agents/registry.js.map +1 -0
- package/out/runtime/auth/cognito.d.ts +16 -0
- package/out/runtime/auth/cognito.d.ts.map +1 -0
- package/out/runtime/auth/cognito.js +186 -0
- package/out/runtime/auth/cognito.js.map +1 -0
- package/out/runtime/auth/defs.d.ts +11 -0
- package/out/runtime/auth/defs.d.ts.map +1 -0
- package/out/runtime/auth/defs.js +24 -0
- package/out/runtime/auth/defs.js.map +1 -0
- package/out/runtime/auth/interface.d.ts +22 -0
- package/out/runtime/auth/interface.d.ts.map +1 -0
- package/out/runtime/auth/interface.js +2 -0
- package/out/runtime/auth/interface.js.map +1 -0
- package/out/runtime/defs.js +24 -0
- package/out/runtime/defs.js.map +1 -0
- package/out/runtime/interpreter.d.ts +69 -0
- package/out/runtime/interpreter.d.ts.map +1 -0
- package/out/runtime/interpreter.js +1163 -0
- package/out/runtime/interpreter.js.map +1 -0
- package/out/runtime/loader.d.ts +25 -0
- package/out/runtime/loader.d.ts.map +1 -0
- package/out/runtime/loader.js +346 -0
- package/out/runtime/loader.js.map +1 -0
- package/out/runtime/logger.d.ts +2 -0
- package/out/runtime/logger.d.ts.map +1 -0
- package/out/runtime/logger.js +44 -0
- package/out/runtime/logger.js.map +1 -0
- package/out/runtime/module.d.ts +273 -0
- package/out/runtime/module.d.ts.map +1 -0
- package/out/runtime/module.js +1786 -0
- package/out/runtime/module.js.map +1 -0
- package/out/runtime/modules/ai.d.ts +26 -0
- package/out/runtime/modules/ai.d.ts.map +1 -0
- package/out/runtime/modules/ai.js +211 -0
- package/out/runtime/modules/ai.js.map +1 -0
- package/out/runtime/modules/auth.d.ts +39 -0
- package/out/runtime/modules/auth.d.ts.map +1 -0
- package/out/runtime/modules/auth.js +359 -0
- package/out/runtime/modules/auth.js.map +1 -0
- package/out/runtime/modules/core.d.ts +2 -0
- package/out/runtime/modules/core.d.ts.map +1 -0
- package/out/runtime/modules/core.js +67 -0
- package/out/runtime/modules/core.js.map +1 -0
- package/out/runtime/relgraph.d.ts +21 -0
- package/out/runtime/relgraph.d.ts.map +1 -0
- package/out/runtime/relgraph.js +156 -0
- package/out/runtime/relgraph.js.map +1 -0
- package/out/runtime/resolvers/interface.d.ts +59 -0
- package/out/runtime/resolvers/interface.d.ts.map +1 -0
- package/out/runtime/resolvers/interface.js +111 -0
- package/out/runtime/resolvers/interface.js.map +1 -0
- package/out/runtime/resolvers/registry.d.ts +8 -0
- package/out/runtime/resolvers/registry.d.ts.map +1 -0
- package/out/runtime/resolvers/registry.js +26 -0
- package/out/runtime/resolvers/registry.js.map +1 -0
- package/out/runtime/resolvers/sqldb/database.d.ts +50 -0
- package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -0
- package/out/runtime/resolvers/sqldb/database.js +618 -0
- package/out/runtime/resolvers/sqldb/database.js.map +1 -0
- package/out/runtime/resolvers/sqldb/dbutil.d.ts +18 -0
- package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -0
- package/out/runtime/resolvers/sqldb/dbutil.js +221 -0
- package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -0
- package/out/runtime/resolvers/sqldb/impl.d.ts +26 -0
- package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -0
- package/out/runtime/resolvers/sqldb/impl.js +300 -0
- package/out/runtime/resolvers/sqldb/impl.js.map +1 -0
- package/out/runtime/state.js +83 -0
- package/out/runtime/state.js.map +1 -0
- package/out/runtime/util.d.ts +43 -0
- package/out/runtime/util.d.ts.map +1 -0
- package/out/runtime/util.js +447 -0
- package/out/runtime/util.js.map +1 -0
- 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.d.ts +77 -0
- package/out/syntaxes/agentlang.monarch.d.ts.map +1 -0
- package/out/syntaxes/agentlang.monarch.js +31 -0
- package/out/syntaxes/agentlang.monarch.js.map +1 -0
- package/out/utils/fs/index.d.ts +14 -0
- package/out/utils/fs/index.d.ts.map +1 -0
- package/out/utils/fs/index.js +26 -0
- package/out/utils/fs/index.js.map +1 -0
- package/out/utils/fs/interfaces.d.ts +105 -0
- package/out/utils/fs/interfaces.d.ts.map +1 -0
- package/out/utils/fs/interfaces.js +5 -0
- package/out/utils/fs/interfaces.js.map +1 -0
- package/out/utils/fs/lightning-fs.d.ts +116 -0
- package/out/utils/fs/lightning-fs.d.ts.map +1 -0
- package/out/utils/fs/lightning-fs.js +243 -0
- package/out/utils/fs/lightning-fs.js.map +1 -0
- package/out/utils/fs/node-fs.d.ts +93 -0
- package/out/utils/fs/node-fs.d.ts.map +1 -0
- package/out/utils/fs/node-fs.js +169 -0
- package/out/utils/fs/node-fs.js.map +1 -0
- package/out/utils/fs-utils.d.ts +153 -0
- package/out/utils/fs-utils.d.ts.map +1 -0
- package/out/utils/fs-utils.js +271 -0
- package/out/utils/fs-utils.js.map +1 -0
- package/out/utils/runtime.d.ts +36 -0
- package/out/utils/runtime.d.ts.map +1 -0
- package/out/utils/runtime.js +39 -0
- package/out/utils/runtime.js.map +1 -0
- package/package.json +155 -0
- package/src/api/http.ts +361 -0
- package/src/cli/cli-util.ts +18 -0
- package/src/cli/main.ts +146 -0
- package/src/extension/main.ts +51 -0
- package/src/language/agentlang-module.ts +75 -0
- package/src/language/agentlang-validator.ts +60 -0
- package/src/language/agentlang.langium +178 -0
- package/src/language/generated/ast.ts +1698 -0
- package/src/language/generated/grammar.ts +4477 -0
- package/src/language/generated/module.ts +25 -0
- package/src/language/main-browser.ts +19 -0
- package/src/language/main.ts +13 -0
- package/src/language/parser.ts +329 -0
- package/src/language/syntax.ts +646 -0
- package/src/runtime/agents/common.ts +177 -0
- package/src/runtime/agents/impl/openai.ts +19 -0
- package/src/runtime/agents/provider.ts +58 -0
- package/src/runtime/agents/registry.ts +9 -0
- package/src/runtime/auth/cognito.ts +225 -0
- package/src/runtime/auth/defs.ts +33 -0
- package/src/runtime/auth/interface.ts +31 -0
- package/src/runtime/defs.ts +33 -0
- package/src/runtime/interpreter.ts +1352 -0
- package/src/runtime/loader.ts +450 -0
- package/src/runtime/logger.ts +51 -0
- package/src/runtime/module.ts +2188 -0
- package/src/runtime/modules/ai.ts +257 -0
- package/src/runtime/modules/auth.ts +489 -0
- package/src/runtime/modules/core.ts +95 -0
- package/src/runtime/relgraph.ts +195 -0
- package/src/runtime/resolvers/interface.ts +160 -0
- package/src/runtime/resolvers/registry.ts +30 -0
- package/src/runtime/resolvers/sqldb/database.ts +823 -0
- package/src/runtime/resolvers/sqldb/dbutil.ts +257 -0
- package/src/runtime/resolvers/sqldb/impl.ts +471 -0
- package/src/runtime/state.ts +87 -0
- package/src/runtime/util.ts +513 -0
- package/src/setupClassic.ts +43 -0
- package/src/setupCommon.ts +33 -0
- package/src/setupExtended.ts +79 -0
- package/src/syntaxes/agentlang.monarch.ts +31 -0
- package/src/utils/fs/index.ts +28 -0
- package/src/utils/fs/interfaces.ts +118 -0
- package/src/utils/fs/lightning-fs.ts +284 -0
- package/src/utils/fs/node-fs.ts +185 -0
- package/src/utils/fs-utils.ts +304 -0
- package/src/utils/runtime.ts +43 -0
|
@@ -0,0 +1,1352 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ArrayLiteral,
|
|
3
|
+
CrudMap,
|
|
4
|
+
Delete,
|
|
5
|
+
Expr,
|
|
6
|
+
FnCall,
|
|
7
|
+
ForEach,
|
|
8
|
+
FullTextSearch,
|
|
9
|
+
Handler,
|
|
10
|
+
If,
|
|
11
|
+
isBinExpr,
|
|
12
|
+
isGroup,
|
|
13
|
+
isLiteral,
|
|
14
|
+
isNegExpr,
|
|
15
|
+
isNotExpr,
|
|
16
|
+
Literal,
|
|
17
|
+
MapKey,
|
|
18
|
+
MapLiteral,
|
|
19
|
+
Pattern,
|
|
20
|
+
Purge,
|
|
21
|
+
RelationshipPattern,
|
|
22
|
+
RuntimeHint,
|
|
23
|
+
SelectIntoEntry,
|
|
24
|
+
SelectIntoSpec,
|
|
25
|
+
SetAttribute,
|
|
26
|
+
Statement,
|
|
27
|
+
Upsert,
|
|
28
|
+
} from '../language/generated/ast.js';
|
|
29
|
+
import {
|
|
30
|
+
defineAgentEvent,
|
|
31
|
+
getOneOfRef,
|
|
32
|
+
getRelationship,
|
|
33
|
+
getWorkflow,
|
|
34
|
+
Instance,
|
|
35
|
+
InstanceAttributes,
|
|
36
|
+
isAgentEvent,
|
|
37
|
+
isBetweenRelationship,
|
|
38
|
+
isContainsRelationship,
|
|
39
|
+
isEmptyWorkflow,
|
|
40
|
+
isEntityInstance,
|
|
41
|
+
isEventInstance,
|
|
42
|
+
isInstanceOfType,
|
|
43
|
+
isTimer,
|
|
44
|
+
makeInstance,
|
|
45
|
+
newInstanceAttributes,
|
|
46
|
+
PlaceholderRecordEntry,
|
|
47
|
+
Relationship,
|
|
48
|
+
Workflow,
|
|
49
|
+
} from './module.js';
|
|
50
|
+
import { JoinInfo, Resolver, ResolverAuthInfo } from './resolvers/interface.js';
|
|
51
|
+
import { SqlDbResolver } from './resolvers/sqldb/impl.js';
|
|
52
|
+
import {
|
|
53
|
+
CrudType,
|
|
54
|
+
DefaultModuleName,
|
|
55
|
+
escapeFqName,
|
|
56
|
+
escapeQueryName,
|
|
57
|
+
fqNameFromPath,
|
|
58
|
+
invokeModuleFn,
|
|
59
|
+
isFqName,
|
|
60
|
+
isPath,
|
|
61
|
+
isString,
|
|
62
|
+
makeFqName,
|
|
63
|
+
Path,
|
|
64
|
+
QuerySuffix,
|
|
65
|
+
splitFqName,
|
|
66
|
+
splitRefs,
|
|
67
|
+
} from './util.js';
|
|
68
|
+
import { getResolver, getResolverNameForPath } from './resolvers/registry.js';
|
|
69
|
+
import { parseStatement, parseWorkflow } from '../language/parser.js';
|
|
70
|
+
import { ActiveSessionInfo, AdminSession, AdminUserId } from './auth/defs.js';
|
|
71
|
+
import { Agent, AgentFqName, findAgentByName } from './modules/ai.js';
|
|
72
|
+
import { logger } from './logger.js';
|
|
73
|
+
import { ParentAttributeName, PathAttributeName, PathAttributeNameQuery } from './defs.js';
|
|
74
|
+
import {
|
|
75
|
+
addCreateAudit,
|
|
76
|
+
addDeleteAudit,
|
|
77
|
+
addUpdateAudit,
|
|
78
|
+
maybeCancelTimer,
|
|
79
|
+
setTimerRunning,
|
|
80
|
+
} from './modules/core.js';
|
|
81
|
+
|
|
82
|
+
export type Result = any;
|
|
83
|
+
|
|
84
|
+
const EmptyResult: Result = null;
|
|
85
|
+
|
|
86
|
+
export function isEmptyResult(r: Result): boolean {
|
|
87
|
+
return r == EmptyResult;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type BetweenRelInfo = {
|
|
91
|
+
relationship: Relationship;
|
|
92
|
+
connectedInstance: Instance;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
function mkEnvName(name: string | undefined, parent: Environment | undefined): string {
|
|
96
|
+
if (name) return name;
|
|
97
|
+
else {
|
|
98
|
+
if (parent) {
|
|
99
|
+
return `${parent.name}+`;
|
|
100
|
+
} else {
|
|
101
|
+
return 'env';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export class Environment extends Instance {
|
|
107
|
+
parent: Environment | undefined;
|
|
108
|
+
|
|
109
|
+
private activeModule: string;
|
|
110
|
+
private activeEventInstance: Instance | undefined;
|
|
111
|
+
private activeUser: string = AdminUserId;
|
|
112
|
+
private activeUserSet: boolean = false;
|
|
113
|
+
private lastResult: Result;
|
|
114
|
+
private parentPath: string | undefined;
|
|
115
|
+
private normalizedParentPath: string | undefined;
|
|
116
|
+
private betweenRelInfo: BetweenRelInfo | undefined;
|
|
117
|
+
private activeResolvers: Map<string, Resolver>;
|
|
118
|
+
private activeTransactions: Map<string, string>;
|
|
119
|
+
private inUpsertMode: boolean = false;
|
|
120
|
+
private inDeleteMode: boolean = false;
|
|
121
|
+
private inKernelMode: boolean = false;
|
|
122
|
+
|
|
123
|
+
constructor(name?: string, parent?: Environment) {
|
|
124
|
+
super(
|
|
125
|
+
PlaceholderRecordEntry,
|
|
126
|
+
DefaultModuleName,
|
|
127
|
+
mkEnvName(name, parent),
|
|
128
|
+
newInstanceAttributes()
|
|
129
|
+
);
|
|
130
|
+
if (parent != undefined) {
|
|
131
|
+
this.parent = parent;
|
|
132
|
+
this.activeModule = parent.activeModule;
|
|
133
|
+
this.activeUser = parent.activeUser;
|
|
134
|
+
this.activeUserSet = parent.activeUserSet;
|
|
135
|
+
this.setActiveEvent(parent.getActiveEventInstance());
|
|
136
|
+
this.lastResult = parent.lastResult;
|
|
137
|
+
this.activeTransactions = parent.activeTransactions;
|
|
138
|
+
this.activeResolvers = parent.activeResolvers;
|
|
139
|
+
this.inUpsertMode = parent.inUpsertMode;
|
|
140
|
+
this.inKernelMode = parent.inKernelMode;
|
|
141
|
+
} else {
|
|
142
|
+
this.activeModule = DefaultModuleName;
|
|
143
|
+
this.activeResolvers = new Map<string, Resolver>();
|
|
144
|
+
this.activeTransactions = new Map<string, string>();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static from(parent: Environment): Environment {
|
|
149
|
+
return new Environment(undefined, parent);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
override lookup(k: string): Result {
|
|
153
|
+
const v = this.attributes.get(k);
|
|
154
|
+
if (v == undefined) {
|
|
155
|
+
if (this.parent != undefined) {
|
|
156
|
+
return this.parent.lookup(k);
|
|
157
|
+
} else if (this == GlobalEnvironment) {
|
|
158
|
+
return EmptyResult;
|
|
159
|
+
} else {
|
|
160
|
+
return GlobalEnvironment.lookup(k);
|
|
161
|
+
}
|
|
162
|
+
} else return v;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
bind(k: string, v: any): Environment {
|
|
166
|
+
this.attributes.set(k, v);
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
bindInstance(inst: Instance): Environment {
|
|
171
|
+
const n: string = inst.name;
|
|
172
|
+
this.attributes.set(n, inst);
|
|
173
|
+
return this;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
maybeLookupAgentInstance(entryName: string): Instance | undefined {
|
|
177
|
+
const v = this.lookup(entryName);
|
|
178
|
+
if (v && isInstanceOfType(v, AgentFqName)) {
|
|
179
|
+
return v as Instance;
|
|
180
|
+
} else {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
setActiveEvent(eventInst: Instance | undefined): Environment {
|
|
186
|
+
if (eventInst) {
|
|
187
|
+
if (!isEventInstance(eventInst)) throw new Error(`Not an event instance - ${eventInst.name}`);
|
|
188
|
+
this.bindInstance(eventInst);
|
|
189
|
+
this.activeModule = eventInst.moduleName;
|
|
190
|
+
this.activeEventInstance = eventInst;
|
|
191
|
+
if (!this.activeUserSet) {
|
|
192
|
+
this.activeUser = eventInst.getAuthContextUserId();
|
|
193
|
+
this.activeUserSet = true;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
getActiveEventInstance(): Instance | undefined {
|
|
200
|
+
return this.activeEventInstance;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
getActiveAuthContext(): ActiveSessionInfo | undefined {
|
|
204
|
+
if (this.activeEventInstance) {
|
|
205
|
+
return this.activeEventInstance.getAuthContext();
|
|
206
|
+
}
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
getActiveToken(): string | undefined {
|
|
211
|
+
if (this.activeEventInstance) {
|
|
212
|
+
const sess = this.activeEventInstance.getAuthContext();
|
|
213
|
+
if (sess) {
|
|
214
|
+
return sess.sessionId;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
setActiveUser(userId: string): Environment {
|
|
221
|
+
this.activeUser = userId;
|
|
222
|
+
this.activeUserSet = true;
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
getActiveUser(): string {
|
|
227
|
+
return this.activeUser;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
setLastResult(result: Result): Environment {
|
|
231
|
+
this.lastResult = result;
|
|
232
|
+
return this;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
getLastResult(): Result {
|
|
236
|
+
return this.lastResult;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
getActiveModuleName(): string {
|
|
240
|
+
return this.activeModule;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
switchActiveModuleName(newModuleName: string): string {
|
|
244
|
+
const oldModuleName = this.activeModule;
|
|
245
|
+
this.activeModule = newModuleName;
|
|
246
|
+
return oldModuleName;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
setParentPath(path: string): Environment {
|
|
250
|
+
this.parentPath = path;
|
|
251
|
+
return this;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
getParentPath(): string | undefined {
|
|
255
|
+
return this.parentPath;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
setNormalizedParentPath(path: string): Environment {
|
|
259
|
+
this.normalizedParentPath = path;
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
getNormalizedParentPath(): string | undefined {
|
|
264
|
+
return this.normalizedParentPath;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
setBetweenRelInfo(info: BetweenRelInfo): Environment {
|
|
268
|
+
this.betweenRelInfo = info;
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
getBetweenRelInfo(): BetweenRelInfo | undefined {
|
|
273
|
+
return this.betweenRelInfo;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
setActiveResolvers(resolvers: Map<string, Resolver>): Environment {
|
|
277
|
+
this.activeResolvers = resolvers;
|
|
278
|
+
return this;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
getActiveResolvers(): Map<string, Resolver> {
|
|
282
|
+
return this.activeResolvers;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
getResolver(resolverName: string): Resolver | undefined {
|
|
286
|
+
const r: Resolver | undefined = this.getActiveResolvers().get(resolverName);
|
|
287
|
+
if (r) {
|
|
288
|
+
return r.setUserData(this);
|
|
289
|
+
}
|
|
290
|
+
return undefined;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async addResolver(resolver: Resolver): Promise<Environment> {
|
|
294
|
+
this.getActiveResolvers().set(resolver.getName(), resolver);
|
|
295
|
+
await this.ensureTransactionForResolver(resolver);
|
|
296
|
+
resolver.setUserData(this);
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
setActiveTransactions(txns: Map<string, string>): Environment {
|
|
301
|
+
this.activeTransactions = txns;
|
|
302
|
+
return this;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
getActiveTransactions(): Map<string, string> {
|
|
306
|
+
return this.activeTransactions;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async getTransactionForResolver(resolver: Resolver): Promise<string> {
|
|
310
|
+
const n: string = resolver.getName();
|
|
311
|
+
let txnId: string | undefined = this.getActiveTransactions().get(n);
|
|
312
|
+
if (txnId) {
|
|
313
|
+
return txnId;
|
|
314
|
+
} else {
|
|
315
|
+
txnId = await resolver.startTransaction();
|
|
316
|
+
if (txnId) {
|
|
317
|
+
this.getActiveTransactions().set(n, txnId);
|
|
318
|
+
return txnId;
|
|
319
|
+
} else {
|
|
320
|
+
throw new Error(`Failed to start transaction for ${n}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async ensureTransactionForResolver(resolver: Resolver): Promise<Environment> {
|
|
326
|
+
await this.getTransactionForResolver(resolver);
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private async endAllTransactions(commit: boolean): Promise<void> {
|
|
331
|
+
const txns: Map<string, string> = this.getActiveTransactions();
|
|
332
|
+
for (const n of txns.keys()) {
|
|
333
|
+
const txnId: string | undefined = txns.get(n);
|
|
334
|
+
if (txnId) {
|
|
335
|
+
const res: Resolver | undefined = this.getResolver(n);
|
|
336
|
+
if (res) {
|
|
337
|
+
if (commit) await res.commitTransaction(txnId);
|
|
338
|
+
else await res.rollbackTransaction(txnId);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async callInTransaction(f: Function): Promise<any> {
|
|
345
|
+
let result: any;
|
|
346
|
+
let commit: boolean = true;
|
|
347
|
+
await f()
|
|
348
|
+
.then((r: any) => {
|
|
349
|
+
result = r;
|
|
350
|
+
})
|
|
351
|
+
.catch((r: any) => {
|
|
352
|
+
commit = false;
|
|
353
|
+
result = r;
|
|
354
|
+
});
|
|
355
|
+
await this.endAllTransactions(commit);
|
|
356
|
+
if (!commit) {
|
|
357
|
+
throw result;
|
|
358
|
+
}
|
|
359
|
+
return result;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async commitAllTransactions(): Promise<void> {
|
|
363
|
+
await this.endAllTransactions(true);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async rollbackAllTransactions(): Promise<void> {
|
|
367
|
+
await this.endAllTransactions(false);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
setInUpsertMode(flag: boolean): Environment {
|
|
371
|
+
this.inUpsertMode = flag;
|
|
372
|
+
return this;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
isInUpsertMode(): boolean {
|
|
376
|
+
return this.inUpsertMode;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
setInDeleteMode(flag: boolean): Environment {
|
|
380
|
+
this.inDeleteMode = flag;
|
|
381
|
+
return this;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
isInDeleteMode(): boolean {
|
|
385
|
+
return this.inDeleteMode;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
setInKernelMode(flag: boolean): Environment {
|
|
389
|
+
this.inKernelMode = flag;
|
|
390
|
+
return this;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
isInKernelMode(): boolean {
|
|
394
|
+
return this.inKernelMode;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export const GlobalEnvironment = new Environment();
|
|
399
|
+
|
|
400
|
+
export async function evaluate(
|
|
401
|
+
eventInstance: Instance,
|
|
402
|
+
continuation?: Function,
|
|
403
|
+
activeEnv?: Environment,
|
|
404
|
+
kernelCall?: boolean
|
|
405
|
+
): Promise<void> {
|
|
406
|
+
let env: Environment | undefined;
|
|
407
|
+
let txnRolledBack: boolean = false;
|
|
408
|
+
try {
|
|
409
|
+
if (isEventInstance(eventInstance)) {
|
|
410
|
+
const wf: Workflow = getWorkflow(eventInstance);
|
|
411
|
+
if (!isEmptyWorkflow(wf)) {
|
|
412
|
+
env = new Environment(eventInstance.name + '.env', activeEnv);
|
|
413
|
+
env.setActiveEvent(eventInstance);
|
|
414
|
+
if (kernelCall) {
|
|
415
|
+
env.setInKernelMode(true);
|
|
416
|
+
}
|
|
417
|
+
await evaluateStatements(wf.statements, env, continuation);
|
|
418
|
+
}
|
|
419
|
+
} else {
|
|
420
|
+
throw new Error('Not an event - ' + eventInstance.name);
|
|
421
|
+
}
|
|
422
|
+
} catch (err) {
|
|
423
|
+
if (env != undefined && activeEnv == undefined) {
|
|
424
|
+
await env.rollbackAllTransactions().then(() => {
|
|
425
|
+
txnRolledBack = true;
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
throw err;
|
|
429
|
+
} finally {
|
|
430
|
+
if (!txnRolledBack && env != undefined && activeEnv == undefined) {
|
|
431
|
+
await env.commitAllTransactions();
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export async function evaluateAsEvent(
|
|
437
|
+
moduleName: string,
|
|
438
|
+
eventName: string,
|
|
439
|
+
attrs: Array<any> | object,
|
|
440
|
+
activeSession?: ActiveSessionInfo,
|
|
441
|
+
env?: Environment,
|
|
442
|
+
kernelCall?: boolean
|
|
443
|
+
): Promise<Result> {
|
|
444
|
+
const finalAttrs: Map<string, any> =
|
|
445
|
+
attrs instanceof Array ? new Map(attrs) : new Map(Object.entries(attrs));
|
|
446
|
+
const eventInst: Instance = makeInstance(moduleName, eventName, finalAttrs).setAuthContext(
|
|
447
|
+
activeSession || AdminSession
|
|
448
|
+
);
|
|
449
|
+
let result: any;
|
|
450
|
+
await evaluate(eventInst, (r: any) => (result = r), env, kernelCall);
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export function makeEventEvaluator(moduleName: string): Function {
|
|
455
|
+
return async (
|
|
456
|
+
eventName: string,
|
|
457
|
+
attrs: Array<any> | object,
|
|
458
|
+
env: Environment,
|
|
459
|
+
session?: ActiveSessionInfo,
|
|
460
|
+
kernelCall: boolean = true
|
|
461
|
+
): Promise<Result> => {
|
|
462
|
+
if (!env) {
|
|
463
|
+
env = new Environment();
|
|
464
|
+
}
|
|
465
|
+
return await evaluateAsEvent(moduleName, eventName, attrs, session, env, kernelCall);
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export async function evaluateStatements(
|
|
470
|
+
stmts: Statement[],
|
|
471
|
+
env: Environment,
|
|
472
|
+
continuation?: Function
|
|
473
|
+
) {
|
|
474
|
+
for (let i = 0; i < stmts.length; ++i) {
|
|
475
|
+
await evaluateStatement(stmts[i], env);
|
|
476
|
+
}
|
|
477
|
+
if (continuation != undefined) {
|
|
478
|
+
continuation(env.getLastResult());
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
async function evaluateStatement(stmt: Statement, env: Environment): Promise<void> {
|
|
483
|
+
const hints = stmt.hints;
|
|
484
|
+
const hasHints = hints && hints.length > 0;
|
|
485
|
+
const handlers: Map<string, Statement> | undefined = hasHints
|
|
486
|
+
? maybeFindHandlers(hints)
|
|
487
|
+
: undefined;
|
|
488
|
+
try {
|
|
489
|
+
await evaluatePattern(stmt.pattern, env);
|
|
490
|
+
if (hasHints) {
|
|
491
|
+
maybeBindStatementResultToAlias(hints, env);
|
|
492
|
+
}
|
|
493
|
+
const lastResult: Result = env.getLastResult();
|
|
494
|
+
if (
|
|
495
|
+
lastResult == null ||
|
|
496
|
+
lastResult == undefined ||
|
|
497
|
+
(lastResult instanceof Array && lastResult.length == 0)
|
|
498
|
+
) {
|
|
499
|
+
const onNotFound = handlers ? handlers.get('not_found') : undefined;
|
|
500
|
+
if (onNotFound) {
|
|
501
|
+
await evaluateStatement(onNotFound, env);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
} catch (reason: any) {
|
|
505
|
+
const handler = handlers ? handlers.get('error') : undefined;
|
|
506
|
+
if (handler) {
|
|
507
|
+
await evaluateStatement(handler, env);
|
|
508
|
+
} else {
|
|
509
|
+
throw reason;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function maybeBindStatementResultToAlias(hints: RuntimeHint[], env: Environment) {
|
|
515
|
+
for (let i = 0; i < hints.length; ++i) {
|
|
516
|
+
const rh = hints[i];
|
|
517
|
+
if (rh.aliasSpec) {
|
|
518
|
+
if (rh.aliasSpec.alias != undefined || rh.aliasSpec.aliases.length > 0) {
|
|
519
|
+
const result: Result = env.getLastResult();
|
|
520
|
+
const alias: string | undefined = rh.aliasSpec.alias;
|
|
521
|
+
if (alias != undefined) {
|
|
522
|
+
env.bind(alias, result);
|
|
523
|
+
} else {
|
|
524
|
+
const aliases: string[] = rh.aliasSpec.aliases;
|
|
525
|
+
if (result instanceof Array) {
|
|
526
|
+
const resArr: Array<any> = result as Array<any>;
|
|
527
|
+
for (let i = 0; i < aliases.length; ++i) {
|
|
528
|
+
const k: string = aliases[i];
|
|
529
|
+
if (k == '_') {
|
|
530
|
+
env.bind(aliases[i + 1], resArr.splice(i));
|
|
531
|
+
break;
|
|
532
|
+
} else {
|
|
533
|
+
env.bind(aliases[i], resArr[i]);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
} else {
|
|
537
|
+
env.bind(aliases[0], result);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function maybeFindHandlers(hints: RuntimeHint[]): Map<string, Statement> | undefined {
|
|
547
|
+
for (let i = 0; i < hints.length; ++i) {
|
|
548
|
+
const rh = hints[i];
|
|
549
|
+
if (rh.catchSpec) {
|
|
550
|
+
const result = new Map<string, Statement>();
|
|
551
|
+
rh.catchSpec.handlers.forEach((h: Handler) => {
|
|
552
|
+
result.set(h.except, h.stmt);
|
|
553
|
+
});
|
|
554
|
+
return result;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return undefined;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export async function parseAndEvaluateStatement(
|
|
561
|
+
stmtString: string,
|
|
562
|
+
activeUserId?: string,
|
|
563
|
+
actievEnv?: Environment
|
|
564
|
+
): Promise<Result> {
|
|
565
|
+
const env = actievEnv ? actievEnv : new Environment();
|
|
566
|
+
if (activeUserId) {
|
|
567
|
+
env.setActiveUser(activeUserId);
|
|
568
|
+
}
|
|
569
|
+
let commit: boolean = true;
|
|
570
|
+
try {
|
|
571
|
+
const stmt: Statement = await parseStatement(stmtString);
|
|
572
|
+
if (stmt) {
|
|
573
|
+
await evaluateStatement(stmt, env);
|
|
574
|
+
return env.getLastResult();
|
|
575
|
+
} else {
|
|
576
|
+
commit = false;
|
|
577
|
+
}
|
|
578
|
+
} catch (err) {
|
|
579
|
+
commit = false;
|
|
580
|
+
throw err;
|
|
581
|
+
} finally {
|
|
582
|
+
if (!actievEnv) {
|
|
583
|
+
if (commit) {
|
|
584
|
+
await env.commitAllTransactions();
|
|
585
|
+
} else {
|
|
586
|
+
await env.rollbackAllTransactions();
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
async function evaluatePattern(pat: Pattern, env: Environment): Promise<void> {
|
|
593
|
+
if (pat.literal) {
|
|
594
|
+
await evaluateLiteral(pat.literal, env);
|
|
595
|
+
} else if (pat.crudMap) {
|
|
596
|
+
await evaluateCrudMap(pat.crudMap, env);
|
|
597
|
+
} else if (pat.forEach) {
|
|
598
|
+
await evaluateForEach(pat.forEach, env);
|
|
599
|
+
} else if (pat.if) {
|
|
600
|
+
await evaluateIf(pat.if, env);
|
|
601
|
+
} else if (pat.delete) {
|
|
602
|
+
await evaluateDelete(pat.delete, env);
|
|
603
|
+
} else if (pat.purge) {
|
|
604
|
+
await evaluatePurge(pat.purge, env);
|
|
605
|
+
} else if (pat.upsert) {
|
|
606
|
+
await evaluateUpsert(pat.upsert, env);
|
|
607
|
+
} else if (pat.fullTextSearch) {
|
|
608
|
+
await evaluateFullTextSearch(pat.fullTextSearch, env);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
async function evaluateFullTextSearch(fts: FullTextSearch, env: Environment): Promise<void> {
|
|
613
|
+
let n = escapeQueryName(fts.name);
|
|
614
|
+
if (!isFqName(n)) {
|
|
615
|
+
const inst: Instance | undefined = env.getActiveEventInstance();
|
|
616
|
+
if (inst) {
|
|
617
|
+
n = makeFqName(inst.moduleName, n);
|
|
618
|
+
} else {
|
|
619
|
+
throw new Error(`Fully qualified name required for full-text-search in ${n}`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
const path = splitFqName(n);
|
|
623
|
+
const entryName = path.getEntryName();
|
|
624
|
+
const moduleName = path.getModuleName();
|
|
625
|
+
const resolver = await getResolverForPath(entryName, moduleName, env);
|
|
626
|
+
await evaluateLiteral(fts.query, env);
|
|
627
|
+
const q = env.getLastResult();
|
|
628
|
+
if (!isString(q)) {
|
|
629
|
+
throw new Error(`Full text search query must be a string - ${q}`);
|
|
630
|
+
}
|
|
631
|
+
let options: Map<string, any> | undefined;
|
|
632
|
+
if (fts.options) {
|
|
633
|
+
await realizeMap(fts.options, env);
|
|
634
|
+
options = env.getLastResult();
|
|
635
|
+
}
|
|
636
|
+
env.setLastResult(await resolver.fullTextSearch(entryName, moduleName, q, options));
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
async function evaluateLiteral(lit: Literal, env: Environment): Promise<void> {
|
|
640
|
+
if (lit.id != undefined) env.setLastResult(env.lookup(lit.id));
|
|
641
|
+
else if (lit.ref != undefined) env.setLastResult(await followReference(env, lit.ref));
|
|
642
|
+
else if (lit.fnCall != undefined) await applyFn(lit.fnCall, env, false);
|
|
643
|
+
else if (lit.asyncFnCall != undefined) await applyFn(lit.asyncFnCall.fnCall, env, true);
|
|
644
|
+
else if (lit.array != undefined) await realizeArray(lit.array, env);
|
|
645
|
+
else if (lit.map != undefined) await realizeMap(lit.map, env);
|
|
646
|
+
else if (lit.num != undefined) env.setLastResult(lit.num);
|
|
647
|
+
else if (lit.str != undefined) env.setLastResult(lit.str);
|
|
648
|
+
else if (lit.bool != undefined) env.setLastResult(lit.bool == 'true' ? true : false);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function getMapKey(k: MapKey): Result {
|
|
652
|
+
if (k.str != undefined) return k.str;
|
|
653
|
+
else if (k.num != undefined) return k.num;
|
|
654
|
+
else if (k.bool != undefined) k.bool == 'true' ? true : false;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const DefaultResolverName: string = '--default-resolver--';
|
|
658
|
+
|
|
659
|
+
async function getResolverForPath(
|
|
660
|
+
entryName: string,
|
|
661
|
+
moduleName: string,
|
|
662
|
+
env: Environment,
|
|
663
|
+
isReadForUpdate: boolean = false,
|
|
664
|
+
isReadForDelete: boolean = false
|
|
665
|
+
): Promise<Resolver> {
|
|
666
|
+
const fqEntryName: string = isFqName(entryName) ? entryName : makeFqName(moduleName, entryName);
|
|
667
|
+
const resN: string | undefined = getResolverNameForPath(fqEntryName);
|
|
668
|
+
let res: Resolver | undefined;
|
|
669
|
+
if (resN == undefined) {
|
|
670
|
+
res = env.getResolver(DefaultResolverName);
|
|
671
|
+
if (res == undefined) {
|
|
672
|
+
res = new SqlDbResolver(DefaultResolverName);
|
|
673
|
+
await env.addResolver(res);
|
|
674
|
+
}
|
|
675
|
+
} else {
|
|
676
|
+
res = env.getResolver(resN);
|
|
677
|
+
if (res == undefined) {
|
|
678
|
+
res = getResolver(fqEntryName);
|
|
679
|
+
await env.addResolver(res);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const authInfo: ResolverAuthInfo = new ResolverAuthInfo(
|
|
684
|
+
env.getActiveUser(),
|
|
685
|
+
isReadForUpdate,
|
|
686
|
+
isReadForDelete
|
|
687
|
+
);
|
|
688
|
+
return res.setAuthInfo(authInfo);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
async function lookupOneOfVals(fqName: string, env: Environment): Promise<Instance[] | null> {
|
|
692
|
+
return await parseAndEvaluateStatement(`{${fqName}? {}}`, undefined, env);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
async function patternToInstance(
|
|
696
|
+
entryName: string,
|
|
697
|
+
attributes: SetAttribute[],
|
|
698
|
+
env: Environment
|
|
699
|
+
): Promise<Instance> {
|
|
700
|
+
const attrs: InstanceAttributes = newInstanceAttributes();
|
|
701
|
+
let qattrs: InstanceAttributes | undefined;
|
|
702
|
+
let qattrVals: InstanceAttributes | undefined;
|
|
703
|
+
const isQueryAll: boolean = entryName.endsWith(QuerySuffix);
|
|
704
|
+
if (isQueryAll) {
|
|
705
|
+
entryName = entryName.slice(0, entryName.length - 1);
|
|
706
|
+
}
|
|
707
|
+
for (let i = 0; i < attributes.length; ++i) {
|
|
708
|
+
const a: SetAttribute = attributes[i];
|
|
709
|
+
await evaluateExpression(a.value, env);
|
|
710
|
+
const v: Result = env.getLastResult();
|
|
711
|
+
let aname: string = a.name;
|
|
712
|
+
if (aname.endsWith(QuerySuffix)) {
|
|
713
|
+
if (isQueryAll) {
|
|
714
|
+
throw new Error(`Cannot specifiy query attribute ${aname} here`);
|
|
715
|
+
}
|
|
716
|
+
if (qattrs == undefined) qattrs = newInstanceAttributes();
|
|
717
|
+
if (qattrVals == undefined) qattrVals = newInstanceAttributes();
|
|
718
|
+
aname = aname.slice(0, aname.length - 1);
|
|
719
|
+
qattrs.set(aname, a.op == undefined ? '=' : a.op);
|
|
720
|
+
qattrVals.set(aname, v);
|
|
721
|
+
} else {
|
|
722
|
+
attrs.set(aname, v);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
let moduleName = env.getActiveModuleName();
|
|
726
|
+
if (isFqName(entryName)) {
|
|
727
|
+
const p: Path = splitFqName(entryName);
|
|
728
|
+
if (p.hasModule()) moduleName = p.getModuleName();
|
|
729
|
+
if (p.hasEntry()) entryName = p.getEntryName();
|
|
730
|
+
}
|
|
731
|
+
return makeInstance(moduleName, entryName, attrs, qattrs, qattrVals, isQueryAll);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
async function maybeValidateOneOfRefs(inst: Instance, env: Environment) {
|
|
735
|
+
const attrs = inst.record.oneOfRefAttributes;
|
|
736
|
+
if (!attrs) return;
|
|
737
|
+
for (let i = 0; i < attrs.length; ++i) {
|
|
738
|
+
const n = attrs[i];
|
|
739
|
+
const v = inst.lookup(n);
|
|
740
|
+
if (v == undefined) continue;
|
|
741
|
+
const attrSpec = inst.record.schema.get(n);
|
|
742
|
+
if (!attrSpec) continue;
|
|
743
|
+
const r = getOneOfRef(attrSpec);
|
|
744
|
+
if (!r) throw new Error(`Failed to fetch one-of-ref for ${n}`);
|
|
745
|
+
if (r) {
|
|
746
|
+
const parts = r.split('.');
|
|
747
|
+
const insts = await lookupOneOfVals(parts[0], env);
|
|
748
|
+
if (!insts || insts.length == 0) {
|
|
749
|
+
logger.warn(`No enum values set for ${n}`);
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
if (
|
|
753
|
+
!insts.some((i: Instance) => {
|
|
754
|
+
return i.lookup(parts[1]) == v;
|
|
755
|
+
})
|
|
756
|
+
) {
|
|
757
|
+
throw new Error(`Invalid enum-value ${v} for ${n}`);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
async function evaluateCrudMap(crud: CrudMap, env: Environment): Promise<void> {
|
|
764
|
+
const inst: Instance = await patternToInstance(crud.name, crud.attributes, env);
|
|
765
|
+
const entryName = inst.name;
|
|
766
|
+
const moduleName = inst.moduleName;
|
|
767
|
+
const attrs = inst.attributes;
|
|
768
|
+
const qattrs = inst.queryAttributes;
|
|
769
|
+
const isQueryAll = crud.name.endsWith(QuerySuffix);
|
|
770
|
+
if (attrs.size > 0) {
|
|
771
|
+
await maybeValidateOneOfRefs(inst, env);
|
|
772
|
+
}
|
|
773
|
+
if (crud.into) {
|
|
774
|
+
if (attrs.size > 0) {
|
|
775
|
+
throw new Error(
|
|
776
|
+
`Query pattern for ${entryName} with 'into' clause cannot be used to update attributes`
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
if (qattrs == undefined && !isQueryAll) {
|
|
780
|
+
throw new Error(`Pattern for ${entryName} with 'into' clause must be a query`);
|
|
781
|
+
}
|
|
782
|
+
await evaluateJoinQuery(crud.into, inst, crud.relationships, env);
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
if (isEntityInstance(inst) || isBetweenRelationship(inst.name, inst.moduleName)) {
|
|
786
|
+
if (qattrs == undefined && !isQueryAll) {
|
|
787
|
+
const parentPath: string | undefined = env.getParentPath();
|
|
788
|
+
if (parentPath) {
|
|
789
|
+
inst.attributes.set(PathAttributeName, parentPath);
|
|
790
|
+
inst.attributes.set(ParentAttributeName, env.getNormalizedParentPath() || '');
|
|
791
|
+
}
|
|
792
|
+
const res: Resolver = await getResolverForPath(entryName, moduleName, env);
|
|
793
|
+
let r: Instance | undefined;
|
|
794
|
+
await computeExprAttributes(inst, env);
|
|
795
|
+
if (env.isInUpsertMode()) {
|
|
796
|
+
await runPreUpdateEvents(inst, env);
|
|
797
|
+
r = await res.upsertInstance(inst);
|
|
798
|
+
await runPostUpdateEvents(inst, env);
|
|
799
|
+
} else {
|
|
800
|
+
await runPreCreateEvents(inst, env);
|
|
801
|
+
if (isTimer(inst)) triggerTimer(inst);
|
|
802
|
+
r = await res.createInstance(inst);
|
|
803
|
+
await runPostCreateEvents(inst, env);
|
|
804
|
+
}
|
|
805
|
+
if (r && entryName == 'agent') {
|
|
806
|
+
defineAgentEvent(env.getActiveModuleName(), r.lookup('name'));
|
|
807
|
+
}
|
|
808
|
+
env.setLastResult(r);
|
|
809
|
+
const betRelInfo: BetweenRelInfo | undefined = env.getBetweenRelInfo();
|
|
810
|
+
if (betRelInfo) {
|
|
811
|
+
await res.connectInstances(
|
|
812
|
+
betRelInfo.connectedInstance,
|
|
813
|
+
env.getLastResult(),
|
|
814
|
+
betRelInfo.relationship,
|
|
815
|
+
env.isInUpsertMode()
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
if (crud.relationships != undefined) {
|
|
819
|
+
for (let i = 0; i < crud.relationships.length; ++i) {
|
|
820
|
+
const rel: RelationshipPattern = crud.relationships[i];
|
|
821
|
+
const relEntry: Relationship = getRelationship(rel.name, moduleName);
|
|
822
|
+
const newEnv: Environment = Environment.from(env);
|
|
823
|
+
if (isContainsRelationship(rel.name, moduleName)) {
|
|
824
|
+
const ppath = inst.attributes.get(PathAttributeName);
|
|
825
|
+
newEnv.setParentPath(`${ppath}/${escapeFqName(relEntry.getFqName())}`);
|
|
826
|
+
newEnv.setNormalizedParentPath(ppath);
|
|
827
|
+
await evaluatePattern(rel.pattern, newEnv);
|
|
828
|
+
const lastInst: Instance = env.getLastResult();
|
|
829
|
+
lastInst.attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
830
|
+
} else if (isBetweenRelationship(rel.name, moduleName)) {
|
|
831
|
+
const lastInst: Instance = env.getLastResult() as Instance;
|
|
832
|
+
await evaluatePattern(rel.pattern, newEnv);
|
|
833
|
+
const relResult: any = newEnv.getLastResult();
|
|
834
|
+
const res: Resolver = await getResolverForPath(rel.name, moduleName, env);
|
|
835
|
+
await res.connectInstances(lastInst, relResult, relEntry, env.isInUpsertMode());
|
|
836
|
+
lastInst.attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
} else {
|
|
841
|
+
const parentPath: string | undefined = env.getParentPath();
|
|
842
|
+
const betRelInfo: BetweenRelInfo | undefined = env.getBetweenRelInfo();
|
|
843
|
+
const isReadForUpdate = attrs.size > 0;
|
|
844
|
+
let res: Resolver = Resolver.Default;
|
|
845
|
+
if (parentPath != undefined) {
|
|
846
|
+
res = await getResolverForPath(inst.name, inst.moduleName, env);
|
|
847
|
+
const insts: Instance[] = await res.queryChildInstances(parentPath, inst);
|
|
848
|
+
env.setLastResult(insts);
|
|
849
|
+
} else if (betRelInfo != undefined) {
|
|
850
|
+
res = await getResolverForPath(
|
|
851
|
+
betRelInfo.relationship.name,
|
|
852
|
+
betRelInfo.relationship.moduleName,
|
|
853
|
+
env
|
|
854
|
+
);
|
|
855
|
+
const insts: Instance[] = await res.queryConnectedInstances(
|
|
856
|
+
betRelInfo.relationship,
|
|
857
|
+
betRelInfo.connectedInstance,
|
|
858
|
+
inst
|
|
859
|
+
);
|
|
860
|
+
env.setLastResult(insts);
|
|
861
|
+
} else {
|
|
862
|
+
res = await getResolverForPath(
|
|
863
|
+
inst.name,
|
|
864
|
+
inst.moduleName,
|
|
865
|
+
env,
|
|
866
|
+
isReadForUpdate,
|
|
867
|
+
env.isInDeleteMode()
|
|
868
|
+
);
|
|
869
|
+
const insts: Instance[] = await res.queryInstances(inst, isQueryAll);
|
|
870
|
+
env.setLastResult(insts);
|
|
871
|
+
}
|
|
872
|
+
if (crud.relationships != undefined) {
|
|
873
|
+
const lastRes: Instance[] = env.getLastResult();
|
|
874
|
+
for (let i = 0; i < crud.relationships.length; ++i) {
|
|
875
|
+
const rel: RelationshipPattern = crud.relationships[i];
|
|
876
|
+
const relEntry: Relationship = getRelationship(rel.name, moduleName);
|
|
877
|
+
for (let j = 0; j < lastRes.length; ++j) {
|
|
878
|
+
const newEnv: Environment = Environment.from(env);
|
|
879
|
+
if (isContainsRelationship(rel.name, moduleName)) {
|
|
880
|
+
const ppath = lastRes[j].attributes.get(PathAttributeName);
|
|
881
|
+
newEnv.setParentPath(ppath + '/' + escapeFqName(relEntry.getFqName()));
|
|
882
|
+
newEnv.setNormalizedParentPath(ppath);
|
|
883
|
+
await evaluatePattern(rel.pattern, newEnv);
|
|
884
|
+
lastRes[j].attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
885
|
+
} else if (isBetweenRelationship(rel.name, moduleName)) {
|
|
886
|
+
newEnv.setBetweenRelInfo({ relationship: relEntry, connectedInstance: lastRes[j] });
|
|
887
|
+
await evaluatePattern(rel.pattern, newEnv);
|
|
888
|
+
lastRes[j].attachRelatedInstances(rel.name, newEnv.getLastResult());
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (isReadForUpdate) {
|
|
894
|
+
const lastRes: Instance[] | Instance = env.getLastResult();
|
|
895
|
+
if (lastRes instanceof Array) {
|
|
896
|
+
if (lastRes.length > 0) {
|
|
897
|
+
const resolver: Resolver = await getResolverForPath(
|
|
898
|
+
lastRes[0].name,
|
|
899
|
+
lastRes[0].moduleName,
|
|
900
|
+
env
|
|
901
|
+
);
|
|
902
|
+
const res: Array<Instance> = new Array<Instance>();
|
|
903
|
+
for (let i = 0; i < lastRes.length; ++i) {
|
|
904
|
+
await computeExprAttributes(lastRes[i], env);
|
|
905
|
+
await runPreUpdateEvents(lastRes[i], env);
|
|
906
|
+
const finalInst: Instance = await resolver.updateInstance(lastRes[i], attrs);
|
|
907
|
+
await runPostUpdateEvents(finalInst, env);
|
|
908
|
+
res.push(finalInst);
|
|
909
|
+
}
|
|
910
|
+
env.setLastResult(res);
|
|
911
|
+
} else {
|
|
912
|
+
env.setLastResult(lastRes);
|
|
913
|
+
}
|
|
914
|
+
} else {
|
|
915
|
+
const res: Resolver = await getResolverForPath(lastRes.name, lastRes.moduleName, env);
|
|
916
|
+
await computeExprAttributes(lastRes, env);
|
|
917
|
+
await runPreUpdateEvents(lastRes, env);
|
|
918
|
+
const finalInst: Instance = await res.updateInstance(lastRes, attrs);
|
|
919
|
+
await runPostUpdateEvents(finalInst, env);
|
|
920
|
+
env.setLastResult(finalInst);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
} else if (isEventInstance(inst)) {
|
|
925
|
+
if (isAgentEvent(inst)) await handleAgentInvocation(inst, env);
|
|
926
|
+
else await evaluate(inst, (result: Result) => env.setLastResult(result), env);
|
|
927
|
+
} else {
|
|
928
|
+
env.setLastResult(inst);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
function triggerTimer(timerInst: Instance): Instance {
|
|
933
|
+
const dur = timerInst.lookup('duration');
|
|
934
|
+
const unit = timerInst.lookup('unit');
|
|
935
|
+
let millisecs = 0;
|
|
936
|
+
switch (unit) {
|
|
937
|
+
case 'millisecond': {
|
|
938
|
+
millisecs = dur;
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
941
|
+
case 'second': {
|
|
942
|
+
millisecs = dur * 1000;
|
|
943
|
+
break;
|
|
944
|
+
}
|
|
945
|
+
case 'minute': {
|
|
946
|
+
millisecs = dur * 60 * 1000;
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
case 'hour': {
|
|
950
|
+
millisecs = dur * 60 * 60 * 1000;
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
const eventName = splitFqName(timerInst.lookup('trigger'));
|
|
955
|
+
const m = eventName.hasModule() ? eventName.getModuleName() : timerInst.moduleName;
|
|
956
|
+
const n = eventName.getEntryName();
|
|
957
|
+
const inst = makeInstance(m, n, newInstanceAttributes());
|
|
958
|
+
const name = timerInst.lookup('name');
|
|
959
|
+
const timer = setInterval(async () => {
|
|
960
|
+
const env = new Environment();
|
|
961
|
+
try {
|
|
962
|
+
await evaluate(
|
|
963
|
+
inst,
|
|
964
|
+
(result: Result) => logger.debug(`Timer ${name} ran with result ${result}`),
|
|
965
|
+
env
|
|
966
|
+
);
|
|
967
|
+
await env.commitAllTransactions();
|
|
968
|
+
await maybeCancelTimer(name, timer, env);
|
|
969
|
+
} catch (reason: any) {
|
|
970
|
+
logger.error(`Timer ${name} raised error: ${reason}`);
|
|
971
|
+
}
|
|
972
|
+
}, millisecs);
|
|
973
|
+
setTimerRunning(timerInst);
|
|
974
|
+
return timerInst;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
async function computeExprAttributes(inst: Instance, env: Environment) {
|
|
978
|
+
const exprAttrs = inst.getExprAttributes();
|
|
979
|
+
if (exprAttrs) {
|
|
980
|
+
const newEnv = new Environment('expr-env', env);
|
|
981
|
+
inst.attributes.forEach((v: any, k: string) => {
|
|
982
|
+
newEnv.bind(k, v);
|
|
983
|
+
});
|
|
984
|
+
const ks = [...exprAttrs.keys()];
|
|
985
|
+
for (let i = 0; i < ks.length; ++i) {
|
|
986
|
+
const n = ks[i];
|
|
987
|
+
const expr: Expr | undefined = exprAttrs.get(n);
|
|
988
|
+
if (expr) {
|
|
989
|
+
await evaluateExpression(expr, newEnv);
|
|
990
|
+
const v: Result = newEnv.getLastResult();
|
|
991
|
+
newEnv.bind(n, v);
|
|
992
|
+
inst.attributes.set(n, v);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
async function evaluateJoinQuery(
|
|
999
|
+
intoSpec: SelectIntoSpec,
|
|
1000
|
+
inst: Instance,
|
|
1001
|
+
relationships: RelationshipPattern[],
|
|
1002
|
+
env: Environment
|
|
1003
|
+
): Promise<void> {
|
|
1004
|
+
const normIntoSpec = new Map<string, string>();
|
|
1005
|
+
intoSpec.entries.forEach((entry: SelectIntoEntry) => {
|
|
1006
|
+
normIntoSpec.set(entry.alias, entry.attribute);
|
|
1007
|
+
});
|
|
1008
|
+
const moduleName = inst.moduleName;
|
|
1009
|
+
let joinsSpec = new Array<JoinInfo>();
|
|
1010
|
+
for (let i = 0; i < relationships.length; ++i) {
|
|
1011
|
+
joinsSpec = await walkJoinQueryPattern(relationships[i], joinsSpec, env);
|
|
1012
|
+
}
|
|
1013
|
+
const resolver = await getResolverForPath(inst.name, moduleName, env);
|
|
1014
|
+
const result: Result = await resolver.queryByJoin(inst, joinsSpec, normIntoSpec);
|
|
1015
|
+
env.setLastResult(result);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
async function walkJoinQueryPattern(
|
|
1019
|
+
rp: RelationshipPattern,
|
|
1020
|
+
joinsSpec: JoinInfo[],
|
|
1021
|
+
env: Environment
|
|
1022
|
+
): Promise<JoinInfo[]> {
|
|
1023
|
+
const crudMap = rp.pattern.crudMap;
|
|
1024
|
+
if (crudMap) {
|
|
1025
|
+
let subJoins: JoinInfo[] | undefined;
|
|
1026
|
+
if (crudMap.relationships && crudMap.relationships.length > 0) {
|
|
1027
|
+
subJoins = new Array<JoinInfo>();
|
|
1028
|
+
for (let i = 0; i < crudMap.relationships.length; ++i) {
|
|
1029
|
+
await walkJoinQueryPattern(crudMap.relationships[i], subJoins, env);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
const qInst = await patternToInstance(crudMap.name, crudMap.attributes, env);
|
|
1033
|
+
joinsSpec.push({
|
|
1034
|
+
relationship: getRelationship(rp.name, qInst.moduleName),
|
|
1035
|
+
queryInstance: qInst,
|
|
1036
|
+
subJoins: subJoins,
|
|
1037
|
+
});
|
|
1038
|
+
return joinsSpec;
|
|
1039
|
+
} else {
|
|
1040
|
+
throw new Error(`Expected a query for relationship ${rp.name}`);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
async function handleAgentInvocation(agentEventInst: Instance, env: Environment): Promise<void> {
|
|
1045
|
+
const agent: Agent = await findAgentByName(agentEventInst.name, env);
|
|
1046
|
+
await agent.invoke(agentEventInst.lookup('message'), env);
|
|
1047
|
+
const result: string = env.getLastResult();
|
|
1048
|
+
if (agent.isPlanner()) {
|
|
1049
|
+
logger.debug(`Agent ${agent.name} generated pattern: ${result}`);
|
|
1050
|
+
if (result.trimStart().startsWith('workflow')) {
|
|
1051
|
+
await parseWorkflow(result); // check for errors
|
|
1052
|
+
return;
|
|
1053
|
+
} else {
|
|
1054
|
+
env.setLastResult(await parseAndEvaluateStatement(result, undefined, env));
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
async function evaluateUpsert(upsert: Upsert, env: Environment): Promise<void> {
|
|
1060
|
+
env.setInUpsertMode(true);
|
|
1061
|
+
try {
|
|
1062
|
+
await evaluateCrudMap(upsert.pattern, env);
|
|
1063
|
+
} finally {
|
|
1064
|
+
env.setInUpsertMode(false);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
async function evaluateForEach(forEach: ForEach, env: Environment): Promise<void> {
|
|
1069
|
+
const loopVar: string = forEach.var;
|
|
1070
|
+
await evaluatePattern(forEach.src, env);
|
|
1071
|
+
const src: Result = env.getLastResult();
|
|
1072
|
+
if (src instanceof Array && src.length > 0) {
|
|
1073
|
+
const loopEnv: Environment = Environment.from(env);
|
|
1074
|
+
for (let i = 0; i < src.length; ++i) {
|
|
1075
|
+
loopEnv.bind(loopVar, src[i]);
|
|
1076
|
+
await evaluateStatements(forEach.statements, loopEnv);
|
|
1077
|
+
}
|
|
1078
|
+
env.setLastResult(loopEnv.getLastResult());
|
|
1079
|
+
} else {
|
|
1080
|
+
env.setLastResult(EmptyResult);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
async function evaluateIf(ifStmt: If, env: Environment): Promise<void> {
|
|
1085
|
+
await evaluateExpression(ifStmt.cond, env);
|
|
1086
|
+
if (env.getLastResult()) {
|
|
1087
|
+
await evaluateStatements(ifStmt.statements, env);
|
|
1088
|
+
} else if (ifStmt.else != undefined) {
|
|
1089
|
+
await evaluateStatements(ifStmt.else.statements, env);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
async function evaluateDeleteHelper(
|
|
1094
|
+
pattern: Pattern,
|
|
1095
|
+
purge: boolean,
|
|
1096
|
+
env: Environment
|
|
1097
|
+
): Promise<void> {
|
|
1098
|
+
const newEnv = Environment.from(env).setInDeleteMode(true);
|
|
1099
|
+
await evaluatePattern(pattern, newEnv);
|
|
1100
|
+
const inst: Instance[] | Instance = newEnv.getLastResult();
|
|
1101
|
+
let resolver: Resolver = Resolver.Default;
|
|
1102
|
+
if (inst instanceof Array) {
|
|
1103
|
+
if (inst.length > 0) {
|
|
1104
|
+
resolver = await getResolverForPath(inst[0].name, inst[0].moduleName, newEnv);
|
|
1105
|
+
const finalResult: Array<any> = new Array<any>();
|
|
1106
|
+
for (let i = 0; i < inst.length; ++i) {
|
|
1107
|
+
await runPreDeleteEvents(inst[i], env);
|
|
1108
|
+
const r: any = await resolver.deleteInstance(inst[i], purge);
|
|
1109
|
+
await runPostDeleteEvents(inst[i], env);
|
|
1110
|
+
finalResult.push(r);
|
|
1111
|
+
}
|
|
1112
|
+
newEnv.setLastResult(finalResult);
|
|
1113
|
+
} else {
|
|
1114
|
+
newEnv.setLastResult(inst);
|
|
1115
|
+
}
|
|
1116
|
+
} else {
|
|
1117
|
+
resolver = await getResolverForPath(inst.name, inst.moduleName, newEnv);
|
|
1118
|
+
await runPreDeleteEvents(inst, env);
|
|
1119
|
+
const r: Instance | null = await resolver.deleteInstance(inst, purge);
|
|
1120
|
+
await runPostDeleteEvents(inst, env);
|
|
1121
|
+
newEnv.setLastResult(r);
|
|
1122
|
+
}
|
|
1123
|
+
env.setLastResult(newEnv.getLastResult());
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
async function evaluateDelete(delStmt: Delete, env: Environment): Promise<void> {
|
|
1127
|
+
await evaluateDeleteHelper(delStmt.pattern, false, env);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
async function evaluatePurge(purgeStmt: Purge, env: Environment): Promise<void> {
|
|
1131
|
+
await evaluateDeleteHelper(purgeStmt.pattern, true, env);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
async function evaluateExpression(expr: Expr, env: Environment): Promise<void> {
|
|
1135
|
+
let result: Result = EmptyResult;
|
|
1136
|
+
if (isBinExpr(expr)) {
|
|
1137
|
+
await evaluateExpression(expr.e1, env);
|
|
1138
|
+
const v1 = env.getLastResult();
|
|
1139
|
+
if (expr.op == 'or') {
|
|
1140
|
+
if (v1) return;
|
|
1141
|
+
await evaluateExpression(expr.e2, env);
|
|
1142
|
+
return;
|
|
1143
|
+
} else if (expr.op == 'and') {
|
|
1144
|
+
if (!v1) return;
|
|
1145
|
+
await evaluateExpression(expr.e2, env);
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
await evaluateExpression(expr.e2, env);
|
|
1149
|
+
const v2 = env.getLastResult();
|
|
1150
|
+
switch (expr.op) {
|
|
1151
|
+
// arithmetic operators
|
|
1152
|
+
case '+':
|
|
1153
|
+
result = v1 + v2;
|
|
1154
|
+
break;
|
|
1155
|
+
case '-':
|
|
1156
|
+
result = v1 - v2;
|
|
1157
|
+
break;
|
|
1158
|
+
case '*':
|
|
1159
|
+
result = v1 * v2;
|
|
1160
|
+
break;
|
|
1161
|
+
case '/':
|
|
1162
|
+
result = v1 / v2;
|
|
1163
|
+
break;
|
|
1164
|
+
// comparison operators
|
|
1165
|
+
case '=':
|
|
1166
|
+
result = v1 == v2;
|
|
1167
|
+
break;
|
|
1168
|
+
case '<':
|
|
1169
|
+
result = v1 < v2;
|
|
1170
|
+
break;
|
|
1171
|
+
case '>':
|
|
1172
|
+
result = v1 > v2;
|
|
1173
|
+
break;
|
|
1174
|
+
case '<=':
|
|
1175
|
+
result = v1 <= v2;
|
|
1176
|
+
break;
|
|
1177
|
+
case '>=':
|
|
1178
|
+
result = v1 >= v2;
|
|
1179
|
+
break;
|
|
1180
|
+
case '<>':
|
|
1181
|
+
result = v1 != v2;
|
|
1182
|
+
break;
|
|
1183
|
+
case 'like':
|
|
1184
|
+
result = v1.startsWith(v2);
|
|
1185
|
+
break;
|
|
1186
|
+
case 'in':
|
|
1187
|
+
result = v2.find((x: any) => {
|
|
1188
|
+
x == v1;
|
|
1189
|
+
});
|
|
1190
|
+
break;
|
|
1191
|
+
default:
|
|
1192
|
+
throw new Error(`Unrecognized binary operator: ${expr.op}`);
|
|
1193
|
+
}
|
|
1194
|
+
} else if (isNegExpr(expr)) {
|
|
1195
|
+
await evaluateExpression(expr.ne, env);
|
|
1196
|
+
result = -1 * env.getLastResult();
|
|
1197
|
+
} else if (isGroup(expr)) {
|
|
1198
|
+
await evaluateExpression(expr.ge, env);
|
|
1199
|
+
result = env.getLastResult();
|
|
1200
|
+
} else if (isLiteral(expr)) {
|
|
1201
|
+
await evaluateLiteral(expr, env);
|
|
1202
|
+
return;
|
|
1203
|
+
} else if (isNotExpr(expr)) {
|
|
1204
|
+
await evaluateExpression(expr.ne, env);
|
|
1205
|
+
result = !env.getLastResult();
|
|
1206
|
+
}
|
|
1207
|
+
env.setLastResult(result);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
async function getRef(r: string, src: any, env: Environment): Promise<Result> {
|
|
1211
|
+
if (src instanceof Instance) return src.lookup(r);
|
|
1212
|
+
else if (src instanceof Map) return src.get(r);
|
|
1213
|
+
else if (src instanceof Object) return src[r];
|
|
1214
|
+
else if (isPath(src)) return await getRef(r, await dereferencePath(src, env), env);
|
|
1215
|
+
else return undefined;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
async function followReference(env: Environment, s: string): Promise<Result> {
|
|
1219
|
+
const refs: string[] = splitRefs(s);
|
|
1220
|
+
let result: Result = EmptyResult;
|
|
1221
|
+
let src: any = env;
|
|
1222
|
+
for (let i = 0; i < refs.length; ++i) {
|
|
1223
|
+
const r: string = refs[i];
|
|
1224
|
+
const v: Result | undefined = await getRef(r, src, env);
|
|
1225
|
+
if (v == undefined) return EmptyResult;
|
|
1226
|
+
result = v;
|
|
1227
|
+
src = result;
|
|
1228
|
+
}
|
|
1229
|
+
return result;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
async function dereferencePath(path: string, env: Environment): Promise<Result> {
|
|
1233
|
+
const fqName = fqNameFromPath(path);
|
|
1234
|
+
if (fqName == undefined) {
|
|
1235
|
+
throw new Error(`Failed to deduce entry-name from path - ${path}`);
|
|
1236
|
+
}
|
|
1237
|
+
const newEnv = new Environment('path-deref', env);
|
|
1238
|
+
await parseAndEvaluateStatement(
|
|
1239
|
+
`{${fqName} {${PathAttributeNameQuery} "${path}"}}`,
|
|
1240
|
+
env.getAuthContextUserId(),
|
|
1241
|
+
newEnv
|
|
1242
|
+
);
|
|
1243
|
+
const result: Result = newEnv.getLastResult();
|
|
1244
|
+
if (result && result instanceof Array && result.length > 0) {
|
|
1245
|
+
return result[0];
|
|
1246
|
+
}
|
|
1247
|
+
return undefined;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
async function applyFn(fnCall: FnCall, env: Environment, isAsync: boolean): Promise<void> {
|
|
1251
|
+
const fnName: string | undefined = fnCall.name;
|
|
1252
|
+
if (fnName != undefined) {
|
|
1253
|
+
let args: Array<Result> | null = null;
|
|
1254
|
+
if (fnCall.args != undefined) {
|
|
1255
|
+
args = new Array<Result>();
|
|
1256
|
+
for (let i = 0; i < fnCall.args.length; ++i) {
|
|
1257
|
+
await evaluateLiteral(fnCall.args[i], env);
|
|
1258
|
+
args.push(env.getLastResult());
|
|
1259
|
+
}
|
|
1260
|
+
args.push(env);
|
|
1261
|
+
}
|
|
1262
|
+
const r: Result = await invokeModuleFn(fnName, args, isAsync);
|
|
1263
|
+
env.setLastResult(r);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
async function realizeArray(array: ArrayLiteral, env: Environment): Promise<void> {
|
|
1268
|
+
const result: Array<Result> = new Array<Result>();
|
|
1269
|
+
for (let i = 0; i < array.vals.length; ++i) {
|
|
1270
|
+
await evaluateStatement(array.vals[i], env);
|
|
1271
|
+
result.push(env.getLastResult());
|
|
1272
|
+
}
|
|
1273
|
+
env.setLastResult(result);
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
async function realizeMap(mapLiteral: MapLiteral, env: Environment): Promise<void> {
|
|
1277
|
+
const result: Map<string, Result> = new Map();
|
|
1278
|
+
for (let i = 0; i < mapLiteral.entries.length; ++i) {
|
|
1279
|
+
const entry = mapLiteral.entries[i];
|
|
1280
|
+
const k = getMapKey(entry.key);
|
|
1281
|
+
await evaluateLiteral(entry.value, env);
|
|
1282
|
+
result.set(k, env.getLastResult());
|
|
1283
|
+
}
|
|
1284
|
+
env.setLastResult(Object.fromEntries(result.entries()));
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
async function runPrePostEvents(
|
|
1288
|
+
crudType: CrudType,
|
|
1289
|
+
pre: boolean,
|
|
1290
|
+
inst: Instance,
|
|
1291
|
+
env: Environment
|
|
1292
|
+
) {
|
|
1293
|
+
const trigInfo = pre
|
|
1294
|
+
? inst.record.getPreTriggerInfo(crudType)
|
|
1295
|
+
: inst.record.getPostTriggerInfo(crudType);
|
|
1296
|
+
if (trigInfo) {
|
|
1297
|
+
const p = splitFqName(trigInfo.eventName);
|
|
1298
|
+
const moduleName = p.hasModule() ? p.getModuleName() : inst.record.moduleName;
|
|
1299
|
+
const eventInst: Instance = makeInstance(
|
|
1300
|
+
moduleName,
|
|
1301
|
+
p.getEntryName(),
|
|
1302
|
+
newInstanceAttributes().set(inst.record.name, inst)
|
|
1303
|
+
);
|
|
1304
|
+
const authContext = env.getActiveAuthContext();
|
|
1305
|
+
if (authContext) eventInst.setAuthContext(authContext);
|
|
1306
|
+
const prefix = `${pre ? 'Pre' : 'Post'}-${CrudType[crudType]} ${inst.record.getFqName()}`;
|
|
1307
|
+
const callback = (value: Result) => {
|
|
1308
|
+
logger.debug(`${prefix}: ${value}`);
|
|
1309
|
+
};
|
|
1310
|
+
const catchHandler = (reason: any) => {
|
|
1311
|
+
logger.error(`${prefix}: ${reason}`);
|
|
1312
|
+
};
|
|
1313
|
+
if (trigInfo.async) {
|
|
1314
|
+
evaluate(eventInst, callback).catch(catchHandler);
|
|
1315
|
+
} else {
|
|
1316
|
+
await evaluate(eventInst, callback, env).catch(catchHandler);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
async function runPreCreateEvents(inst: Instance, env: Environment) {
|
|
1322
|
+
await runPrePostEvents(CrudType.CREATE, true, inst, env);
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
async function runPostCreateEvents(inst: Instance, env: Environment) {
|
|
1326
|
+
if (inst.requireAudit()) {
|
|
1327
|
+
await addCreateAudit(inst.getPath(), env);
|
|
1328
|
+
}
|
|
1329
|
+
await runPrePostEvents(CrudType.CREATE, false, inst, env);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
async function runPreUpdateEvents(inst: Instance, env: Environment) {
|
|
1333
|
+
await runPrePostEvents(CrudType.UPDATE, true, inst, env);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
async function runPostUpdateEvents(inst: Instance, env: Environment) {
|
|
1337
|
+
if (inst.requireAudit()) {
|
|
1338
|
+
await addUpdateAudit(inst.getPath(), undefined, env);
|
|
1339
|
+
}
|
|
1340
|
+
await runPrePostEvents(CrudType.UPDATE, false, inst, env);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
async function runPreDeleteEvents(inst: Instance, env: Environment) {
|
|
1344
|
+
await runPrePostEvents(CrudType.DELETE, true, inst, env);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
async function runPostDeleteEvents(inst: Instance, env: Environment) {
|
|
1348
|
+
if (inst.requireAudit()) {
|
|
1349
|
+
await addDeleteAudit(inst.getPath(), undefined, env);
|
|
1350
|
+
}
|
|
1351
|
+
await runPrePostEvents(CrudType.DELETE, false, inst, env);
|
|
1352
|
+
}
|