agentlang 0.7.8 → 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.
Files changed (129) hide show
  1. package/out/api/http.d.ts.map +1 -1
  2. package/out/api/http.js +8 -1
  3. package/out/api/http.js.map +1 -1
  4. package/out/cli/main.d.ts.map +1 -1
  5. package/out/cli/main.js +33 -2
  6. package/out/cli/main.js.map +1 -1
  7. package/out/extension/main.cjs +250 -250
  8. package/out/extension/main.cjs.map +2 -2
  9. package/out/language/agentlang-validator.d.ts +1 -2
  10. package/out/language/agentlang-validator.d.ts.map +1 -1
  11. package/out/language/agentlang-validator.js +0 -39
  12. package/out/language/agentlang-validator.js.map +1 -1
  13. package/out/language/generated/ast.d.ts +62 -11
  14. package/out/language/generated/ast.d.ts.map +1 -1
  15. package/out/language/generated/ast.js +75 -3
  16. package/out/language/generated/ast.js.map +1 -1
  17. package/out/language/generated/grammar.d.ts.map +1 -1
  18. package/out/language/generated/grammar.js +758 -239
  19. package/out/language/generated/grammar.js.map +1 -1
  20. package/out/language/main.cjs +1370 -824
  21. package/out/language/main.cjs.map +4 -4
  22. package/out/language/parser.d.ts +1 -0
  23. package/out/language/parser.d.ts.map +1 -1
  24. package/out/language/parser.js +44 -7
  25. package/out/language/parser.js.map +1 -1
  26. package/out/language/syntax.d.ts +1 -1
  27. package/out/language/syntax.d.ts.map +1 -1
  28. package/out/language/syntax.js +22 -13
  29. package/out/language/syntax.js.map +1 -1
  30. package/out/runtime/api.d.ts +4 -0
  31. package/out/runtime/api.d.ts.map +1 -1
  32. package/out/runtime/api.js +9 -0
  33. package/out/runtime/api.js.map +1 -1
  34. package/out/runtime/auth/cognito.d.ts.map +1 -1
  35. package/out/runtime/auth/cognito.js +4 -4
  36. package/out/runtime/auth/cognito.js.map +1 -1
  37. package/out/runtime/auth/defs.d.ts +9 -1
  38. package/out/runtime/auth/defs.d.ts.map +1 -1
  39. package/out/runtime/auth/defs.js +23 -2
  40. package/out/runtime/auth/defs.js.map +1 -1
  41. package/out/runtime/defs.d.ts +5 -0
  42. package/out/runtime/defs.d.ts.map +1 -1
  43. package/out/runtime/defs.js +16 -0
  44. package/out/runtime/defs.js.map +1 -1
  45. package/out/runtime/exec-graph.js +1 -1
  46. package/out/runtime/exec-graph.js.map +1 -1
  47. package/out/runtime/interpreter.d.ts +6 -1
  48. package/out/runtime/interpreter.d.ts.map +1 -1
  49. package/out/runtime/interpreter.js +144 -112
  50. package/out/runtime/interpreter.js.map +1 -1
  51. package/out/runtime/loader.d.ts +1 -1
  52. package/out/runtime/loader.d.ts.map +1 -1
  53. package/out/runtime/loader.js +74 -27
  54. package/out/runtime/loader.js.map +1 -1
  55. package/out/runtime/module.d.ts +41 -11
  56. package/out/runtime/module.d.ts.map +1 -1
  57. package/out/runtime/module.js +238 -50
  58. package/out/runtime/module.js.map +1 -1
  59. package/out/runtime/modules/ai.d.ts.map +1 -1
  60. package/out/runtime/modules/ai.js +13 -6
  61. package/out/runtime/modules/ai.js.map +1 -1
  62. package/out/runtime/modules/auth.d.ts +2 -1
  63. package/out/runtime/modules/auth.d.ts.map +1 -1
  64. package/out/runtime/modules/auth.js +93 -3
  65. package/out/runtime/modules/auth.js.map +1 -1
  66. package/out/runtime/modules/core.d.ts +7 -5
  67. package/out/runtime/modules/core.d.ts.map +1 -1
  68. package/out/runtime/modules/core.js +93 -16
  69. package/out/runtime/modules/core.js.map +1 -1
  70. package/out/runtime/monitor.d.ts.map +1 -1
  71. package/out/runtime/monitor.js +1 -0
  72. package/out/runtime/monitor.js.map +1 -1
  73. package/out/runtime/resolvers/interface.d.ts +6 -1
  74. package/out/runtime/resolvers/interface.d.ts.map +1 -1
  75. package/out/runtime/resolvers/interface.js +2 -2
  76. package/out/runtime/resolvers/interface.js.map +1 -1
  77. package/out/runtime/resolvers/sqldb/database.d.ts +19 -2
  78. package/out/runtime/resolvers/sqldb/database.d.ts.map +1 -1
  79. package/out/runtime/resolvers/sqldb/database.js +107 -21
  80. package/out/runtime/resolvers/sqldb/database.js.map +1 -1
  81. package/out/runtime/resolvers/sqldb/dbutil.d.ts +1 -0
  82. package/out/runtime/resolvers/sqldb/dbutil.d.ts.map +1 -1
  83. package/out/runtime/resolvers/sqldb/dbutil.js +25 -3
  84. package/out/runtime/resolvers/sqldb/dbutil.js.map +1 -1
  85. package/out/runtime/resolvers/sqldb/impl.d.ts +3 -2
  86. package/out/runtime/resolvers/sqldb/impl.d.ts.map +1 -1
  87. package/out/runtime/resolvers/sqldb/impl.js +80 -6
  88. package/out/runtime/resolvers/sqldb/impl.js.map +1 -1
  89. package/out/runtime/state.d.ts +58 -0
  90. package/out/runtime/state.d.ts.map +1 -1
  91. package/out/runtime/state.js +12 -0
  92. package/out/runtime/state.js.map +1 -1
  93. package/out/runtime/util.d.ts +1 -1
  94. package/out/runtime/util.d.ts.map +1 -1
  95. package/out/runtime/util.js +27 -13
  96. package/out/runtime/util.js.map +1 -1
  97. package/out/syntaxes/agentlang.monarch.js +1 -1
  98. package/out/syntaxes/agentlang.monarch.js.map +1 -1
  99. package/out/utils/fs-utils.d.ts +10 -0
  100. package/out/utils/fs-utils.d.ts.map +1 -1
  101. package/out/utils/fs-utils.js +14 -0
  102. package/out/utils/fs-utils.js.map +1 -1
  103. package/package.json +2 -1
  104. package/src/api/http.ts +8 -0
  105. package/src/cli/main.ts +38 -2
  106. package/src/language/agentlang-validator.ts +1 -51
  107. package/src/language/agentlang.langium +17 -4
  108. package/src/language/generated/ast.ts +147 -13
  109. package/src/language/generated/grammar.ts +758 -239
  110. package/src/language/parser.ts +43 -8
  111. package/src/language/syntax.ts +25 -12
  112. package/src/runtime/api.ts +16 -0
  113. package/src/runtime/auth/defs.ts +25 -2
  114. package/src/runtime/defs.ts +8 -0
  115. package/src/runtime/interpreter.ts +104 -76
  116. package/src/runtime/loader.ts +75 -25
  117. package/src/runtime/module.ts +194 -32
  118. package/src/runtime/modules/ai.ts +10 -4
  119. package/src/runtime/modules/auth.ts +1 -0
  120. package/src/runtime/modules/core.ts +99 -23
  121. package/src/runtime/monitor.ts +1 -0
  122. package/src/runtime/resolvers/interface.ts +9 -2
  123. package/src/runtime/resolvers/sqldb/database.ts +68 -17
  124. package/src/runtime/resolvers/sqldb/dbutil.ts +28 -6
  125. package/src/runtime/resolvers/sqldb/impl.ts +86 -14
  126. package/src/runtime/state.ts +14 -0
  127. package/src/runtime/util.ts +25 -12
  128. package/src/syntaxes/agentlang.monarch.ts +1 -1
  129. package/src/utils/fs-utils.ts +16 -0
@@ -8,6 +8,7 @@ import {
8
8
  isString,
9
9
  restoreSpecialChars,
10
10
  makeCoreModuleName,
11
+ nameToPath,
11
12
  } from '../util.js';
12
13
  import {
13
14
  fetchModule,
@@ -27,7 +28,7 @@ import {
27
28
  } from '../interpreter.js';
28
29
  import { logger } from '../logger.js';
29
30
  import { Statement } from '../../language/generated/ast.js';
30
- import { parseModule, parseStatements } from '../../language/parser.js';
31
+ import { objectToQueryPattern, parseModule, parseStatements } from '../../language/parser.js';
31
32
  import { GenericResolver, Resolver } from '../resolvers/interface.js';
32
33
  import {
33
34
  FlowSuspensionTag,
@@ -48,7 +49,8 @@ entity timer {
48
49
  duration Int,
49
50
  unit @enum("millisecond", "second", "minute", "hour") @default("second"),
50
51
  trigger String,
51
- status @enum("I", "C", "R") @default("I") // Inited, Cancelled, Running
52
+ repeat Boolean @default(true),
53
+ status @enum("I", "C", "R") @default("I") @indexed // Inited, Cancelled, Running
52
54
  }
53
55
 
54
56
  entity auditlog {
@@ -56,7 +58,7 @@ entity auditlog {
56
58
  action @enum("c", "d", "u"), // Create, Delete, Update
57
59
  resource String, // __path__
58
60
  timestamp DateTime @default(now()),
59
- previous_value Any @optional,
61
+ diff Any @optional,
60
62
  user String,
61
63
  token String @optional
62
64
  }
@@ -161,6 +163,14 @@ entity Migration {
161
163
  ups String @optional,
162
164
  downs String @optional
163
165
  }
166
+
167
+ @public event Query {
168
+ q Any
169
+ }
170
+
171
+ workflow Query {
172
+ await Core.doRawQuery(Query.q)
173
+ }
164
174
  `;
165
175
 
166
176
  export const CoreModules: string[] = [];
@@ -183,25 +193,94 @@ export function registerCoreModules() {
183
193
  });
184
194
  }
185
195
 
186
- export function setTimerRunning(timerInst: Instance) {
187
- timerInst.attributes.set('status', 'R');
196
+ function isTimerCancelled(inst: Instance): boolean {
197
+ return inst.lookup('status') === 'C';
188
198
  }
189
199
 
190
- export async function maybeCancelTimer(name: string, timer: NodeJS.Timeout, env: Environment) {
200
+ // If the timer is deleted or its status is set to 'C' (cancelled), then clear the associated timer.
201
+ async function maybeClearTimer(name: string, timer: NodeJS.Timeout, env: Environment) {
191
202
  await parseAndEvaluateStatement(`{agentlang/timer {name? "${name}"}}`, undefined, env).then(
192
203
  (result: any) => {
193
- if (result === null || (result instanceof Array && result.length == 0)) {
204
+ if (
205
+ result === null ||
206
+ (result instanceof Array && (result.length == 0 || isTimerCancelled(result[0])))
207
+ ) {
194
208
  clearInterval(timer);
195
209
  }
196
210
  }
197
211
  );
198
212
  }
199
213
 
214
+ export function triggerTimer(timerInst: Instance): Instance {
215
+ const dur = timerInst.lookup('duration');
216
+ const unit = timerInst.lookup('unit');
217
+ let millisecs = 0;
218
+ switch (unit) {
219
+ case 'millisecond': {
220
+ millisecs = dur;
221
+ break;
222
+ }
223
+ case 'second': {
224
+ millisecs = dur * 1000;
225
+ break;
226
+ }
227
+ case 'minute': {
228
+ millisecs = dur * 60 * 1000;
229
+ break;
230
+ }
231
+ case 'hour': {
232
+ millisecs = dur * 60 * 60 * 1000;
233
+ break;
234
+ }
235
+ }
236
+ const eventName = nameToPath(timerInst.lookup('trigger'));
237
+ const m = eventName.hasModule() ? eventName.getModuleName() : timerInst.moduleName;
238
+ const n = eventName.getEntryName();
239
+ const inst = makeInstance(m, n, newInstanceAttributes());
240
+ const name = timerInst.lookup('name');
241
+ const repeat = timerInst.lookup('repeat');
242
+ const timer = setInterval(async () => {
243
+ const env = new Environment();
244
+ try {
245
+ await evaluate(
246
+ inst,
247
+ (result: any) => logger.debug(`Timer ${name} ran with result ${result}`),
248
+ env
249
+ );
250
+ await env.commitAllTransactions();
251
+ if (!repeat) clearInterval(timer);
252
+ else await maybeClearTimer(name, timer, env);
253
+ } catch (reason: any) {
254
+ logger.error(`Timer ${name} raised error: ${reason}`);
255
+ }
256
+ }, millisecs);
257
+ timerInst.attributes.set('status', 'R');
258
+ return timerInst;
259
+ }
260
+
261
+ export async function saveTimerStatus(timerInst: Instance): Promise<boolean> {
262
+ const name = timerInst.lookup('name');
263
+ const status = timerInst.lookup('status');
264
+ const env = new Environment();
265
+ try {
266
+ await parseAndEvaluateStatement(`{agentlang/timer {name? "${name}", "status": "${status}"}}`);
267
+ await env.commitAllTransactions();
268
+ } catch (reason: any) {
269
+ logger.warn(`Failed to save status of timer ${name} - ${reason}`);
270
+ return false;
271
+ }
272
+ return true;
273
+ }
274
+
275
+ export async function lookupTimersWithRunningStatus(): Promise<Instance[]> {
276
+ return await parseAndEvaluateStatement(`{agentlang/timer {status? "R"}}`);
277
+ }
278
+
200
279
  async function addAudit(
201
280
  env: Environment,
202
281
  action: 'c' | 'd' | 'u',
203
282
  resource: string,
204
- previuos_value?: Instance
283
+ diff?: object
205
284
  ) {
206
285
  const user = env.getActiveUser();
207
286
  const token = env.getActiveToken();
@@ -211,7 +290,7 @@ async function addAudit(
211
290
  `{agentlang/auditlog {
212
291
  action "${action}",
213
292
  resource "${resource}",
214
- previous_value "${previuos_value ? escapeSpecialChars(JSON.stringify(previuos_value.asObject())) : ''}",
293
+ diff "${diff ? escapeSpecialChars(JSON.stringify(diff)) : ''}",
215
294
  user "${user}",
216
295
  token "${token ? token : ''}"
217
296
  }}`,
@@ -225,24 +304,16 @@ async function addAudit(
225
304
  }
226
305
  }
227
306
 
228
- export async function addCreateAudit(resource: string, env: Environment) {
229
- await addAudit(env, 'c', resource);
307
+ export async function addCreateAudit(resource: string, env: Environment, init: object) {
308
+ await addAudit(env, 'c', resource, init);
230
309
  }
231
310
 
232
- export async function addDeleteAudit(
233
- resource: string,
234
- previous_value: Instance | undefined,
235
- env: Environment
236
- ) {
237
- await addAudit(env, 'd', resource, previous_value);
311
+ export async function addDeleteAudit(resource: string, diff: object | undefined, env: Environment) {
312
+ await addAudit(env, 'd', resource, diff);
238
313
  }
239
314
 
240
- export async function addUpdateAudit(
241
- resource: string,
242
- previous_value: Instance | undefined,
243
- env: Environment
244
- ) {
245
- await addAudit(env, 'u', resource, previous_value);
315
+ export async function addUpdateAudit(resource: string, diff: object | undefined, env: Environment) {
316
+ await addAudit(env, 'u', resource, diff);
246
317
  }
247
318
 
248
319
  export async function createSuspension(
@@ -664,3 +735,8 @@ export function migrationDowns(inst: Instance): string[] | undefined {
664
735
  }
665
736
  return undefined;
666
737
  }
738
+
739
+ export async function doRawQuery(q: any): Promise<any> {
740
+ const qs = objectToQueryPattern(q);
741
+ return await parseAndEvaluateStatement(qs);
742
+ }
@@ -289,6 +289,7 @@ export class Monitor {
289
289
 
290
290
  decrement(): Monitor {
291
291
  if (this.parent !== undefined) {
292
+ this.parent.totalLatency += this.totalLatency;
292
293
  return this.parent;
293
294
  }
294
295
  return this;
@@ -33,6 +33,12 @@ export function getSubscriptionEvent(resolverName: string): string | undefined {
33
33
  return subscriptionEvents.get(resolverName);
34
34
  }
35
35
 
36
+ export type WhereClause = {
37
+ attrName: string;
38
+ op: string;
39
+ qval: any;
40
+ };
41
+
36
42
  export class Resolver {
37
43
  protected authInfo: ResolverAuthInfo = DefaultAuthInfo;
38
44
  protected env: Environment | undefined;
@@ -131,10 +137,11 @@ export class Resolver {
131
137
  joinInfo: JoinInfo[],
132
138
  intoSpec: Map<string, string>,
133
139
  distinct: boolean = false,
134
- rawJoinSpec?: JoinSpec
140
+ rawJoinSpec?: JoinSpec[],
141
+ whereClauses?: WhereClause[]
135
142
  ): Promise<any> {
136
143
  return this.notImpl(
137
- `queryByJoin(${inst}, ${joinInfo}, ${intoSpec}, ${distinct} ${rawJoinSpec})`
144
+ `queryByJoin(${inst}, ${joinInfo}, ${intoSpec}, ${distinct}, ${rawJoinSpec}, ${whereClauses})`
138
145
  );
139
146
  }
140
147
 
@@ -41,6 +41,7 @@ import {
41
41
  } from '../../defs.js';
42
42
  import { saveMigration } from '../../modules/core.js';
43
43
  import { getAppSpec } from '../../loader.js';
44
+ import { WhereClause } from '../interface.js';
44
45
 
45
46
  export let defaultDataSource: DataSource | undefined;
46
47
 
@@ -880,17 +881,30 @@ function objectToRawWhereClause(queryObj: object, queryVals: any, tableName?: st
880
881
  }
881
882
  }
882
883
 
884
+ export type QuerySpec = {
885
+ queryObj: object | undefined;
886
+ queryVals: object | undefined;
887
+ aggregates: Map<string, string> | undefined;
888
+ groupBy: string[] | undefined;
889
+ orderBy: string[] | undefined;
890
+ orderByDesc: 'DESC' | 'ASC';
891
+ joinClauses: JoinClause[] | undefined;
892
+ intoSpec: Map<string, string> | undefined;
893
+ whereClauses: WhereClause[] | undefined;
894
+ distinct: boolean;
895
+ };
896
+
883
897
  export async function getMany(
884
898
  tableName: string,
885
- queryObj: object | undefined,
886
- queryVals: object | undefined,
887
- distinct: boolean,
899
+ querySpec: QuerySpec,
888
900
  ctx: DbContext
889
901
  ): Promise<any> {
890
902
  const alias: string = tableName.toLowerCase();
891
903
  const queryStr: string = withNotDeletedClause(
892
904
  alias,
893
- queryObj !== undefined ? objectToWhereClause(queryObj, queryVals, alias) : ''
905
+ querySpec.queryObj !== undefined
906
+ ? objectToWhereClause(querySpec.queryObj, querySpec.queryVals, alias)
907
+ : ''
894
908
  );
895
909
  let ownersJoinCond: string[] | undefined;
896
910
  let ot: string = '';
@@ -927,30 +941,54 @@ export async function getMany(
927
941
  const qb: SelectQueryBuilder<any> = getDatasourceForTransaction(ctx.txnId)
928
942
  .getRepository(tableName)
929
943
  .createQueryBuilder();
944
+ const hasAggregates = querySpec.aggregates !== undefined;
945
+ if (hasAggregates) {
946
+ qb.select([]);
947
+ querySpec.aggregates?.forEach((f: string, n: string) => {
948
+ qb.addSelect(f, n);
949
+ });
950
+ }
951
+ if (querySpec.groupBy !== undefined) {
952
+ querySpec.groupBy.forEach((gb: string) => {
953
+ qb.addGroupBy(gb);
954
+ });
955
+ }
956
+ if (querySpec.orderBy !== undefined) {
957
+ querySpec.orderBy.forEach((ob: string) => {
958
+ qb.addOrderBy(ob, querySpec.orderByDesc);
959
+ });
960
+ }
930
961
  if (ownersJoinCond) {
931
962
  qb.innerJoin(ot, otAlias, ownersJoinCond.join(' AND '));
932
963
  }
933
- if (distinct) {
964
+ if (querySpec.distinct) {
934
965
  qb.distinct(true);
935
966
  }
936
- qb.where(queryStr, queryVals);
937
- return await qb.getMany();
967
+ qb.where(queryStr, querySpec.queryVals);
968
+ if (hasAggregates) return await qb.getRawMany();
969
+ else return await qb.getMany();
938
970
  }
939
971
 
940
972
  export async function getManyByJoin(
941
973
  tableName: string,
942
- queryObj: object | undefined,
943
- queryVals: object | undefined,
944
- joinClauses: JoinClause[],
945
- intoSpec: Map<string, string>,
946
- distinct: boolean,
974
+ querySpec: QuerySpec,
947
975
  ctx: DbContext
948
976
  ): Promise<any> {
949
977
  const alias: string = tableName.toLowerCase();
950
- const queryStr: string = withNotDeletedClause(
978
+ let queryStr: string = withNotDeletedClause(
951
979
  alias,
952
- queryObj !== undefined ? objectToRawWhereClause(queryObj, queryVals, alias) : ''
980
+ querySpec.queryObj !== undefined
981
+ ? objectToRawWhereClause(querySpec.queryObj, querySpec.queryVals, alias)
982
+ : ''
953
983
  );
984
+ if (querySpec.whereClauses) {
985
+ const qs = new Array<string>();
986
+ querySpec.whereClauses.forEach((wc: WhereClause) => {
987
+ const v = isString(wc.qval) ? `'${wc.qval}'` : wc.qval;
988
+ qs.push(`${wc.attrName} ${wc.op} ${v}`);
989
+ });
990
+ queryStr = `${queryStr} AND ${qs.join(' AND ')}`;
991
+ }
954
992
  let ot: string = '';
955
993
  let otAlias: string = '';
956
994
  if (!ctx.isPermitted()) {
@@ -961,7 +999,7 @@ export async function getManyByJoin(
961
999
  if (!hasGlobalPerms) {
962
1000
  ot = ownersTable(tableName);
963
1001
  otAlias = ot.toLowerCase();
964
- joinClauses.push({
1002
+ querySpec.joinClauses?.push({
965
1003
  tableName: otAlias,
966
1004
  joinOn: [
967
1005
  makeJoinOn(`${otAlias}.path`, `${alias}.${PathAttributeName}`),
@@ -972,7 +1010,7 @@ export async function getManyByJoin(
972
1010
  }
973
1011
  }
974
1012
  const joinSql = new Array<string>();
975
- joinClauses.forEach((jc: JoinClause) => {
1013
+ querySpec.joinClauses?.forEach((jc: JoinClause) => {
976
1014
  const joinType = jc.joinType ? jc.joinType : 'inner join';
977
1015
  joinSql.push(
978
1016
  `${joinType} ${jc.tableName} as ${jc.tableName} on ${joinOnAsSql(jc.joinOn)} AND ${jc.tableName}.${DeletedFlagAttributeName} = false`
@@ -984,7 +1022,20 @@ export async function getManyByJoin(
984
1022
  }
985
1023
  }
986
1024
  });
987
- const sql = `SELECT ${distinct ? 'DISTINCT' : ''} ${intoSpecToSql(intoSpec)} FROM ${tableName} ${joinSql.join('\n')} WHERE ${queryStr}`;
1025
+ if (querySpec.intoSpec === undefined) {
1026
+ throw new Error('SELECT-INTO pattern is missing');
1027
+ }
1028
+ const intos = intoSpecToSql(querySpec.intoSpec);
1029
+ const aggrs =
1030
+ querySpec.aggregates !== undefined ? intoSpecToSql(querySpec.aggregates) : undefined;
1031
+ const cols = aggrs ? `${intos}, ${aggrs}` : intos;
1032
+ let sql = `SELECT ${querySpec.distinct ? 'DISTINCT' : ''} ${cols} FROM ${tableName} ${joinSql.join('\n')} WHERE ${queryStr}`;
1033
+ if (querySpec.groupBy !== undefined) {
1034
+ sql = `${sql} GROUP BY ${querySpec.groupBy.join(', ')}`;
1035
+ }
1036
+ if (querySpec.orderBy !== undefined) {
1037
+ sql = `${sql} ORDER BY ${querySpec.orderBy.join(', ')} ${querySpec.orderByDesc}`;
1038
+ }
988
1039
  logger.debug(`Join Query: ${sql}`);
989
1040
  const qb = getDatasourceForTransaction(ctx.txnId).getRepository(tableName).manager;
990
1041
  return await qb.query(sql);
@@ -28,8 +28,13 @@ import {
28
28
  Module,
29
29
  } from '../../module.js';
30
30
  import { buildGraph } from '../../relgraph.js';
31
- import { makeFqName } from '../../util.js';
32
- import { DeletedFlagAttributeName, FkSpec, ParentAttributeName, PathAttributeName } from '../../defs.js';
31
+ import { makeFqName, splitFqName, splitRefs } from '../../util.js';
32
+ import {
33
+ DeletedFlagAttributeName,
34
+ FkSpec,
35
+ ParentAttributeName,
36
+ PathAttributeName,
37
+ } from '../../defs.js';
33
38
 
34
39
  export const DefaultVectorDimension = 1536;
35
40
 
@@ -50,6 +55,22 @@ export function asTableReference(moduleName: string, ref: string): string {
50
55
  }
51
56
  }
52
57
 
58
+ export function asColumnReference(n: string, tableName: string, entityName: string, entityFqName: string, moduleName: string, quoted: boolean = false): string {
59
+ const refs = splitRefs(n);
60
+ const rlen = refs.length
61
+ if (rlen == 1 || refs[0] == entityName || refs[0] == entityFqName) {
62
+ const r = rlen == 1 ? refs[0] : refs[1]
63
+ return quoted ? `"${tableName}"."${r}"` : `${tableName}.${r}`;
64
+ } else {
65
+ const p = splitFqName(refs[0]);
66
+ if (p.length == 2) {
67
+ return quoted ? `"${asTableReference(p[0], p[1])}"."${refs[1]}"` : `${asTableReference(p[0], p[1])}.${refs[1]}`;
68
+ } else {
69
+ return quoted ? `"${asTableReference(moduleName, p[0])}"."${refs[1]}"` : `${asTableReference(moduleName, p[0])}.${refs[1]}`;
70
+ }
71
+ }
72
+ }
73
+
53
74
  export function modulesAsDbSchema(): TableSchema[] {
54
75
  const result: TableSchema[] = new Array<TableSchema>();
55
76
  getModuleNames().forEach((n: string) => {
@@ -96,11 +117,11 @@ export function modulesAsOrmSchema(): OrmSchema {
96
117
  }
97
118
  });
98
119
  entities.forEach((r: Record) => {
99
- const fks = r.getFkAttributeSpecs()
120
+ const fks = r.getFkAttributeSpecs();
100
121
  if (fks.length > 0) {
101
- fkSpecs.push(...fks)
122
+ fkSpecs.push(...fks);
102
123
  }
103
- })
124
+ });
104
125
  });
105
126
  return { entities: ents, vectorEntities: vects, fkSpecs };
106
127
  }
@@ -291,7 +312,8 @@ export function asSqlType(type: string): ColumnType {
291
312
  t == 'url' ||
292
313
  t == 'map' ||
293
314
  t == 'any' ||
294
- t == 'path'
315
+ t == 'path' ||
316
+ t == 'password'
295
317
  )
296
318
  return 'varchar';
297
319
  else if (t == 'int') return 'integer';
@@ -22,8 +22,8 @@ import {
22
22
  splitFqName,
23
23
  splitRefs,
24
24
  } from '../../util.js';
25
- import { JoinInfo, Resolver } from '../interface.js';
26
- import { asTableReference } from './dbutil.js';
25
+ import { JoinInfo, Resolver, WhereClause } from '../interface.js';
26
+ import { asColumnReference, asTableReference } from './dbutil.js';
27
27
  import {
28
28
  getMany,
29
29
  insertRow,
@@ -43,8 +43,9 @@ import {
43
43
  JoinOn,
44
44
  makeJoinOn,
45
45
  getManyByJoin,
46
+ QuerySpec,
46
47
  } from './database.js';
47
- import { Environment } from '../../interpreter.js';
48
+ import { AggregateFunctionCall, Environment } from '../../interpreter.js';
48
49
  import { OpenAIEmbeddings } from '@langchain/openai';
49
50
  import { Embeddings } from '@langchain/core/embeddings';
50
51
  import { DeletedFlagAttributeName, ParentAttributeName, PathAttributeName } from '../../defs.js';
@@ -164,6 +165,26 @@ export class SqlDbResolver extends Resolver {
164
165
  return Instance.clone(inst).mergeAttributes(newAttrs);
165
166
  }
166
167
 
168
+ private static normalizedAggregates(
169
+ inst: Instance,
170
+ tableName: string
171
+ ): Map<string, string> | undefined {
172
+ if (inst.aggregates !== undefined) {
173
+ const entn = inst.name;
174
+ const entfqn = inst.getFqName();
175
+ const mn = inst.moduleName;
176
+ const result = new Map<string, string>();
177
+ inst.aggregates.forEach((f: AggregateFunctionCall, n: string) => {
178
+ const args = f.args.map((v: string) => {
179
+ return asColumnReference(v, tableName, entn, entfqn, mn, true);
180
+ });
181
+ result.set(n, `${f.name}(${args.join(', ')})`);
182
+ });
183
+ return result;
184
+ }
185
+ return undefined;
186
+ }
187
+
167
188
  static EmptyResultSet: Array<Instance> = new Array<Instance>();
168
189
 
169
190
  public override async queryInstances(
@@ -178,7 +199,32 @@ export class SqlDbResolver extends Resolver {
178
199
  const ctx = this.getDbContext(fqName);
179
200
  const qattrs: any = queryAll ? undefined : inst.queryAttributesAsObject();
180
201
  const qvals: any = queryAll ? undefined : inst.queryAttributeValuesAsObject();
181
- const rslt: any = await getMany(tableName, qattrs, qvals, distinct, ctx);
202
+ const groupBy = inst.groupBy
203
+ ? inst.groupBy.map((gb: string) => {
204
+ return asColumnReference(gb, tableName, inst.name, fqName, inst.moduleName, true);
205
+ })
206
+ : undefined;
207
+ const orderBy = inst.orderBy
208
+ ? inst.orderBy.map((ob: string) => {
209
+ return asColumnReference(ob, tableName, inst.name, fqName, inst.moduleName, true);
210
+ })
211
+ : undefined;
212
+ const orderByDesc = inst.orderByDesc ? 'DESC' : 'ASC';
213
+ const aggregates = SqlDbResolver.normalizedAggregates(inst, tableName);
214
+ const qspec: QuerySpec = {
215
+ queryObj: qattrs,
216
+ queryVals: qvals,
217
+ distinct,
218
+ groupBy,
219
+ orderBy,
220
+ orderByDesc,
221
+ aggregates,
222
+ joinClauses: undefined,
223
+ intoSpec: undefined,
224
+ whereClauses: undefined,
225
+ };
226
+ const readOnlyAttrs = inst.record.getWriteOnlyAttributes();
227
+ const rslt: any = await getMany(tableName, qspec, ctx);
182
228
  if (rslt instanceof Array) {
183
229
  result = new Array<Instance>();
184
230
  rslt.forEach((r: object) => {
@@ -187,6 +233,9 @@ export class SqlDbResolver extends Resolver {
187
233
  new Map(Object.entries(r))
188
234
  );
189
235
  attrs.delete(DeletedFlagAttributeName);
236
+ readOnlyAttrs?.forEach((n: string) => {
237
+ attrs.delete(n);
238
+ });
190
239
  result.push(Instance.newWithAttributes(inst, attrs));
191
240
  });
192
241
  }
@@ -266,12 +315,15 @@ export class SqlDbResolver extends Resolver {
266
315
  joinInfo: JoinInfo[],
267
316
  intoSpec: Map<string, string>,
268
317
  distinct: boolean = false,
269
- rawJoinSpec?: JoinSpec
318
+ rawJoinSpec?: JoinSpec[],
319
+ whereClauses?: WhereClause[]
270
320
  ): Promise<any> {
271
321
  const tableName = asTableReference(inst.moduleName, inst.name);
272
322
  const joinClauses: JoinClause[] = [];
273
323
  if (rawJoinSpec) {
274
- this.processRawJoinSpec(tableName, inst, rawJoinSpec, joinClauses);
324
+ rawJoinSpec.forEach((rjs: JoinSpec) => {
325
+ this.processRawJoinSpec(tableName, inst, rjs, joinClauses);
326
+ });
275
327
  } else {
276
328
  this.processJoinInfo(tableName, inst, joinInfo, joinClauses);
277
329
  }
@@ -280,15 +332,35 @@ export class SqlDbResolver extends Resolver {
280
332
  const mn = p.hasModule() ? p.getModuleName() : inst.moduleName;
281
333
  intoSpec.set(k, asTableReference(mn, p.getEntryName()));
282
334
  });
283
- const rslt: any = await getManyByJoin(
284
- tableName,
285
- inst.queryAttributesAsObject(),
286
- inst.queryAttributeValuesAsObject(),
335
+ const fqName = inst.getFqName();
336
+ const groupBy = inst.groupBy
337
+ ? inst.groupBy.map((gb: string) => {
338
+ return asColumnReference(gb, tableName, inst.name, fqName, inst.moduleName, true);
339
+ })
340
+ : undefined;
341
+ const orderBy = inst.orderBy
342
+ ? inst.orderBy.map((ob: string) => {
343
+ return asColumnReference(ob, tableName, inst.name, fqName, inst.moduleName, true);
344
+ })
345
+ : undefined;
346
+ const orderByDesc = inst.orderByDesc ? 'DESC' : 'ASC';
347
+ const aggregates = SqlDbResolver.normalizedAggregates(inst, tableName);
348
+ whereClauses?.forEach((wc: WhereClause) => {
349
+ wc.attrName = asColumnReference(wc.attrName, tableName, inst.name, fqName, inst.moduleName);
350
+ });
351
+ const qspec: QuerySpec = {
352
+ queryObj: inst.queryAttributesAsObject(),
353
+ queryVals: inst.queryAttributeValuesAsObject(),
354
+ distinct,
355
+ groupBy,
356
+ orderBy,
357
+ orderByDesc,
358
+ aggregates,
287
359
  joinClauses,
360
+ whereClauses,
288
361
  intoSpec,
289
- distinct,
290
- this.getDbContext(inst.getFqName())
291
- );
362
+ };
363
+ const rslt: any = await getManyByJoin(tableName, qspec, this.getDbContext(inst.getFqName()));
292
364
  return rslt;
293
365
  }
294
366
 
@@ -536,7 +608,7 @@ function maybeNormalizeAttributeNames(
536
608
  ks.forEach((k: string) => {
537
609
  const v = attrs.get(k);
538
610
  attrs.delete(k);
539
- attrs.set(k.substring(n + 1), v);
611
+ attrs.set(k.substring(n + 1) || k, v);
540
612
  });
541
613
  }
542
614
  return attrs;
@@ -116,6 +116,20 @@ export const ConfigSchema = z.object({
116
116
  level: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
117
117
  })
118
118
  .optional(),
119
+ retry: z
120
+ .array(
121
+ z.object({
122
+ name: z.string(),
123
+ attempts: z.number(),
124
+ backoff: z.object({
125
+ strategy: z.enum(['linear', 'exponential', 'constant']),
126
+ delay: z.number(),
127
+ magnitude: z.enum(['seconds', 'milliSeconds', 'minutes']),
128
+ factor: z.number(),
129
+ }),
130
+ })
131
+ )
132
+ .optional(),
119
133
  });
120
134
 
121
135
  export type Config = z.infer<typeof ConfigSchema>;
@@ -621,16 +621,18 @@ export function generateLoggerCallId() {
621
621
  const JS_PREFIX = '#js';
622
622
 
623
623
  export function preprocessRawConfig(rawConfig: any): any {
624
- const keys = Object.keys(rawConfig);
625
- keys.forEach((k: any) => {
626
- const v = rawConfig[k];
627
- if (isString(v) && v.startsWith(JS_PREFIX)) {
628
- const s = v.substring(3).trim();
629
- rawConfig[k] = eval(s);
630
- } else if (typeof v == 'object') {
631
- preprocessRawConfig(v);
632
- }
633
- });
624
+ if (rawConfig) {
625
+ const keys = Object.keys(rawConfig);
626
+ keys.forEach((k: any) => {
627
+ const v = rawConfig[k];
628
+ if (isString(v) && v.startsWith(JS_PREFIX)) {
629
+ const s = v.substring(3).trim();
630
+ rawConfig[k] = eval(s);
631
+ } else if (typeof v == 'object') {
632
+ preprocessRawConfig(v);
633
+ }
634
+ });
635
+ }
634
636
  return rawConfig;
635
637
  }
636
638
 
@@ -644,11 +646,22 @@ export function setScecretReader(f: ReadSecret) {
644
646
  globalThis.readSecret = f;
645
647
  }
646
648
 
647
- export function objectAsString(obj: any) {
649
+ export function objectAsString(obj: any, keyAsString: boolean = false) {
648
650
  const entries = new Array<string>();
649
651
  Object.entries(obj).forEach(([k, v]) => {
650
652
  const vv = typeof v === 'string' ? `"${v}"` : v;
651
- entries.push(`${k}: ${vv}`);
653
+ let fv = vv;
654
+ if (fv instanceof Array) {
655
+ fv = fv.map((v: any) => {
656
+ return objectAsString(v, true);
657
+ });
658
+ } else if (fv instanceof Object) {
659
+ fv = objectAsString(fv, true);
660
+ }
661
+ if (keyAsString) {
662
+ k = `"${k}"`;
663
+ }
664
+ entries.push(`${k}: ${fv}`);
652
665
  });
653
666
  return `{${entries.join(', ')}}`;
654
667
  }