jinaga-server 1.0.0 → 1.1.0

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 (63) hide show
  1. package/README.md +103 -0
  2. package/dist/authentication/authentication-device.d.ts +3 -1
  3. package/dist/authentication/authentication-device.js +3 -0
  4. package/dist/authentication/authentication-device.js.map +1 -1
  5. package/dist/authentication/authentication-impl.d.ts +3 -2
  6. package/dist/authentication/authentication-impl.js +3 -0
  7. package/dist/authentication/authentication-impl.js.map +1 -1
  8. package/dist/authentication/authentication-session.d.ts +4 -2
  9. package/dist/authentication/authentication-session.js +7 -2
  10. package/dist/authentication/authentication-session.js.map +1 -1
  11. package/dist/authentication.d.ts +5 -4
  12. package/dist/authentication.js +3 -0
  13. package/dist/authentication.js.map +1 -1
  14. package/dist/authorization/authorization-keystore.d.ts +5 -3
  15. package/dist/authorization/authorization-keystore.js +12 -9
  16. package/dist/authorization/authorization-keystore.js.map +1 -1
  17. package/dist/http/feed-cache.d.ts +5 -0
  18. package/dist/http/feed-cache.js +3 -0
  19. package/dist/http/feed-cache.js.map +1 -0
  20. package/dist/http/node-http.js +4 -1
  21. package/dist/http/node-http.js.map +1 -1
  22. package/dist/http/router.d.ts +5 -1
  23. package/dist/http/router.js +157 -24
  24. package/dist/http/router.js.map +1 -1
  25. package/dist/jinaga-server.js +6 -4
  26. package/dist/jinaga-server.js.map +1 -1
  27. package/dist/memory/memory-feed-cache.d.ts +7 -0
  28. package/dist/memory/memory-feed-cache.js +17 -0
  29. package/dist/memory/memory-feed-cache.js.map +1 -0
  30. package/dist/postgres/postgres-store.d.ts +5 -2
  31. package/dist/postgres/postgres-store.js +53 -28
  32. package/dist/postgres/postgres-store.js.map +1 -1
  33. package/dist/postgres/specification-result-sql.d.ts +11 -4
  34. package/dist/postgres/specification-result-sql.js +302 -5
  35. package/dist/postgres/specification-result-sql.js.map +1 -1
  36. package/dist/postgres/specification-sql.d.ts +14 -3
  37. package/dist/postgres/specification-sql.js +233 -100
  38. package/dist/postgres/specification-sql.js.map +1 -1
  39. package/package.json +2 -2
  40. package/src/authentication/authentication-device.ts +6 -0
  41. package/src/authentication/authentication-impl.ts +6 -3
  42. package/src/authentication/authentication-session.ts +11 -3
  43. package/src/authentication.ts +18 -5
  44. package/src/authorization/authorization-keystore.ts +14 -8
  45. package/src/http/feed-cache.ts +6 -0
  46. package/src/http/node-http.ts +5 -2
  47. package/src/http/router.ts +179 -31
  48. package/src/jinaga-server.ts +11 -9
  49. package/src/memory/memory-feed-cache.ts +15 -0
  50. package/src/postgres/postgres-store.ts +59 -31
  51. package/src/postgres/specification-result-sql.ts +450 -10
  52. package/src/postgres/specification-sql.ts +335 -115
  53. package/test/authorization/authorizationSpec.ts +11 -2
  54. package/test/postgres/postgresSpec.ts +31 -25
  55. package/test/postgres/postgresSpecificationSpec.ts +40 -68
  56. package/dist/postgres/query-description-builder.d.ts +0 -13
  57. package/dist/postgres/query-description-builder.js +0 -104
  58. package/dist/postgres/query-description-builder.js.map +0 -1
  59. package/dist/postgres/query-description.d.ts +0 -71
  60. package/dist/postgres/query-description.js +0 -256
  61. package/dist/postgres/query-description.js.map +0 -1
  62. package/src/postgres/query-description-builder.ts +0 -116
  63. package/src/postgres/query-description.ts +0 -385
@@ -51,7 +51,7 @@ describe('Postgres', () => {
51
51
  });
52
52
 
53
53
  it('should parse successor query with type', () => {
54
- const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.predecessor F.type="IntegrationTest.Successor"');
54
+ const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.predecessor F.type="IntegrationTest.Successor"')!;
55
55
  expect(sql).toEqual(
56
56
  'SELECT f2.hash as hash2 ' +
57
57
  'FROM public.fact f1 ' +
@@ -66,7 +66,7 @@ describe('Postgres', () => {
66
66
  });
67
67
 
68
68
  it('should parse predecessor query with type', () => {
69
- const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('P.parent F.type="Parent"');
69
+ const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('P.parent F.type="Parent"')!;
70
70
  expect(sql).toEqual(
71
71
  'SELECT f2.hash as hash2 ' +
72
72
  'FROM public.fact f1 ' +
@@ -81,7 +81,7 @@ describe('Postgres', () => {
81
81
  });
82
82
 
83
83
  it('should parse successor query with existential', () => {
84
- const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.predecessor F.type="IntegrationTest.Successor" E(S.successor F.type="IntegrationTest.Grandchild")');
84
+ const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.predecessor F.type="IntegrationTest.Successor" E(S.successor F.type="IntegrationTest.Grandchild")')!;
85
85
  expect(sql).toEqual(
86
86
  'SELECT f2.hash as hash2 ' +
87
87
  'FROM public.fact f1 ' +
@@ -100,7 +100,7 @@ describe('Postgres', () => {
100
100
  });
101
101
 
102
102
  it('should parse successor query with negative existential', () => {
103
- const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.predecessor F.type="IntegrationTest.Successor" N(S.successor F.type="IntegrationTest.Grandchild")');
103
+ const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.predecessor F.type="IntegrationTest.Successor" N(S.successor F.type="IntegrationTest.Grandchild")')!;
104
104
  expect(sql).toEqual(
105
105
  'SELECT f2.hash as hash2 ' +
106
106
  'FROM public.fact f1 ' +
@@ -119,7 +119,7 @@ describe('Postgres', () => {
119
119
  });
120
120
 
121
121
  it('should parse successor query with existential predecessor', () => {
122
- const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.parent F.type="Child" E(P.uncle F.type="Uncle")');
122
+ const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.parent F.type="Child" E(P.uncle F.type="Uncle")')!;
123
123
  expect(sql).toEqual(
124
124
  'SELECT f2.hash as hash2 ' +
125
125
  'FROM public.fact f1 ' +
@@ -138,7 +138,7 @@ describe('Postgres', () => {
138
138
  });
139
139
 
140
140
  it('should parse successor query with negative existential predecessor', () => {
141
- const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.parent F.type="Child" N(P.uncle F.type="Uncle")');
141
+ const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.parent F.type="Child" N(P.uncle F.type="Uncle")')!;
142
142
  expect(sql).toEqual(
143
143
  'SELECT f2.hash as hash2 ' +
144
144
  'FROM public.fact f1 ' +
@@ -157,7 +157,7 @@ describe('Postgres', () => {
157
157
  });
158
158
 
159
159
  it('should parse consecutive existential queries', () => {
160
- const { sql, parameters, factTypes, roleMap } = sqlFor('S.parent F.type="Child" N(S.condition F.type="Condition") N(S.other F.type="Other")');
160
+ const { sql, parameters, factTypes, roleMap } = sqlFor('S.parent F.type="Child" N(S.condition F.type="Condition") N(S.other F.type="Other")')!;
161
161
  expect(sql).toEqual(
162
162
  'SELECT f2.hash as hash2 ' +
163
163
  'FROM public.fact f1 ' +
@@ -181,7 +181,7 @@ describe('Postgres', () => {
181
181
  });
182
182
 
183
183
  it('should parse existential query form predecessor', () => {
184
- const { sql, parameters, factTypes, roleMap } = sqlFor('S.root F.type="Identifier" N(S.prior F.type="Identifier") P.identified F.type="Identified" N(S.identified F.type="Delete")');
184
+ const { sql, parameters, factTypes, roleMap } = sqlFor('S.root F.type="Identifier" N(S.prior F.type="Identifier") P.identified F.type="Identified" N(S.identified F.type="Delete")')!;
185
185
  expect(sql).toEqual(
186
186
  'SELECT f2.hash as hash2, f3.hash as hash3 ' +
187
187
  'FROM public.fact f1 ' +
@@ -213,7 +213,7 @@ describe('Postgres', () => {
213
213
  });
214
214
 
215
215
  it('should parse zig-zag pipeline', () => {
216
- const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.user F.type="Assignment" P.project F.type="Project" S.project F.type="Task" S.task F.type="Task.Title"');
216
+ const { sql, parameters, pathLength, factTypes, roleMap } = sqlFor('S.user F.type="Assignment" P.project F.type="Project" S.project F.type="Task" S.task F.type="Task.Title"')!;
217
217
  expect(sql).toEqual(
218
218
  'SELECT f2.hash as hash2, f3.hash as hash3, f4.hash as hash4, f5.hash as hash5 ' +
219
219
  'FROM public.fact f1 ' +
@@ -239,37 +239,37 @@ describe('Postgres', () => {
239
239
  });
240
240
 
241
241
  it('should parse query with unknown successor type', () => {
242
- const { empty } = sqlFor('S.root F.type="Unknown"');
242
+ const { empty } = sqlFor('S.root F.type="Unknown"')!;
243
243
  expect(empty).toBeTruthy();
244
244
  });
245
245
 
246
246
  it('should parse query with unknown predecessor type', () => {
247
- const { empty } = sqlFor('S.root F.type="Assignment" P.pred F.type="Unknown" P.user F.type="Jinaga.User"');
247
+ const { empty } = sqlFor('S.root F.type="Assignment" P.pred F.type="Unknown" P.user F.type="Jinaga.User"')!;
248
248
  expect(empty).toBeTruthy();
249
249
  });
250
250
 
251
251
  it('should parse query with some unknown types', () => {
252
- const { empty } = sqlFor('S.root F.type="Unknown" P.user F.type="Jinaga.User"');
252
+ const { empty } = sqlFor('S.root F.type="Unknown" P.user F.type="Jinaga.User"')!;
253
253
  expect(empty).toBeTruthy();
254
254
  });
255
255
 
256
256
  it('should parse query with unknown successor role', () => {
257
- const { empty } = sqlFor('S.unknown F.type="Successor"');
257
+ const { empty } = sqlFor('S.unknown F.type="Successor"')!;
258
258
  expect(empty).toBeTruthy();
259
259
  });
260
260
 
261
261
  it('should parse query with unknown predecessor role', () => {
262
- const { empty } = sqlFor('S.root F.type="Assignment" P.unknown F.type="Jinaga.User"');
262
+ const { empty } = sqlFor('S.root F.type="Assignment" P.unknown F.type="Jinaga.User"')!;
263
263
  expect(empty).toBeTruthy();
264
264
  });
265
265
 
266
266
  it('should parse query with some unknown predecessor roles', () => {
267
- const { empty } = sqlFor('S.root F.type="Assignment" P.predecessor F.type="Predecessor" P.unknown F.type="Jinaga.User"');
267
+ const { empty } = sqlFor('S.root F.type="Assignment" P.predecessor F.type="Predecessor" P.unknown F.type="Jinaga.User"')!;
268
268
  expect(empty).toBeTruthy();
269
269
  });
270
270
 
271
271
  it('should ignore negative existential with unknown type', () => {
272
- const { empty, sql, parameters, factTypes, roleMap } = sqlFor('S.root F.type="Assignment" N(S.assignment F.type="Unknown")');
272
+ const { empty, sql, parameters, factTypes, roleMap } = sqlFor('S.root F.type="Assignment" N(S.assignment F.type="Unknown")')!;
273
273
  expect(empty).toBeFalsy();
274
274
  expect(sql).toEqual(
275
275
  'SELECT f2.hash as hash2 ' +
@@ -286,7 +286,7 @@ describe('Postgres', () => {
286
286
  });
287
287
 
288
288
  it('should ignore negative existential with unknown role', () => {
289
- const { empty, sql, parameters, factTypes, roleMap } = sqlFor('S.root F.type="Assignment" N(S.unknown F.type="Assignment.Delete")');
289
+ const { empty, sql, parameters, factTypes, roleMap } = sqlFor('S.root F.type="Assignment" N(S.unknown F.type="Assignment.Delete")')!;
290
290
  expect(empty).toBeFalsy();
291
291
  expect(sql).toEqual(
292
292
  'SELECT f2.hash as hash2 ' +
@@ -303,17 +303,17 @@ describe('Postgres', () => {
303
303
  });
304
304
 
305
305
  it('should elevate positive existential with unknown type', () => {
306
- const { empty } = sqlFor('S.root F.type="Assignment" E(S.assignment F.type="Unknown")');
306
+ const { empty } = sqlFor('S.root F.type="Assignment" E(S.assignment F.type="Unknown")')!;
307
307
  expect(empty).toBeTruthy();
308
308
  });
309
309
 
310
310
  it('should elevate positive existential with unknown role', () => {
311
- const { empty } = sqlFor('S.root F.type="Assignment" E(S.unknown F.type="Assignment.Delete")');
311
+ const { empty } = sqlFor('S.root F.type="Assignment" E(S.unknown F.type="Assignment.Delete")')!;
312
312
  expect(empty).toBeTruthy();
313
313
  });
314
314
 
315
315
  it('should parse nested existential condition', () => {
316
- const { sql, parameters, factTypes, roleMap } = sqlFor('S.catalog F.type="ImprovingU.Idea" N(S.idea F.type="ImprovingU.Idea.Deletion" N(S.ideaDeletion F.type="ImprovingU.Idea.Restore"))');
316
+ const { sql, parameters, factTypes, roleMap } = sqlFor('S.catalog F.type="ImprovingU.Idea" N(S.idea F.type="ImprovingU.Idea.Deletion" N(S.ideaDeletion F.type="ImprovingU.Idea.Restore"))')!;
317
317
 
318
318
  expect(sql).toEqual(
319
319
  'SELECT f2.hash as hash2 ' +
@@ -353,22 +353,26 @@ function allFactTypes(steps: Step[]): string[] {
353
353
 
354
354
  function allRoles(steps: Step[], initialType: string) {
355
355
  let roles: { type: string; role: string }[] = [];
356
- let type: string = initialType;
357
- let role: string = undefined;
356
+ let type: string | undefined = initialType;
357
+ let role: string | undefined = undefined;
358
358
 
359
359
  for (const step of steps) {
360
360
  if (step instanceof PropertyCondition) {
361
361
  if (step.name === 'type') {
362
362
  type = step.value;
363
363
  if (role) {
364
- roles.push({ type, role });
364
+ if (type) {
365
+ roles.push({ type, role });
366
+ }
365
367
  role = undefined;
366
368
  }
367
369
  }
368
370
  }
369
371
  else if (step instanceof Join) {
370
372
  if (step.direction === Direction.Predecessor) {
371
- roles.push({ type, role: step.role });
373
+ if (type) {
374
+ roles.push({ type, role: step.role });
375
+ }
372
376
  role = undefined;
373
377
  }
374
378
  else {
@@ -377,7 +381,9 @@ function allRoles(steps: Step[], initialType: string) {
377
381
  type = undefined;
378
382
  }
379
383
  else if (step instanceof ExistentialCondition) {
380
- roles = roles.concat(allRoles(step.steps, type));
384
+ if (type) {
385
+ roles = roles.concat(allRoles(step.steps, type));
386
+ }
381
387
  }
382
388
  }
383
389
 
@@ -1,7 +1,6 @@
1
- import { dehydrateReference, FactBookmark, getAllFactTypes, getAllRoles, SpecificationParser } from "jinaga";
1
+ import { dehydrateReference, getAllFactTypes, getAllRoles, SpecificationParser } from "jinaga";
2
2
 
3
3
  import { addFactType, addRole, emptyFactTypeMap, emptyRoleMap, getFactTypeId, getRoleId } from "../../src/postgres/maps";
4
- import { SpecificationSqlQuery } from "../../src/postgres/query-description";
5
4
  import { sqlFromSpecification } from "../../src/postgres/specification-sql";
6
5
 
7
6
  const root = dehydrateReference({ type: 'Root' });
@@ -15,7 +14,7 @@ function parseSpecification(input: string) {
15
14
  return parser.parseSpecification();
16
15
  }
17
16
 
18
- function sqlFor(descriptiveString: string, bookmarks: FactBookmark[] = []) {
17
+ function sqlFor(descriptiveString: string, bookmarks: string[] = []) {
19
18
  const specification = parseSpecification(descriptiveString);
20
19
  const factTypeNames = getAllFactTypes(specification);
21
20
 
@@ -45,7 +44,7 @@ function sqlFor(descriptiveString: string, bookmarks: FactBookmark[] = []) {
45
44
  }
46
45
  throw new Error(`Unknown input type ${input.type}`);
47
46
  });
48
- const sqlQueries: SpecificationSqlQuery[] = sqlFromSpecification(start, bookmarks, 100, specification, factTypes, roleMap);
47
+ const sqlQueries = sqlFromSpecification(start, bookmarks, 100, specification, factTypes, roleMap);
49
48
  return { sqlQueries, factTypes, roleMap };
50
49
  }
51
50
 
@@ -91,7 +90,6 @@ describe("Postgres query generator", () => {
91
90
  ]);
92
91
  expect(query.labels).toEqual([
93
92
  {
94
- name: 'successor',
95
93
  type: 'IntegrationTest.Successor',
96
94
  index: 2
97
95
  }
@@ -134,12 +132,10 @@ describe("Postgres query generator", () => {
134
132
  ]);
135
133
  expect(sqlQueries[0].labels).toEqual([
136
134
  {
137
- name: "successor",
138
135
  type: "IntegrationTest.Successor",
139
136
  index: 2
140
137
  },
141
138
  {
142
- name: "other",
143
139
  type: "IntegrationTest.OtherPredecessor",
144
140
  index: 3
145
141
  }
@@ -185,12 +181,10 @@ describe("Postgres query generator", () => {
185
181
  ]);
186
182
  expect(sqlQueries[0].labels).toEqual([
187
183
  {
188
- name: "project",
189
184
  type: "MyApplication.Project",
190
185
  index: 2
191
186
  },
192
187
  {
193
- name: "assignment",
194
188
  type: "MyApplication.Assignment",
195
189
  index: 3
196
190
  }
@@ -236,12 +230,10 @@ describe("Postgres query generator", () => {
236
230
  ]);
237
231
  expect(sqlQueries[0].labels).toEqual([
238
232
  {
239
- name: "project",
240
233
  type: "MyApplication.Project",
241
234
  index: 2
242
235
  },
243
236
  {
244
- name: "deleted",
245
237
  type: "MyApplication.Project.Deleted",
246
238
  index: 3
247
239
  }
@@ -274,7 +266,6 @@ describe("Postgres query generator", () => {
274
266
  ]);
275
267
  expect(sqlQueries[1].labels).toEqual([
276
268
  {
277
- name: "project",
278
269
  type: "MyApplication.Project",
279
270
  index: 2
280
271
  }
@@ -296,43 +287,41 @@ describe("Postgres query generator", () => {
296
287
 
297
288
  expect(sqlQueries.length).toEqual(1);
298
289
  expect(sqlQueries[0].sql).toEqual(
299
- 'SELECT f3.hash as hash3, ' +
300
- 'f4.hash as hash4, ' +
301
- 'sort(array[f3.fact_id, f4.fact_id], \'desc\') as bookmark ' +
290
+ 'SELECT f2.hash as hash2, ' +
291
+ 'f3.hash as hash3, ' +
292
+ 'sort(array[f2.fact_id, f3.fact_id], \'desc\') as bookmark ' +
302
293
  'FROM public.fact f1 ' +
303
- 'JOIN public.edge e1 ON e1.predecessor_fact_id = f1.fact_id AND e1.role_id = $3 ' +
304
- 'JOIN public.fact f3 ON f3.fact_id = e1.successor_fact_id ' +
305
- 'JOIN public.edge e2 ON e2.predecessor_fact_id = f3.fact_id AND e2.role_id = $4 ' +
306
- 'JOIN public.fact f4 ON f4.fact_id = e2.successor_fact_id ' +
307
- 'JOIN public.edge e3 ON e3.successor_fact_id = f4.fact_id AND e3.role_id = $7 ' +
308
- 'JOIN public.fact f2 ON f2.fact_id = e3.predecessor_fact_id ' +
294
+ 'JOIN public.edge e1 ON e1.predecessor_fact_id = f1.fact_id AND e1.role_id = $5 ' +
295
+ 'JOIN public.fact f2 ON f2.fact_id = e1.successor_fact_id ' +
296
+ 'JOIN public.edge e2 ON e2.predecessor_fact_id = f2.fact_id AND e2.role_id = $6 ' +
297
+ 'JOIN public.fact f3 ON f3.fact_id = e2.successor_fact_id ' +
298
+ 'JOIN public.edge e3 ON e3.successor_fact_id = f3.fact_id AND e3.role_id = $7 ' +
299
+ 'JOIN public.fact f4 ON f4.fact_id = e3.predecessor_fact_id ' +
309
300
  'WHERE f1.fact_type_id = $1 AND f1.hash = $2 ' +
310
- 'AND f2.fact_type_id = $5 AND f2.hash = $6 ' +
311
- 'AND sort(array[f3.fact_id, f4.fact_id], \'desc\') > $8 ' +
301
+ 'AND f4.fact_type_id = $3 AND f4.hash = $4 ' +
302
+ 'AND sort(array[f2.fact_id, f3.fact_id], \'desc\') > $8 ' +
312
303
  'ORDER BY bookmark ASC ' +
313
304
  'LIMIT $9'
314
305
  );
315
306
  expect(sqlQueries[0].parameters).toEqual([
316
307
  getFactTypeId(factTypes, "Root"),
317
308
  rootHash,
318
- roleParameter(roleMap, factTypes, "MyApplication.Project", "root"),
319
- roleParameter(roleMap, factTypes, "MyApplication.Assignment", "project"),
320
309
  getFactTypeId(factTypes, "Jinaga.User"),
321
310
  userHash,
311
+ roleParameter(roleMap, factTypes, "MyApplication.Project", "root"),
312
+ roleParameter(roleMap, factTypes, "MyApplication.Assignment", "project"),
322
313
  roleParameter(roleMap, factTypes, "MyApplication.Assignment", "user"),
323
314
  [],
324
315
  100
325
316
  ]);
326
317
  expect(sqlQueries[0].labels).toEqual([
327
318
  {
328
- name: "project",
329
319
  type: "MyApplication.Project",
330
- index: 3
320
+ index: 2
331
321
  },
332
322
  {
333
- name: "assignment",
334
323
  type: "MyApplication.Assignment",
335
- index: 4
324
+ index: 3
336
325
  }
337
326
  ]);
338
327
  });
@@ -352,43 +341,41 @@ describe("Postgres query generator", () => {
352
341
 
353
342
  expect(sqlQueries.length).toEqual(1);
354
343
  expect(sqlQueries[0].sql).toEqual(
355
- 'SELECT f3.hash as hash3, ' +
356
- 'f4.hash as hash4, ' +
357
- 'sort(array[f3.fact_id, f4.fact_id], \'desc\') as bookmark ' +
358
- 'FROM public.fact f2 ' +
359
- 'JOIN public.edge e1 ON e1.predecessor_fact_id = f2.fact_id AND e1.role_id = $3 ' +
360
- 'JOIN public.fact f3 ON f3.fact_id = e1.successor_fact_id ' +
361
- 'JOIN public.edge e2 ON e2.predecessor_fact_id = f3.fact_id AND e2.role_id = $4 ' +
362
- 'JOIN public.fact f4 ON f4.fact_id = e2.successor_fact_id ' +
363
- 'JOIN public.edge e3 ON e3.successor_fact_id = f4.fact_id AND e3.role_id = $7 ' +
364
- 'JOIN public.fact f1 ON f1.fact_id = e3.predecessor_fact_id ' +
365
- 'WHERE f1.fact_type_id = $5 AND f1.hash = $6 ' +
366
- 'AND f2.fact_type_id = $1 AND f2.hash = $2 ' +
367
- 'AND sort(array[f3.fact_id, f4.fact_id], \'desc\') > $8 ' +
344
+ 'SELECT f2.hash as hash2, ' +
345
+ 'f3.hash as hash3, ' +
346
+ 'sort(array[f2.fact_id, f3.fact_id], \'desc\') as bookmark ' +
347
+ 'FROM public.fact f1 ' +
348
+ 'JOIN public.edge e1 ON e1.predecessor_fact_id = f1.fact_id AND e1.role_id = $5 ' +
349
+ 'JOIN public.fact f2 ON f2.fact_id = e1.successor_fact_id ' +
350
+ 'JOIN public.edge e2 ON e2.predecessor_fact_id = f2.fact_id AND e2.role_id = $6 ' +
351
+ 'JOIN public.fact f3 ON f3.fact_id = e2.successor_fact_id ' +
352
+ 'JOIN public.edge e3 ON e3.successor_fact_id = f3.fact_id AND e3.role_id = $7 ' +
353
+ 'JOIN public.fact f4 ON f4.fact_id = e3.predecessor_fact_id ' +
354
+ 'WHERE f1.fact_type_id = $1 AND f1.hash = $2 ' +
355
+ 'AND f4.fact_type_id = $3 AND f4.hash = $4 ' +
356
+ 'AND sort(array[f2.fact_id, f3.fact_id], \'desc\') > $8 ' +
368
357
  'ORDER BY bookmark ASC ' +
369
358
  'LIMIT $9'
370
359
  );
371
360
  expect(sqlQueries[0].parameters).toEqual([
372
361
  getFactTypeId(factTypes, "Root"),
373
362
  rootHash,
374
- roleParameter(roleMap, factTypes, "MyApplication.Project", "root"),
375
- roleParameter(roleMap, factTypes, "MyApplication.Assignment", "project"),
376
363
  getFactTypeId(factTypes, "Jinaga.User"),
377
364
  userHash,
365
+ roleParameter(roleMap, factTypes, "MyApplication.Project", "root"),
366
+ roleParameter(roleMap, factTypes, "MyApplication.Assignment", "project"),
378
367
  roleParameter(roleMap, factTypes, "MyApplication.Assignment", "user"),
379
368
  [],
380
369
  100
381
370
  ]);
382
371
  expect(sqlQueries[0].labels).toEqual([
383
372
  {
384
- name: "project",
385
373
  type: "MyApplication.Project",
386
- index: 3
374
+ index: 2
387
375
  },
388
376
  {
389
- name: "assignment",
390
377
  type: "MyApplication.Assignment",
391
- index: 4
378
+ index: 3
392
379
  }
393
380
  ]);
394
381
  });
@@ -428,7 +415,6 @@ describe("Postgres query generator", () => {
428
415
  ]);
429
416
  expect(sqlQueries[0].labels).toEqual([
430
417
  {
431
- name: "project",
432
418
  type: "MyApplication.Project",
433
419
  index: 2
434
420
  }
@@ -456,12 +442,10 @@ describe("Postgres query generator", () => {
456
442
  ]);
457
443
  expect(sqlQueries[1].labels).toEqual([
458
444
  {
459
- name: "project",
460
445
  type: "MyApplication.Project",
461
446
  index: 2
462
447
  },
463
448
  {
464
- name: "names.name",
465
449
  type: "MyApplication.Project.Name",
466
450
  index: 3
467
451
  }
@@ -486,18 +470,9 @@ describe("Postgres query generator", () => {
486
470
  ]
487
471
  }
488
472
  }`, [
489
- {
490
- labels: [ "project" ],
491
- bookmark: "123"
492
- },
493
- {
494
- labels: [ "project", "names.name", "names.next" ],
495
- bookmark: "456.345.234"
496
- },
497
- {
498
- labels: [ "project", "names.name" ],
499
- bookmark: "789.678"
500
- }
473
+ "123",
474
+ "456.345.234",
475
+ "789.678"
501
476
  ]);
502
477
 
503
478
  expect(sqlQueries.length).toEqual(3);
@@ -521,7 +496,6 @@ describe("Postgres query generator", () => {
521
496
  ]);
522
497
  expect(sqlQueries[0].labels).toEqual([
523
498
  {
524
- name: "project",
525
499
  type: "MyApplication.Project",
526
500
  index: 2
527
501
  }
@@ -560,7 +534,6 @@ describe("Postgres query generator", () => {
560
534
  ]);
561
535
  expect(sqlQueries[0].labels).toEqual([
562
536
  {
563
- name: "project",
564
537
  type: "MyApplication.Project",
565
538
  index: 2
566
539
  }
@@ -645,7 +618,7 @@ describe("Postgres query generator", () => {
645
618
  const { sqlQueries } = sqlFor(`
646
619
  (root: Root) {
647
620
  successor: MyApplication.Successor [
648
- successor = root->intermediate: Unknown->root: Root
621
+ successor = root->intermediate: Unknown->successor: MyApplication.Successor
649
622
  ]
650
623
  }`);
651
624
 
@@ -667,7 +640,7 @@ describe("Postgres query generator", () => {
667
640
  const { sqlQueries } = sqlFor(`
668
641
  (root: Root) {
669
642
  successor: MyApplication.Successor [
670
- successor = root->unknown: Intermediate->root: Root
643
+ successor = root->unknown: Intermediate->successor: MyApplication.Successor
671
644
  ]
672
645
  }`);
673
646
 
@@ -733,7 +706,6 @@ describe("Postgres query generator", () => {
733
706
  ]);
734
707
  expect(sqlQueries[0].labels).toEqual([
735
708
  {
736
- name: "project",
737
709
  type: "MyApplication.Project",
738
710
  index: 2
739
711
  }
@@ -1,13 +0,0 @@
1
- import { Label, PathCondition } from "jinaga";
2
- import { FactTypeMap, RoleMap } from "./maps";
3
- import { QueryDescription } from "./query-description";
4
- import { FactByIdentifier } from "./specification-result-sql";
5
- export declare class QueryDescriptionBuilder {
6
- protected readonly factTypes: FactTypeMap;
7
- protected readonly roleMap: RoleMap;
8
- constructor(factTypes: FactTypeMap, roleMap: RoleMap);
9
- protected addPathCondition(queryDescription: QueryDescription, knownFacts: FactByIdentifier, path: number[], unknown: Label, prefix: string, condition: PathCondition): {
10
- queryDescription: QueryDescription;
11
- knownFacts: FactByIdentifier;
12
- };
13
- }
@@ -1,104 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.QueryDescriptionBuilder = void 0;
4
- const maps_1 = require("./maps");
5
- const query_description_1 = require("./query-description");
6
- class QueryDescriptionBuilder {
7
- constructor(factTypes, roleMap) {
8
- this.factTypes = factTypes;
9
- this.roleMap = roleMap;
10
- }
11
- addPathCondition(queryDescription, knownFacts, path, unknown, prefix, condition) {
12
- // If no input parameter has been allocated, allocate one now.
13
- const input = queryDescription.inputByLabel(condition.labelRight);
14
- if (input && input.factTypeParameter === 0) {
15
- queryDescription = queryDescription.withInputParameter(input.label);
16
- }
17
- // Determine whether we have already written the output.
18
- const knownFact = knownFacts[unknown.name];
19
- const roleCount = condition.rolesLeft.length + condition.rolesRight.length;
20
- // Walk up the right-hand side.
21
- // This generates predecessor joins from a given or prior label.
22
- let fact = knownFacts[condition.labelRight];
23
- if (!fact) {
24
- throw new Error(`Label ${condition.labelRight} not found. Known labels: ${Object.keys(knownFacts).join(", ")}`);
25
- }
26
- let type = fact.type;
27
- let factIndex = fact.factIndex;
28
- for (const [i, role] of condition.rolesRight.entries()) {
29
- // If the type or role is not known, then no facts matching the condition can
30
- // exist. The query is unsatisfiable.
31
- const typeId = (0, maps_1.getFactTypeId)(this.factTypes, type);
32
- if (!typeId) {
33
- return { queryDescription: query_description_1.QueryDescription.unsatisfiable, knownFacts };
34
- }
35
- const roleId = (0, maps_1.getRoleId)(this.roleMap, typeId, role.name);
36
- if (!roleId) {
37
- return { queryDescription: query_description_1.QueryDescription.unsatisfiable, knownFacts };
38
- }
39
- const { query: queryWithParameter, parameterIndex: roleParameter } = queryDescription.withParameter(roleId);
40
- if (i === roleCount - 1 && knownFact) {
41
- // If we have already written the output, we can use the fact index.
42
- queryDescription = queryWithParameter.withEdge(knownFact.factIndex, factIndex, roleParameter, path);
43
- factIndex = knownFact.factIndex;
44
- }
45
- else {
46
- // If we have not written the fact, we need to write it now.
47
- const { query, factIndex: predecessorFactIndex } = queryWithParameter.withFact(role.targetType);
48
- queryDescription = query.withEdge(predecessorFactIndex, factIndex, roleParameter, path);
49
- factIndex = predecessorFactIndex;
50
- }
51
- type = role.targetType;
52
- }
53
- const rightType = type;
54
- // Walk up the left-hand side.
55
- // We will need to reverse this walk to generate successor joins.
56
- type = unknown.type;
57
- const newEdges = [];
58
- for (const role of condition.rolesLeft) {
59
- // If the type or role is not known, then no facts matching the condition can
60
- // exist. The query is unsatisfiable.
61
- const typeId = (0, maps_1.getFactTypeId)(this.factTypes, type);
62
- if (!typeId) {
63
- return { queryDescription: query_description_1.QueryDescription.unsatisfiable, knownFacts };
64
- }
65
- const roleId = (0, maps_1.getRoleId)(this.roleMap, typeId, role.name);
66
- if (!roleId) {
67
- return { queryDescription: query_description_1.QueryDescription.unsatisfiable, knownFacts };
68
- }
69
- newEdges.push({
70
- roleId,
71
- declaringType: type
72
- });
73
- type = role.targetType;
74
- }
75
- if (type !== rightType) {
76
- throw new Error(`Type mismatch: ${type} is compared to ${rightType}`);
77
- }
78
- newEdges.reverse().forEach(({ roleId, declaringType }, i) => {
79
- const { query: queryWithParameter, parameterIndex: roleParameter } = queryDescription.withParameter(roleId);
80
- if (condition.rolesRight.length + i === roleCount - 1 && knownFact) {
81
- queryDescription = queryWithParameter.withEdge(factIndex, knownFact.factIndex, roleParameter, path);
82
- factIndex = knownFact.factIndex;
83
- }
84
- else {
85
- const { query: queryWithFact, factIndex: successorFactIndex } = queryWithParameter.withFact(declaringType);
86
- queryDescription = queryWithFact.withEdge(factIndex, successorFactIndex, roleParameter, path);
87
- factIndex = successorFactIndex;
88
- }
89
- });
90
- // If we have not captured the known fact, add it now.
91
- if (!knownFact) {
92
- knownFacts = Object.assign(Object.assign({}, knownFacts), { [unknown.name]: { factIndex, type: unknown.type } });
93
- // If we have not written the output, write it now.
94
- // Only write the output if we are not inside of an existential condition.
95
- // Use the prefix, which will be set for projections.
96
- if (path.length === 0) {
97
- queryDescription = queryDescription.withOutput(prefix + unknown.name, unknown.type, factIndex);
98
- }
99
- }
100
- return { queryDescription, knownFacts };
101
- }
102
- }
103
- exports.QueryDescriptionBuilder = QueryDescriptionBuilder;
104
- //# sourceMappingURL=query-description-builder.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"query-description-builder.js","sourceRoot":"","sources":["../../src/postgres/query-description-builder.ts"],"names":[],"mappings":"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"}