jinaga-server 1.1.3 → 2.0.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 (89) hide show
  1. package/README.md +12 -0
  2. package/dist/authentication/authentication-device.d.ts +3 -2
  3. package/dist/authentication/authentication-device.js +6 -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 +6 -0
  7. package/dist/authentication/authentication-impl.js.map +1 -1
  8. package/dist/authentication/authentication-noop.d.ts +20 -0
  9. package/dist/authentication/authentication-noop.js +52 -0
  10. package/dist/authentication/authentication-noop.js.map +1 -0
  11. package/dist/authentication/authentication-session.d.ts +3 -2
  12. package/dist/authentication/authentication-session.js +6 -0
  13. package/dist/authentication/authentication-session.js.map +1 -1
  14. package/dist/authentication.d.ts +3 -2
  15. package/dist/authentication.js +6 -0
  16. package/dist/authentication.js.map +1 -1
  17. package/dist/authorization/authorization-keystore.d.ts +3 -4
  18. package/dist/authorization/authorization-keystore.js +9 -4
  19. package/dist/authorization/authorization-keystore.js.map +1 -1
  20. package/dist/debug.d.ts +1 -0
  21. package/dist/debug.js +30 -0
  22. package/dist/debug.js.map +1 -0
  23. package/dist/http/router.js.map +1 -1
  24. package/dist/jinaga-server.js +15 -7
  25. package/dist/jinaga-server.js.map +1 -1
  26. package/dist/memory/memory-keystore.js +0 -6
  27. package/dist/memory/memory-keystore.js.map +1 -1
  28. package/dist/postgres/connection.js +1 -0
  29. package/dist/postgres/connection.js.map +1 -1
  30. package/dist/postgres/maps.d.ts +7 -6
  31. package/dist/postgres/maps.js +9 -1
  32. package/dist/postgres/maps.js.map +1 -1
  33. package/dist/postgres/postgres-keystore.js +0 -6
  34. package/dist/postgres/postgres-keystore.js.map +1 -1
  35. package/dist/postgres/postgres-store.d.ts +1 -2
  36. package/dist/postgres/postgres-store.js +29 -24
  37. package/dist/postgres/postgres-store.js.map +1 -1
  38. package/dist/postgres/specification-result-sql.d.ts +4 -5
  39. package/dist/postgres/specification-result-sql.js +139 -112
  40. package/dist/postgres/specification-result-sql.js.map +1 -1
  41. package/dist/postgres/specification-sql.js.map +1 -1
  42. package/dist/postgres/sql.d.ts +1 -1
  43. package/dist/postgres/sql.js +15 -7
  44. package/dist/postgres/sql.js.map +1 -1
  45. package/dist/util/maps.d.ts +0 -0
  46. package/dist/util/maps.js +2 -0
  47. package/dist/util/maps.js.map +1 -0
  48. package/docs/sql/SQL Generator (projection).png +0 -0
  49. package/docs/sql/SQLFromSpecification.md +396 -0
  50. package/docs/sql/example.sql +49 -0
  51. package/docs/sql/first-path.gv +9 -0
  52. package/docs/sql/first-path.png +0 -0
  53. package/docs/sql/model.gv +20 -0
  54. package/docs/sql/model.png +0 -0
  55. package/integration-test/jinaga-test/Dockerfile +2 -2
  56. package/integration-test/jinaga-test/jinaga.test.js +3 -3
  57. package/integration-test/jinaga-test/package-lock.json +745 -3484
  58. package/integration-test/jinaga-test/package.json +2 -0
  59. package/integration-test/run.sh +3 -3
  60. package/package.json +5 -6
  61. package/replicator/index.ts +31 -0
  62. package/replicator/package-lock.json +855 -0
  63. package/replicator/package.json +27 -0
  64. package/replicator/tsconfig.json +15 -0
  65. package/src/authentication/authentication-device.ts +11 -1
  66. package/src/authentication/authentication-impl.ts +9 -2
  67. package/src/authentication/authentication-noop.ts +65 -0
  68. package/src/authentication/authentication-session.ts +11 -1
  69. package/src/authentication.ts +12 -2
  70. package/src/authorization/authorization-keystore.ts +12 -7
  71. package/src/debug.ts +30 -0
  72. package/src/http/router.ts +2 -2
  73. package/src/jinaga-server.ts +18 -8
  74. package/src/memory/memory-keystore.ts +0 -6
  75. package/src/postgres/connection.ts +2 -1
  76. package/src/postgres/maps.ts +8 -0
  77. package/src/postgres/postgres-keystore.ts +2 -8
  78. package/src/postgres/postgres-store.ts +37 -30
  79. package/src/postgres/specification-result-sql.ts +200 -145
  80. package/src/postgres/specification-sql.ts +1 -1
  81. package/src/postgres/sql.ts +23 -12
  82. package/src/util/maps.ts +0 -0
  83. package/test/postgres/postgresReadSpec.ts +292 -0
  84. package/test/postgres/postgresSpec.ts +31 -31
  85. package/test/postgres/postgresSpecificationSpec.ts +1 -1
  86. package/tsconfig.json +1 -0
  87. package/tsconfig.test.json +26 -0
  88. package/docs/specification.txt +0 -41
  89. package/interactive/index.js +0 -56
@@ -1,6 +1,6 @@
1
1
  import { Direction, ExistentialCondition, FactReference, Join, PropertyCondition, Quantifier, Step } from "jinaga";
2
2
 
3
- import { FactTypeMap, getFactTypeId, getRoleId, RoleMap } from "./maps";
3
+ import { ensureGetFactTypeId, FactTypeMap, getFactTypeId, getRoleId, RoleMap } from "./maps";
4
4
 
5
5
  export type SqlQuery = {
6
6
  empty: boolean,
@@ -10,7 +10,7 @@ export type SqlQuery = {
10
10
  factTypeNames: string[]
11
11
  };
12
12
 
13
- export function sqlFromSteps(start: FactReference, steps: Step[], factTypes: FactTypeMap, roleMap: RoleMap) : SqlQuery {
13
+ export function sqlFromSteps(start: FactReference, steps: Step[], factTypes: FactTypeMap, roleMap: RoleMap) : SqlQuery | null {
14
14
  const builder = new QueryBuilder(factTypes, roleMap);
15
15
 
16
16
  return builder.buildQuery(start, steps);
@@ -90,18 +90,18 @@ class QueryBuilder {
90
90
  constructor(private factTypes: FactTypeMap, private roleMap: RoleMap) {
91
91
  }
92
92
 
93
- buildQuery(start: FactReference, steps: Step[]): SqlQuery {
93
+ buildQuery(start: FactReference, steps: Step[]): SqlQuery | null {
94
94
  if (steps.length === 0) {
95
95
  return null;
96
96
  }
97
97
 
98
- const startTypeId = getFactTypeId(this.factTypes, start.type);
98
+ const startTypeId = ensureGetFactTypeId(this.factTypes, start.type);
99
99
  const startState: QueryBuilderState = {
100
100
  state: 'start',
101
101
  typeId: startTypeId,
102
102
  typeName: start.type
103
103
  };
104
- const finalState = steps.reduce((state, step) => {
104
+ const finalState = steps.reduce((state: QueryBuilderState, step) => {
105
105
  return this.matchStep(state, step);
106
106
  }, startState);
107
107
  this.end(finalState);
@@ -134,6 +134,14 @@ class QueryBuilder {
134
134
  }
135
135
 
136
136
  private buildJoins(joins: QueryJoin[], priorFactId: string) {
137
+ interface Joins {
138
+ priorFactId: string,
139
+ clauses: string[]
140
+ };
141
+ const initialJoins: Joins = {
142
+ priorFactId,
143
+ clauses: []
144
+ };
137
145
  const clauses = joins.reduce((joins, join) => {
138
146
  if (join.table === 'edge') {
139
147
  if (join.direction === 'successor') {
@@ -161,10 +169,7 @@ class QueryBuilder {
161
169
  clauses: [...joins.clauses, clause]
162
170
  };
163
171
  }
164
- }, {
165
- priorFactId,
166
- clauses: []
167
- }).clauses;
172
+ }, initialJoins).clauses;
168
173
  return clauses.join('');
169
174
  }
170
175
 
@@ -209,7 +214,7 @@ class QueryBuilder {
209
214
  typeId: typeId,
210
215
  typeName: typeName
211
216
  };
212
- const finalState = steps.reduce((state, step) => {
217
+ const finalState = steps.reduce((state: QueryBuilderState, step) => {
213
218
  return this.matchStep(state, step);
214
219
  }, startState);
215
220
  this.end(finalState);
@@ -270,12 +275,15 @@ class QueryBuilder {
270
275
  position: `${state.typeName}.${step.role}`
271
276
  }
272
277
  }
273
- if (step.direction === Direction.Successor) {
278
+ else if (step.direction === Direction.Successor) {
274
279
  return {
275
280
  state: 'successor-join',
276
281
  role: step.role
277
282
  }
278
283
  }
284
+ else {
285
+ throw new Error(`Unknown direction ${step.direction}`);
286
+ }
279
287
  }
280
288
  else if (step instanceof ExistentialCondition) {
281
289
  return this.pushExistentialCondition(state.typeId, state.typeName, state, step);
@@ -311,13 +319,16 @@ class QueryBuilder {
311
319
  position: `${state.typeName}.${step.role}`
312
320
  }
313
321
  }
314
- if (step.direction === Direction.Successor) {
322
+ else if (step.direction === Direction.Successor) {
315
323
  this.emitFact(state.typeName);
316
324
  return {
317
325
  state: 'successor-join',
318
326
  role: step.role
319
327
  }
320
328
  }
329
+ else {
330
+ throw new Error(`Unknown direction ${step.direction}`);
331
+ }
321
332
  }
322
333
  else if (step instanceof ExistentialCondition) {
323
334
  return this.pushExistentialCondition(state.typeId, state.typeName, state, step);
File without changes
@@ -0,0 +1,292 @@
1
+ import { dehydrateReference, getAllFactTypes, getAllRoles, SpecificationParser } from "jinaga";
2
+ import { addFactType, addRole, emptyFactTypeMap, emptyRoleMap, getFactTypeId, getRoleId } from "../../src/postgres/maps";
3
+ import { resultSqlFromSpecification } from "../../src/postgres/specification-result-sql";
4
+
5
+ const company = dehydrateReference({ type: "Company" });
6
+ const companyHash = company.hash;
7
+ const user = dehydrateReference({ type: "Jinaga.User", publicKey: "PUBLIC KEY"});
8
+ const userHash = user.hash;
9
+
10
+ function parseSpecification(input: string) {
11
+ const parser = new SpecificationParser(input);
12
+ parser.skipWhitespace();
13
+ return parser.parseSpecification();
14
+ }
15
+
16
+ function sqlFor(descriptiveString: string, bookmarks: string[] = []) {
17
+ const specification = parseSpecification(descriptiveString);
18
+ const factTypeNames = getAllFactTypes(specification);
19
+
20
+ // Build a fact type map containing all fact types in the specification.
21
+ // Filter out fact types named "Unknown".
22
+ const factTypes = factTypeNames.filter(t => t !== 'Unknown').reduce(
23
+ (f, factType, i) => addFactType(f, factType, i + 1),
24
+ emptyFactTypeMap());
25
+
26
+ // Build a role map containing all roles in the specification.
27
+ // Filter out the roles named "unknown", and those of unknown fact types.
28
+ let roleMap = getAllRoles(specification).filter(r => r.name !== 'unknown').reduce(
29
+ (r, role, i) => {
30
+ const factTypeId = getFactTypeId(factTypes, role.successorType);
31
+ if (!factTypeId) {
32
+ return r;
33
+ }
34
+ return addRole(r, factTypeId, role.name, i + 1);
35
+ },
36
+ emptyRoleMap());
37
+ const start = specification.given.map(input => {
38
+ if (input.type === "Company") {
39
+ return company;
40
+ }
41
+ if (input.type === "Jinaga.User") {
42
+ return user;
43
+ }
44
+ throw new Error(`Unknown input type ${input.type}`);
45
+ });
46
+ const composer = resultSqlFromSpecification(start, specification, factTypes, roleMap);
47
+ if (!composer) {
48
+ throw new Error("The specification is not satisfiable.");
49
+ }
50
+ return { composer, factTypes, roleMap };
51
+ }
52
+
53
+ function roleParameter(roleMap: Map<number, Map<string, number>>, factTypes: Map<string, number>, factTypeName: string, roleName: string): number {
54
+ const factTypeId = getFactTypeId(factTypes, factTypeName);
55
+ if (!factTypeId) {
56
+ throw new Error(`Unknown fact type ${factTypeName}`);
57
+ }
58
+ const roleId = getRoleId(roleMap, factTypeId, roleName);
59
+ if (!roleId) {
60
+ throw new Error(`Unknown role ${roleName} in fact type ${factTypeName}`);
61
+ }
62
+ return roleId;
63
+ }
64
+
65
+ describe("Postgres read", () => {
66
+ it("should join successors", () => {
67
+ const { composer } = sqlFor(`
68
+ (company: Company) {
69
+ department: Department [
70
+ department->company: Company = company
71
+ ]
72
+ }
73
+ `);
74
+
75
+ const sql = composer.getSqlQueries().sqlQuery.sql;
76
+ expect(sql).toEqual(
77
+ `SELECT f2.hash as hash2, f2.fact_id as id2, f2.data as data2 ` +
78
+ `FROM public.fact f1 ` +
79
+ `JOIN public.edge e1 ` +
80
+ `ON e1.predecessor_fact_id = f1.fact_id ` +
81
+ `AND e1.role_id = $3 ` +
82
+ `JOIN public.fact f2 ` +
83
+ `ON f2.fact_id = e1.successor_fact_id ` +
84
+ `WHERE f1.fact_type_id = $1 AND f1.hash = $2 ` +
85
+ `ORDER BY f2.fact_id ASC`
86
+ );
87
+ });
88
+
89
+ it("should apply negative existential conditions", () => {
90
+ const { composer, factTypes, roleMap } = sqlFor(`
91
+ (company: Company) {
92
+ project: Project [
93
+ project->department: Department->company: Company = company
94
+ !E {
95
+ deleted: Project.Deleted [
96
+ deleted->project: Project = project
97
+ ]
98
+ }
99
+ ]
100
+ }
101
+ `);
102
+
103
+ const tree = composer.getSqlQueries();
104
+ const sql = tree.sqlQuery.sql;
105
+ expect(sql).toEqual(
106
+ `SELECT f3.hash as hash3, f3.fact_id as id3, f3.data as data3 ` +
107
+ `FROM public.fact f1 ` +
108
+ `JOIN public.edge e1 ` +
109
+ `ON e1.predecessor_fact_id = f1.fact_id ` +
110
+ `AND e1.role_id = $3 ` +
111
+ `JOIN public.fact f2 ` +
112
+ `ON f2.fact_id = e1.successor_fact_id ` +
113
+ `JOIN public.edge e2 ` +
114
+ `ON e2.predecessor_fact_id = f2.fact_id ` +
115
+ `AND e2.role_id = $4 ` +
116
+ `JOIN public.fact f3 ` +
117
+ `ON f3.fact_id = e2.successor_fact_id ` +
118
+ `WHERE f1.fact_type_id = $1 AND f1.hash = $2 ` +
119
+ `AND NOT EXISTS (` +
120
+ `SELECT 1 ` +
121
+ `FROM public.edge e3 ` +
122
+ `JOIN public.fact f4 ` +
123
+ `ON f4.fact_id = e3.successor_fact_id ` +
124
+ `WHERE e3.predecessor_fact_id = f3.fact_id ` +
125
+ `AND e3.role_id = $5` +
126
+ `) ` +
127
+ `ORDER BY f3.fact_id ASC`
128
+ );
129
+ expect(tree.sqlQuery.parameters).toEqual([
130
+ getFactTypeId(factTypes, 'Company'),
131
+ companyHash,
132
+ roleParameter(roleMap, factTypes, 'Department', 'company'),
133
+ roleParameter(roleMap, factTypes, 'Project', 'department'),
134
+ roleParameter(roleMap, factTypes, 'Project.Deleted', 'project')
135
+ ]);
136
+ });
137
+
138
+ it("should apply positive existential conditions", () => {
139
+ const { composer, factTypes, roleMap } = sqlFor(`
140
+ (company: Company) {
141
+ project: Project [
142
+ project->department: Department->company: Company = company
143
+ E {
144
+ deleted: Project.Deleted [
145
+ deleted->project: Project = project
146
+ ]
147
+ }
148
+ ]
149
+ }
150
+ `);
151
+
152
+ const tree = composer.getSqlQueries();
153
+ const sql = tree.sqlQuery.sql;
154
+ expect(sql).toEqual(
155
+ `SELECT f3.hash as hash3, f3.fact_id as id3, f3.data as data3 ` +
156
+ `FROM public.fact f1 ` +
157
+ `JOIN public.edge e1 ` +
158
+ `ON e1.predecessor_fact_id = f1.fact_id ` +
159
+ `AND e1.role_id = $3 ` +
160
+ `JOIN public.fact f2 ` +
161
+ `ON f2.fact_id = e1.successor_fact_id ` +
162
+ `JOIN public.edge e2 ` +
163
+ `ON e2.predecessor_fact_id = f2.fact_id ` +
164
+ `AND e2.role_id = $4 ` +
165
+ `JOIN public.fact f3 ` +
166
+ `ON f3.fact_id = e2.successor_fact_id ` +
167
+ `WHERE f1.fact_type_id = $1 AND f1.hash = $2 ` +
168
+ `AND EXISTS (` +
169
+ `SELECT 1 ` +
170
+ `FROM public.edge e3 ` +
171
+ `JOIN public.fact f4 ` +
172
+ `ON f4.fact_id = e3.successor_fact_id ` +
173
+ `WHERE e3.predecessor_fact_id = f3.fact_id ` +
174
+ `AND e3.role_id = $5` +
175
+ `) ` +
176
+ `ORDER BY f3.fact_id ASC`
177
+ );
178
+ expect(tree.sqlQuery.parameters).toEqual([
179
+ getFactTypeId(factTypes, 'Company'),
180
+ companyHash,
181
+ roleParameter(roleMap, factTypes, 'Department', 'company'),
182
+ roleParameter(roleMap, factTypes, 'Project', 'department'),
183
+ roleParameter(roleMap, factTypes, 'Project.Deleted', 'project')
184
+ ]);
185
+ });
186
+
187
+ it("should read complex specifications", () => {
188
+ const { composer, factTypes, roleMap } = sqlFor(`
189
+ (company: Company, user: Jinaga.User) {
190
+ project: Project [
191
+ project->department: Department->company: Company = company
192
+ !E {
193
+ deleted: Project.Deleted [
194
+ deleted->project: Project = project
195
+ !E {
196
+ restored: Project.Restored [
197
+ restored->deleted: Project.Deleted = deleted
198
+ ]
199
+ }
200
+ ]
201
+ }
202
+ E {
203
+ assignment: Project.Assignment [
204
+ assignment->project: Project = project
205
+ assignment->user: Jinaga.User = user
206
+ !E {
207
+ revoked: Project.Assignment.Revoked [
208
+ revoked->assignment: Project.Assignment = assignment
209
+ ]
210
+ }
211
+ ]
212
+ }
213
+ ]
214
+ deliverable: Deliverable [
215
+ deliverable->project: Project = project
216
+ ]
217
+ } => {
218
+ assignedTasks = {
219
+ task: Task [
220
+ task->deliverable: Deliverable = deliverable
221
+ E {
222
+ assignment: Task.Assignment [
223
+ assignment->task: Task = task
224
+ assignment->user: Jinaga.User = user
225
+ ]
226
+ }
227
+ ]
228
+ } => {
229
+ number = task.number
230
+ }
231
+ }
232
+ `);
233
+
234
+ const queries = composer.getSqlQueries();
235
+ expect(queries.sqlQuery.sql).toEqual(
236
+ `SELECT ` +
237
+ `f3.hash as hash3, f3.fact_id as id3, f3.data as data3, ` +
238
+ `f9.hash as hash9, f9.fact_id as id9, f9.data as data9 ` +
239
+ `FROM public.fact f1 ` +
240
+ `JOIN public.edge e1 ` +
241
+ `ON e1.predecessor_fact_id = f1.fact_id ` +
242
+ `AND e1.role_id = $3 ` +
243
+ `JOIN public.fact f2 ` +
244
+ `ON f2.fact_id = e1.successor_fact_id ` +
245
+ `JOIN public.edge e2 ` +
246
+ `ON e2.predecessor_fact_id = f2.fact_id ` +
247
+ `AND e2.role_id = $4 ` +
248
+ `JOIN public.fact f3 ` +
249
+ `ON f3.fact_id = e2.successor_fact_id ` +
250
+ `JOIN public.edge e8 ` +
251
+ `ON e8.predecessor_fact_id = f3.fact_id ` +
252
+ `AND e8.role_id = $12 ` +
253
+ `JOIN public.fact f9 ` +
254
+ `ON f9.fact_id = e8.successor_fact_id ` +
255
+ `WHERE f1.fact_type_id = $1 AND f1.hash = $2 ` +
256
+ `AND NOT EXISTS (` +
257
+ `SELECT 1 ` +
258
+ `FROM public.edge e3 ` +
259
+ `JOIN public.fact f4 ` +
260
+ `ON f4.fact_id = e3.successor_fact_id ` +
261
+ `WHERE e3.predecessor_fact_id = f3.fact_id ` +
262
+ `AND e3.role_id = $5 ` +
263
+ `AND NOT EXISTS (` +
264
+ `SELECT 1 ` +
265
+ `FROM public.edge e4 ` +
266
+ `JOIN public.fact f5 ` +
267
+ `ON f5.fact_id = e4.successor_fact_id ` +
268
+ `WHERE e4.predecessor_fact_id = f4.fact_id AND e4.role_id = $6` +
269
+ `)` +
270
+ `) AND EXISTS (` +
271
+ `SELECT 1 ` +
272
+ `FROM public.edge e5 ` +
273
+ `JOIN public.fact f6 ` +
274
+ `ON f6.fact_id = e5.successor_fact_id ` +
275
+ `JOIN public.edge e6 ` +
276
+ `ON e6.successor_fact_id = f6.fact_id ` +
277
+ `AND e6.role_id = $10 ` +
278
+ `JOIN public.fact f7 ` +
279
+ `ON f7.fact_id = e6.predecessor_fact_id ` +
280
+ `WHERE e5.predecessor_fact_id = f3.fact_id AND e5.role_id = $7 ` +
281
+ `AND f7.fact_type_id = $8 AND f7.hash = $9 ` +
282
+ `AND NOT EXISTS (` +
283
+ `SELECT 1 ` +
284
+ `FROM public.edge e7 ` +
285
+ `JOIN public.fact f8 ` +
286
+ `ON f8.fact_id = e7.successor_fact_id ` +
287
+ `WHERE e7.predecessor_fact_id = f6.fact_id AND e7.role_id = $11` +
288
+ `)` +
289
+ `) ` +
290
+ `ORDER BY f3.fact_id ASC, f9.fact_id ASC`);
291
+ });
292
+ });
@@ -10,7 +10,7 @@ import {
10
10
  Step,
11
11
  } from "jinaga";
12
12
 
13
- import { addFactType, addRole, emptyFactTypeMap, emptyRoleMap, getFactTypeId, getRoleId } from "../../src/postgres/maps";
13
+ import { addFactType, addRole, emptyFactTypeMap, emptyRoleMap, ensureGetFactTypeId, getFactTypeId, getRoleId } from "../../src/postgres/maps";
14
14
  import { sqlFromSteps } from "../../src/postgres/sql";
15
15
  import { distinct } from "../../src/util/fn";
16
16
 
@@ -24,8 +24,8 @@ describe('Postgres', () => {
24
24
  const factTypes = allFactTypes(query.steps).filter(t => t !== 'Unknown').reduce(
25
25
  (f, factType, i) => addFactType(f, factType, i + 1),
26
26
  emptyFactTypeMap());
27
- let roleMap = allRoles(query.steps, 'Root').filter(r => r.role !== 'unknown').reduce(
28
- (r, role, i) => addRole(r, getFactTypeId(factTypes, role.type), role.role, i + 1),
27
+ let roleMap = allRoles(query.steps, 'Root').filter(r => r.type !== 'Unknown' && r.role !== 'unknown').reduce(
28
+ (r, role, i) => addRole(r, ensureGetFactTypeId(factTypes, role.type), role.role, i + 1),
29
29
  emptyRoleMap());
30
30
  const sqlQuery = sqlFromSteps(start, query.steps, factTypes, roleMap);
31
31
  return sqlQuery ? { sql: sqlQuery.sql, parameters: sqlQuery.parameters, pathLength: sqlQuery.pathLength, empty: sqlQuery.empty, factTypes, roleMap } : null;
@@ -61,7 +61,7 @@ describe('Postgres', () => {
61
61
  );
62
62
  expect(parameters[0]).toEqual(getFactTypeId(factTypes, 'Root'));
63
63
  expect(parameters[1]).toEqual(startHash);
64
- expect(parameters[2]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'IntegrationTest.Successor'), 'predecessor'));
64
+ expect(parameters[2]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'IntegrationTest.Successor'), 'predecessor'));
65
65
  expect(pathLength).toEqual(1);
66
66
  });
67
67
 
@@ -76,7 +76,7 @@ describe('Postgres', () => {
76
76
  );
77
77
  expect(parameters[0]).toEqual(getFactTypeId(factTypes, 'Root'));
78
78
  expect(parameters[1]).toEqual(startHash);
79
- expect(parameters[2]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'Root'), 'parent'));
79
+ expect(parameters[2]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Root'), 'parent'));
80
80
  expect(pathLength).toEqual(1);
81
81
  });
82
82
 
@@ -94,8 +94,8 @@ describe('Postgres', () => {
94
94
  );
95
95
  expect(parameters[0]).toEqual(getFactTypeId(factTypes, 'Root'));
96
96
  expect(parameters[1]).toEqual(startHash);
97
- expect(parameters[2]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'IntegrationTest.Successor'), 'predecessor'));
98
- expect(parameters[3]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'IntegrationTest.Grandchild'), 'successor'));
97
+ expect(parameters[2]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'IntegrationTest.Successor'), 'predecessor'));
98
+ expect(parameters[3]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'IntegrationTest.Grandchild'), 'successor'));
99
99
  expect(pathLength).toEqual(1);
100
100
  });
101
101
 
@@ -113,8 +113,8 @@ describe('Postgres', () => {
113
113
  );
114
114
  expect(parameters[0]).toEqual(getFactTypeId(factTypes, 'Root'));
115
115
  expect(parameters[1]).toEqual(startHash);
116
- expect(parameters[2]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'IntegrationTest.Successor'), 'predecessor'));
117
- expect(parameters[3]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'IntegrationTest.Grandchild'), 'successor'));
116
+ expect(parameters[2]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'IntegrationTest.Successor'), 'predecessor'));
117
+ expect(parameters[3]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'IntegrationTest.Grandchild'), 'successor'));
118
118
  expect(pathLength).toEqual(1);
119
119
  });
120
120
 
@@ -132,8 +132,8 @@ describe('Postgres', () => {
132
132
  );
133
133
  expect(parameters[0]).toEqual(getFactTypeId(factTypes, 'Root'));
134
134
  expect(parameters[1]).toEqual(startHash);
135
- expect(parameters[2]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'Child'), 'parent'));
136
- expect(parameters[3]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'Child'), 'uncle'));
135
+ expect(parameters[2]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Child'), 'parent'));
136
+ expect(parameters[3]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Child'), 'uncle'));
137
137
  expect(pathLength).toEqual(1);
138
138
  });
139
139
 
@@ -151,8 +151,8 @@ describe('Postgres', () => {
151
151
  );
152
152
  expect(parameters[0]).toEqual(getFactTypeId(factTypes, 'Root'));
153
153
  expect(parameters[1]).toEqual(startHash);
154
- expect(parameters[2]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'Child'), 'parent'));
155
- expect(parameters[3]).toEqual(getRoleId(roleMap, getFactTypeId(factTypes, 'Child'), 'uncle'));
154
+ expect(parameters[2]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Child'), 'parent'));
155
+ expect(parameters[3]).toEqual(getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Child'), 'uncle'));
156
156
  expect(pathLength).toEqual(1);
157
157
  });
158
158
 
@@ -174,9 +174,9 @@ describe('Postgres', () => {
174
174
  expect(parameters).toEqual([
175
175
  getFactTypeId(factTypes, 'Root'),
176
176
  startHash,
177
- getRoleId(roleMap, getFactTypeId(factTypes, 'Child'), 'parent'),
178
- getRoleId(roleMap, getFactTypeId(factTypes, 'Condition'), 'condition'),
179
- getRoleId(roleMap, getFactTypeId(factTypes, 'Other'), 'other')
177
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Child'), 'parent'),
178
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Condition'), 'condition'),
179
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Other'), 'other')
180
180
  ]);
181
181
  });
182
182
 
@@ -200,10 +200,10 @@ describe('Postgres', () => {
200
200
  expect(parameters).toEqual([
201
201
  getFactTypeId(factTypes, 'Root'),
202
202
  startHash,
203
- getRoleId(roleMap, getFactTypeId(factTypes, 'Identifier'), 'root'),
204
- getRoleId(roleMap, getFactTypeId(factTypes, 'Identifier'), 'prior'),
205
- getRoleId(roleMap, getFactTypeId(factTypes, 'Identifier'), 'identified'),
206
- getRoleId(roleMap, getFactTypeId(factTypes, 'Delete'), 'identified')
203
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Identifier'), 'root'),
204
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Identifier'), 'prior'),
205
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Identifier'), 'identified'),
206
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Delete'), 'identified')
207
207
  ]);
208
208
  });
209
209
 
@@ -230,10 +230,10 @@ describe('Postgres', () => {
230
230
  expect(parameters).toEqual([
231
231
  getFactTypeId(factTypes, 'Root'),
232
232
  startHash,
233
- getRoleId(roleMap, getFactTypeId(factTypes, 'Assignment'), 'user'),
234
- getRoleId(roleMap, getFactTypeId(factTypes, 'Assignment'), 'project'),
235
- getRoleId(roleMap, getFactTypeId(factTypes, 'Task'), 'project'),
236
- getRoleId(roleMap, getFactTypeId(factTypes, 'Task.Title'), 'task')
233
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Assignment'), 'user'),
234
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Assignment'), 'project'),
235
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Task'), 'project'),
236
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Task.Title'), 'task')
237
237
  ]);
238
238
  expect(pathLength).toEqual(4);
239
239
  });
@@ -281,7 +281,7 @@ describe('Postgres', () => {
281
281
  expect(parameters).toEqual([
282
282
  getFactTypeId(factTypes, 'Root'),
283
283
  startHash,
284
- getRoleId(roleMap, getFactTypeId(factTypes, 'Assignment'), 'root')
284
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Assignment'), 'root')
285
285
  ]);
286
286
  });
287
287
 
@@ -298,7 +298,7 @@ describe('Postgres', () => {
298
298
  expect(parameters).toEqual([
299
299
  getFactTypeId(factTypes, 'Root'),
300
300
  startHash,
301
- getRoleId(roleMap, getFactTypeId(factTypes, 'Assignment'), 'root')
301
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'Assignment'), 'root')
302
302
  ]);
303
303
  });
304
304
 
@@ -332,11 +332,11 @@ describe('Postgres', () => {
332
332
  ')' +
333
333
  ')');
334
334
  expect(parameters).toEqual([
335
- getFactTypeId(factTypes, 'Catalog'),
335
+ getFactTypeId(factTypes, 'Root'),
336
336
  startHash,
337
- getRoleId(roleMap, getFactTypeId(factTypes, 'ImprovingU.Idea'), 'catalog'),
338
- getRoleId(roleMap, getFactTypeId(factTypes, 'ImprovingU.Idea.Deletion'), 'idea'),
339
- getRoleId(roleMap, getFactTypeId(factTypes, 'ImprovingU.Idea.Restore'), 'ideaDeletion')
337
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'ImprovingU.Idea'), 'catalog'),
338
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'ImprovingU.Idea.Deletion'), 'idea'),
339
+ getRoleId(roleMap, ensureGetFactTypeId(factTypes, 'ImprovingU.Idea.Restore'), 'ideaDeletion')
340
340
  ]);
341
341
  });
342
342
  });
@@ -348,7 +348,7 @@ function allFactTypes(steps: Step[]): string[] {
348
348
  const childFactTypes = steps
349
349
  .filter(step => step instanceof ExistentialCondition)
350
350
  .flatMap(step => allFactTypes((step as ExistentialCondition).steps));
351
- return [...factTypes, ...childFactTypes].filter(distinct);
351
+ return ["Root", ...factTypes, ...childFactTypes].filter(distinct);
352
352
  }
353
353
 
354
354
  function allRoles(steps: Step[], initialType: string) {
@@ -28,7 +28,7 @@ function sqlFor(descriptiveString: string, bookmarks: string[] = []) {
28
28
  // Filter out the roles named "unknown", and those of unknown fact types.
29
29
  let roleMap = getAllRoles(specification).filter(r => r.name !== 'unknown').reduce(
30
30
  (r, role, i) => {
31
- const factTypeId = getFactTypeId(factTypes, role.definingFactType);
31
+ const factTypeId = getFactTypeId(factTypes, role.successorType);
32
32
  if (!factTypeId) {
33
33
  return r;
34
34
  }
package/tsconfig.json CHANGED
@@ -8,6 +8,7 @@
8
8
  "sourceMap": true,
9
9
  "declaration": true,
10
10
  "outDir": "./dist",
11
+ "strict": true,
11
12
  "forceConsistentCasingInFileNames": true,
12
13
  "skipLibCheck": true,
13
14
  "esModuleInterop": true,
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "target": "es6",
5
+ "lib": [ "ES2019" ],
6
+ "noImplicitAny": true,
7
+ "moduleResolution": "node",
8
+ "sourceMap": true,
9
+ "declaration": true,
10
+ "outDir": "./dist",
11
+ "strict": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "skipLibCheck": true,
14
+ "esModuleInterop": true,
15
+ "baseUrl": ".",
16
+ "paths": {
17
+ "*": [
18
+ "./node_modules/*",
19
+ "./types/*"
20
+ ]
21
+ }
22
+ },
23
+ "include": [
24
+ "test/**/*.ts"
25
+ ]
26
+ }
@@ -1,41 +0,0 @@
1
- let user: Jinaga.User = me
2
- let semester: ImprovingU.Semester = #Ws6RWV8bWmP7ibBlzwL2UoKKwg6E1iItQPFpX/mvU5u6FLwHJAbRd0SbH+P1hoMn4QndhArLqJqVReRqJdoyBg==
3
-
4
- (semester: ImprovingU.Semester, user: Jinaga.User) {
5
- catalog: ImprovingU.Catalog [
6
- catalog->_in:ImprovingU.Semester = semester
7
- ]
8
- } => {
9
- office = catalog.office
10
- courses = {
11
- course: ImprovingU.Course [
12
- course->_in:ImprovingU.Catalog = catalog
13
- !E {
14
- delete: ImprovingU.Course.Delete [
15
- delete->course:ImprovingU.Course = course
16
- ]
17
- }
18
- ]
19
- } => {
20
- titles = {
21
- title: ImprovingU.Course.Title [
22
- title->course: ImprovingU.Course = course
23
- !E {
24
- next: ImprovingU.Course.Title [
25
- next->prior: ImprovingU.Course.Title = title
26
- ]
27
- }
28
- ]
29
- } => title.value
30
- instructors = {
31
- instructor: ImprovingU.Course.Instructor [
32
- instructor->course: ImprovingU.Course = course
33
- !E {
34
- next: ImprovingU.Course.Instructor [
35
- next->prior: ImprovingU.Course.Instructor = instructor
36
- ]
37
- }
38
- ]
39
- } => instructor.value
40
- }
41
- }