jinaga-server 2.1.7 → 2.2.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.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/jinaga-server.d.ts +2 -0
- package/dist/jinaga-server.js +13 -2
- package/dist/jinaga-server.js.map +1 -1
- package/dist/postgres/postgres-keystore.d.ts +2 -1
- package/dist/postgres/postgres-keystore.js +5 -4
- package/dist/postgres/postgres-keystore.js.map +1 -1
- package/dist/postgres/postgres-store.d.ts +2 -1
- package/dist/postgres/postgres-store.js +54 -53
- package/dist/postgres/postgres-store.js.map +1 -1
- package/dist/postgres/specification-result-sql.d.ts +1 -1
- package/dist/postgres/specification-result-sql.js +21 -21
- package/dist/postgres/specification-result-sql.js.map +1 -1
- package/dist/postgres/specification-sql.d.ts +2 -2
- package/dist/postgres/specification-sql.js +19 -19
- package/dist/postgres/specification-sql.js.map +1 -1
- package/dist/postgres/sql.d.ts +1 -1
- package/dist/postgres/sql.js +14 -14
- package/dist/postgres/sql.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/src/jinaga-server.ts +19 -3
- package/src/postgres/postgres-keystore.ts +4 -4
- package/src/postgres/postgres-store.ts +53 -53
- package/src/postgres/specification-result-sql.ts +21 -21
- package/src/postgres/specification-sql.ts +19 -19
- package/src/postgres/sql.ts +14 -14
- package/test/postgres/postgresReadSpec.ts +1 -1
- package/test/postgres/postgresSpec.ts +1 -1
- package/test/postgres/postgresSpecificationSpec.ts +1 -1
|
@@ -147,7 +147,7 @@ export class PostgresStore implements Storage {
|
|
|
147
147
|
private factTypeMap: FactTypeMap = emptyFactTypeMap();
|
|
148
148
|
private roleMap: RoleMap = emptyRoleMap();
|
|
149
149
|
|
|
150
|
-
constructor (pool: Pool) {
|
|
150
|
+
constructor (pool: Pool, private schema: string) {
|
|
151
151
|
this.connectionFactory = new ConnectionFactory(pool);
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -166,8 +166,8 @@ export class PostgresStore implements Storage {
|
|
|
166
166
|
factTypes: FactTypeMap;
|
|
167
167
|
roles: RoleMap;
|
|
168
168
|
} = await this.connectionFactory.withTransaction(async (connection) => {
|
|
169
|
-
const factTypes = await storeFactTypes(facts, this.factTypeMap, connection);
|
|
170
|
-
const existingFacts = await findExistingFacts(facts, factTypes, connection);
|
|
169
|
+
const factTypes = await storeFactTypes(facts, this.factTypeMap, connection, this.schema);
|
|
170
|
+
const existingFacts = await findExistingFacts(facts, factTypes, connection, this.schema);
|
|
171
171
|
const newFacts = facts.filter(f => !hasFact(existingFacts, f.hash, ensureGetFactTypeId(factTypes, f.type)));
|
|
172
172
|
if (newFacts.length === 0) {
|
|
173
173
|
return {
|
|
@@ -177,8 +177,8 @@ export class PostgresStore implements Storage {
|
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
const roles = await storeRoles(newFacts, factTypes, copyRoleMap(this.roleMap), connection);
|
|
181
|
-
const allFacts = await insertFactsEdgesAndAncestors(newFacts, factTypes, existingFacts, connection, roles);
|
|
180
|
+
const roles = await storeRoles(newFacts, factTypes, copyRoleMap(this.roleMap), connection, this.schema);
|
|
181
|
+
const allFacts = await insertFactsEdgesAndAncestors(newFacts, factTypes, existingFacts, connection, roles, this.schema);
|
|
182
182
|
const newEnvelopes = envelopes.filter(envelope => newFacts.some(
|
|
183
183
|
factReferenceEquals(envelope.fact)));
|
|
184
184
|
if (newEnvelopes.length === 0) {
|
|
@@ -189,8 +189,8 @@ export class PostgresStore implements Storage {
|
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
const publicKeys = await storePublicKeys(newEnvelopes, connection);
|
|
193
|
-
await insertSignatures(newEnvelopes, allFacts, factTypes, publicKeys, connection);
|
|
192
|
+
const publicKeys = await storePublicKeys(newEnvelopes, connection, this.schema);
|
|
193
|
+
await insertSignatures(newEnvelopes, allFacts, factTypes, publicKeys, connection, this.schema);
|
|
194
194
|
return {
|
|
195
195
|
newEnvelopes,
|
|
196
196
|
factTypes,
|
|
@@ -215,7 +215,7 @@ export class PostgresStore implements Storage {
|
|
|
215
215
|
const factTypes = await this.loadFactTypesFromSteps(query.steps, start.type);
|
|
216
216
|
const roleMap = await this.loadRolesFromSteps(query.steps, factTypes, start.type);
|
|
217
217
|
|
|
218
|
-
const sqlQuery = sqlFromSteps(start, query.steps, factTypes, roleMap);
|
|
218
|
+
const sqlQuery = sqlFromSteps(start, query.steps, factTypes, roleMap, this.schema);
|
|
219
219
|
if (!sqlQuery) {
|
|
220
220
|
throw new Error(`Could not generate SQL for query "${query.toDescriptiveString()}" starting at "${start.type}"`);
|
|
221
221
|
}
|
|
@@ -241,7 +241,7 @@ export class PostgresStore implements Storage {
|
|
|
241
241
|
return [];
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
const composer = resultSqlFromSpecification(start, specification, factTypes, roleMap);
|
|
244
|
+
const composer = resultSqlFromSpecification(start, specification, factTypes, roleMap, this.schema);
|
|
245
245
|
if (composer === null) {
|
|
246
246
|
return [];
|
|
247
247
|
}
|
|
@@ -256,7 +256,7 @@ export class PostgresStore implements Storage {
|
|
|
256
256
|
async feed(feed: Feed, bookmark: string): Promise<FactFeed> {
|
|
257
257
|
const factTypes: FactTypeMap = await this.loadFactTypesFromFeed(feed);
|
|
258
258
|
const roleMap: RoleMap = await this.loadRolesFromFeed(feed, factTypes);
|
|
259
|
-
const sql = sqlFromFeed(feed, bookmark, 100, factTypes, roleMap);
|
|
259
|
+
const sql = sqlFromFeed(feed, this.schema, bookmark, 100, factTypes, roleMap);
|
|
260
260
|
if (!sql) {
|
|
261
261
|
return {
|
|
262
262
|
tuples: [],
|
|
@@ -281,7 +281,7 @@ export class PostgresStore implements Storage {
|
|
|
281
281
|
.filter(distinct);
|
|
282
282
|
if (unknownFactTypes.length > 0) {
|
|
283
283
|
const loadedFactTypes = await this.connectionFactory.with(async (connection) => {
|
|
284
|
-
return await loadFactTypes(unknownFactTypes, connection);
|
|
284
|
+
return await loadFactTypes(unknownFactTypes, connection, this.schema);
|
|
285
285
|
});
|
|
286
286
|
const merged = mergeFactTypes(this.factTypeMap, loadedFactTypes);
|
|
287
287
|
this.factTypeMap = merged;
|
|
@@ -296,7 +296,7 @@ export class PostgresStore implements Storage {
|
|
|
296
296
|
.filter(factType => !factTypes.has(factType));
|
|
297
297
|
if (unknownFactTypes.length > 0) {
|
|
298
298
|
const loadedFactTypes = await this.connectionFactory.with(async (connection) => {
|
|
299
|
-
return await loadFactTypes(unknownFactTypes, connection);
|
|
299
|
+
return await loadFactTypes(unknownFactTypes, connection, this.schema);
|
|
300
300
|
});
|
|
301
301
|
const merged = mergeFactTypes(this.factTypeMap, loadedFactTypes);
|
|
302
302
|
this.factTypeMap = merged;
|
|
@@ -311,7 +311,7 @@ export class PostgresStore implements Storage {
|
|
|
311
311
|
.filter(factType => !factTypes.has(factType));
|
|
312
312
|
if (unknownFactTypes.length > 0) {
|
|
313
313
|
const loadedFactTypes = await this.connectionFactory.with(async (connection) => {
|
|
314
|
-
return await loadFactTypes(unknownFactTypes, connection);
|
|
314
|
+
return await loadFactTypes(unknownFactTypes, connection, this.schema);
|
|
315
315
|
});
|
|
316
316
|
const merged = mergeFactTypes(this.factTypeMap, loadedFactTypes);
|
|
317
317
|
this.factTypeMap = merged;
|
|
@@ -326,7 +326,7 @@ export class PostgresStore implements Storage {
|
|
|
326
326
|
.filter(r => !hasRole(roleMap, r.successor_type_id, r.role));
|
|
327
327
|
if (unknownRoles.length > 0) {
|
|
328
328
|
const loadedRoles = await this.connectionFactory.with(async (connection) => {
|
|
329
|
-
return await loadRoles(unknownRoles, roleMap, connection);
|
|
329
|
+
return await loadRoles(unknownRoles, roleMap, connection, this.schema);
|
|
330
330
|
});
|
|
331
331
|
const merged = mergeRoleMaps(this.roleMap, loadedRoles);
|
|
332
332
|
this.roleMap = merged;
|
|
@@ -346,7 +346,7 @@ export class PostgresStore implements Storage {
|
|
|
346
346
|
.filter(r => r.successor_type_id && !hasRole(roleMap, r.successor_type_id, r.role));
|
|
347
347
|
if (unknownRoles.length > 0) {
|
|
348
348
|
const loadedRoles = await this.connectionFactory.with(async (connection) => {
|
|
349
|
-
return await loadRoles(unknownRoles, roleMap, connection);
|
|
349
|
+
return await loadRoles(unknownRoles, roleMap, connection, this.schema);
|
|
350
350
|
});
|
|
351
351
|
const merged = mergeRoleMaps(this.roleMap, loadedRoles);
|
|
352
352
|
this.roleMap = merged;
|
|
@@ -365,7 +365,7 @@ export class PostgresStore implements Storage {
|
|
|
365
365
|
.filter(r => r.successor_type_id && !hasRole(roleMap, r.successor_type_id, r.role));
|
|
366
366
|
if (unknownRoles.length > 0) {
|
|
367
367
|
const loadedRoles = await this.connectionFactory.with(async (connection) => {
|
|
368
|
-
return await loadRoles(unknownRoles, roleMap, connection);
|
|
368
|
+
return await loadRoles(unknownRoles, roleMap, connection, this.schema);
|
|
369
369
|
});
|
|
370
370
|
const merged = mergeRoleMaps(this.roleMap, loadedRoles);
|
|
371
371
|
this.roleMap = merged;
|
|
@@ -387,7 +387,7 @@ export class PostgresStore implements Storage {
|
|
|
387
387
|
[f.hash, factTypes.get(f.type)]);
|
|
388
388
|
const sql =
|
|
389
389
|
'SELECT f.fact_type_id, f.hash ' +
|
|
390
|
-
|
|
390
|
+
`FROM ${this.schema}.fact f ` +
|
|
391
391
|
'JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id) ' +
|
|
392
392
|
' ON v.fact_type_id = f.fact_type_id AND v.hash = f.hash ';
|
|
393
393
|
const result: ExistsResult = await this.connectionFactory.with(async (connection) => {
|
|
@@ -415,21 +415,21 @@ export class PostgresStore implements Storage {
|
|
|
415
415
|
[f.hash, factTypes.get(f.type)]);
|
|
416
416
|
const sql =
|
|
417
417
|
'SELECT f.fact_type_id, t.name, f.hash, f.data ' +
|
|
418
|
-
|
|
419
|
-
|
|
418
|
+
`FROM ${this.schema}.fact f ` +
|
|
419
|
+
`JOIN ${this.schema}.fact_type t ` +
|
|
420
420
|
' ON f.fact_type_id = t.fact_type_id ' +
|
|
421
421
|
'JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id) ' +
|
|
422
422
|
' ON v.fact_type_id = f.fact_type_id AND v.hash = f.hash ' +
|
|
423
423
|
'UNION ' +
|
|
424
424
|
'SELECT f2.fact_type_id, t.name, f2.hash, f2.data ' +
|
|
425
|
-
|
|
425
|
+
`FROM ${this.schema}.fact f1 ` +
|
|
426
426
|
'JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id) ' +
|
|
427
427
|
' ON v.fact_type_id = f1.fact_type_id AND v.hash = f1.hash ' +
|
|
428
|
-
|
|
428
|
+
`JOIN ${this.schema}.ancestor a ` +
|
|
429
429
|
' ON a.fact_id = f1.fact_id ' +
|
|
430
|
-
|
|
430
|
+
`JOIN ${this.schema}.fact f2 ` +
|
|
431
431
|
' ON f2.fact_id = a.ancestor_fact_id ' +
|
|
432
|
-
|
|
432
|
+
`JOIN ${this.schema}.fact_type t ` +
|
|
433
433
|
' ON t.fact_type_id = f2.fact_type_id;';
|
|
434
434
|
const result: AncestorResult = await this.connectionFactory.with(async (connection) => {
|
|
435
435
|
return await connection.query(sql, factParameters);
|
|
@@ -460,7 +460,7 @@ export class PostgresStore implements Storage {
|
|
|
460
460
|
.filter(distinct);
|
|
461
461
|
if (newFactTypes.length > 0) {
|
|
462
462
|
const loadedFactTypes = await this.connectionFactory.with(async (connection) => {
|
|
463
|
-
return await loadFactTypes(newFactTypes, connection);
|
|
463
|
+
return await loadFactTypes(newFactTypes, connection, this.schema);
|
|
464
464
|
});
|
|
465
465
|
const mergedFactTypes = mergeFactTypes(factTypes, loadedFactTypes);
|
|
466
466
|
this.factTypeMap = mergedFactTypes;
|
|
@@ -506,7 +506,7 @@ function predecessorCollectionTypes(predecessors: PredecessorCollection): string
|
|
|
506
506
|
return Object.keys(predecessors).flatMap(key => predecessorTypes(predecessors[key]));
|
|
507
507
|
}
|
|
508
508
|
|
|
509
|
-
async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient) {
|
|
509
|
+
async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient, schema: string) {
|
|
510
510
|
const newFactTypes = facts
|
|
511
511
|
.flatMap(fact => [fact.type, ...predecessorCollectionTypes(fact.predecessors)])
|
|
512
512
|
.filter(type => !factTypes.has(type))
|
|
@@ -516,7 +516,7 @@ async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, conne
|
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
// Look up existing fact types
|
|
519
|
-
const loadedFactTypes = await loadFactTypes(newFactTypes, connection);
|
|
519
|
+
const loadedFactTypes = await loadFactTypes(newFactTypes, connection, schema);
|
|
520
520
|
const remainingNames = newFactTypes.filter(type => !loadedFactTypes.has(type));
|
|
521
521
|
if (remainingNames.length === 0) {
|
|
522
522
|
return mergeFactTypes(loadedFactTypes, factTypes);
|
|
@@ -524,7 +524,7 @@ async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, conne
|
|
|
524
524
|
|
|
525
525
|
// Insert new fact types
|
|
526
526
|
const values = remainingNames.map((name, index) => `($${index + 1})`);
|
|
527
|
-
const insertSql =
|
|
527
|
+
const insertSql = `INSERT INTO ${schema}.fact_type (name) VALUES ` + values.join(', ') +
|
|
528
528
|
' RETURNING fact_type_id, name;';
|
|
529
529
|
const { rows: newRows }: FactTypeResult = await connection.query(insertSql, remainingNames);
|
|
530
530
|
if (newRows.length !== remainingNames.length) {
|
|
@@ -537,8 +537,8 @@ async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, conne
|
|
|
537
537
|
return allFactTypes;
|
|
538
538
|
}
|
|
539
539
|
|
|
540
|
-
async function loadFactTypes(factTypeNames: string[], connection: PoolClient) {
|
|
541
|
-
const lookUpSql =
|
|
540
|
+
async function loadFactTypes(factTypeNames: string[], connection: PoolClient, schema: string) {
|
|
541
|
+
const lookUpSql = `SELECT name, fact_type_id FROM ${schema}.fact_type WHERE name=ANY($1);`;
|
|
542
542
|
const { rows: existingRows }: FactTypeResult = await connection.query(lookUpSql, [factTypeNames]);
|
|
543
543
|
const factTypeIds = existingRows.reduce(
|
|
544
544
|
(map, row) => addFactType(map, row.name, row.fact_type_id),
|
|
@@ -547,7 +547,7 @@ async function loadFactTypes(factTypeNames: string[], connection: PoolClient) {
|
|
|
547
547
|
return factTypeIds;
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
-
async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap: RoleMap, connection: PoolClient) {
|
|
550
|
+
async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap: RoleMap, connection: PoolClient, schema: string) {
|
|
551
551
|
// Find distinct roles
|
|
552
552
|
const roles = flatten(facts, fact => {
|
|
553
553
|
const successor_type_id = ensureGetFactTypeId(factTypes, fact.type);
|
|
@@ -562,7 +562,7 @@ async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap:
|
|
|
562
562
|
|
|
563
563
|
if (roles.length > 0) {
|
|
564
564
|
// Look up existing roles
|
|
565
|
-
const roleIds = await loadRoles(roles, roleMap, connection);
|
|
565
|
+
const roleIds = await loadRoles(roles, roleMap, connection, schema);
|
|
566
566
|
const remainingRoles = roles.filter(role => !hasRole(
|
|
567
567
|
roleIds, role.successor_type_id, role.role));
|
|
568
568
|
if (remainingRoles.length === 0) {
|
|
@@ -572,7 +572,7 @@ async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap:
|
|
|
572
572
|
// Insert new roles
|
|
573
573
|
const remainingRoleValues = remainingRoles.map((role, index) =>
|
|
574
574
|
`($${index * 2 + 1}, $${index * 2 + 2}::integer)`);
|
|
575
|
-
const insertSql =
|
|
575
|
+
const insertSql = `INSERT INTO ${schema}.role (name, defining_fact_type_id) VALUES ` +
|
|
576
576
|
remainingRoleValues.join(', ') +
|
|
577
577
|
' RETURNING role_id, name, defining_fact_type_id;';
|
|
578
578
|
const remainingRoleParameters = flatten(remainingRoles, (role) => [
|
|
@@ -594,7 +594,7 @@ async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap:
|
|
|
594
594
|
}
|
|
595
595
|
}
|
|
596
596
|
|
|
597
|
-
async function loadRoles(roles: { role: string; successor_type_id: number; }[], roleMap: RoleMap, connection: PoolClient) {
|
|
597
|
+
async function loadRoles(roles: { role: string; successor_type_id: number; }[], roleMap: RoleMap, connection: PoolClient, schema: string) {
|
|
598
598
|
const roleValues = roles.map((role, index) =>
|
|
599
599
|
`($${index * 2 + 1}, $${index * 2 + 2}::integer)`);
|
|
600
600
|
const roleParameters = flatten(roles, (role) => [
|
|
@@ -603,7 +603,7 @@ async function loadRoles(roles: { role: string; successor_type_id: number; }[],
|
|
|
603
603
|
]);
|
|
604
604
|
|
|
605
605
|
const lookUpSql = 'SELECT role.name, role.defining_fact_type_id, role.role_id' +
|
|
606
|
-
|
|
606
|
+
` FROM ${schema}.role` +
|
|
607
607
|
' JOIN (VALUES ' + roleValues.join(', ') + ') AS v (name, defining_fact_type_id)' +
|
|
608
608
|
' ON v.name = role.name AND v.defining_fact_type_id = role.defining_fact_type_id;';
|
|
609
609
|
const { rows }: RoleResult = await connection.query(lookUpSql, roleParameters);
|
|
@@ -614,7 +614,7 @@ async function loadRoles(roles: { role: string; successor_type_id: number; }[],
|
|
|
614
614
|
return roleIds;
|
|
615
615
|
}
|
|
616
616
|
|
|
617
|
-
async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient) {
|
|
617
|
+
async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient, schema: string) {
|
|
618
618
|
if (facts.length > 0) {
|
|
619
619
|
const factReferences: FactReference[] = facts.flatMap(fact => [
|
|
620
620
|
...predecessorsOf(fact),
|
|
@@ -626,7 +626,7 @@ async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, co
|
|
|
626
626
|
[f.hash, factTypes.get(f.type)]);
|
|
627
627
|
|
|
628
628
|
const sql = 'SELECT fact_id, fact.fact_type_id, fact.hash' +
|
|
629
|
-
|
|
629
|
+
` FROM ${schema}.fact` +
|
|
630
630
|
' JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id)' +
|
|
631
631
|
' ON v.fact_type_id = fact.fact_type_id AND v.hash = fact.hash;';
|
|
632
632
|
const { rows }: FactResult = await connection.query(sql, factParameters);
|
|
@@ -641,12 +641,12 @@ async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, co
|
|
|
641
641
|
}
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
-
async function insertFactsEdgesAndAncestors(facts: FactRecord[], factTypes: FactTypeMap, existingFacts: Map<string, Map<number, number>>, connection: PoolClient, roles: RoleMap) {
|
|
644
|
+
async function insertFactsEdgesAndAncestors(facts: FactRecord[], factTypes: FactTypeMap, existingFacts: Map<string, Map<number, number>>, connection: PoolClient, roles: RoleMap, schema: string) {
|
|
645
645
|
if (facts.length === 0) {
|
|
646
646
|
return emptyFactMap();
|
|
647
647
|
}
|
|
648
648
|
|
|
649
|
-
const { sql, parameters } = sqlInsertFacts(facts, roles, factTypes);
|
|
649
|
+
const { sql, parameters } = sqlInsertFacts(facts, roles, factTypes, schema);
|
|
650
650
|
|
|
651
651
|
const { rows }: FactResult = await connection.query(sql, parameters);
|
|
652
652
|
if (rows.length !== facts.length) {
|
|
@@ -659,7 +659,7 @@ async function insertFactsEdgesAndAncestors(facts: FactRecord[], factTypes: Fact
|
|
|
659
659
|
return allFacts;
|
|
660
660
|
}
|
|
661
661
|
|
|
662
|
-
function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactTypeMap) {
|
|
662
|
+
function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactTypeMap, schema: string) {
|
|
663
663
|
const factValues = facts.map((f, i) => `(\$${i * 3 + 1}, \$${i * 3 + 2}::integer, \$${i * 3 + 3}::jsonb)`);
|
|
664
664
|
const factParameters = flatten(facts, (f) => [f.hash, ensureGetFactTypeId(factTypes, f.type), {
|
|
665
665
|
fields: f.fields,
|
|
@@ -668,11 +668,11 @@ function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactType
|
|
|
668
668
|
|
|
669
669
|
const edgeRecords = flatten(facts, fact => makeEdgeRecords(fact));
|
|
670
670
|
if (edgeRecords.length > 0) {
|
|
671
|
-
return sqlInsertFactsEdgesAndAncestors(facts, factParameters, edgeRecords, factTypes, roles, factValues);
|
|
671
|
+
return sqlInsertFactsEdgesAndAncestors(facts, factParameters, edgeRecords, factTypes, roles, factValues, schema);
|
|
672
672
|
}
|
|
673
673
|
else {
|
|
674
674
|
return {
|
|
675
|
-
sql:
|
|
675
|
+
sql: `INSERT INTO ${schema}.fact (hash, fact_type_id, data) VALUES ` +
|
|
676
676
|
factValues.join(', ') +
|
|
677
677
|
' RETURNING fact_id, hash, fact_type_id;',
|
|
678
678
|
parameters: factParameters
|
|
@@ -680,7 +680,7 @@ function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactType
|
|
|
680
680
|
}
|
|
681
681
|
}
|
|
682
682
|
|
|
683
|
-
function sqlInsertFactsEdgesAndAncestors(facts: FactRecord[], factParameters: (string | number | { fields: {}; predecessors: PredecessorCollection; })[], edgeRecords: EdgeRecord[], factTypes: FactTypeMap, roles: RoleMap, factValues: string[]) {
|
|
683
|
+
function sqlInsertFactsEdgesAndAncestors(facts: FactRecord[], factParameters: (string | number | { fields: {}; predecessors: PredecessorCollection; })[], edgeRecords: EdgeRecord[], factTypes: FactTypeMap, roles: RoleMap, factValues: string[], schema: string) {
|
|
684
684
|
let parameterOffset = factParameters.length;
|
|
685
685
|
const edgeValues = edgeRecords.map((e, i) => `(\$${i * 5 + 1 + parameterOffset}, \$${i * 5 + 2 + parameterOffset}::integer, \$${i * 5 + 3 + parameterOffset}, \$${i * 5 + 4 + parameterOffset}::integer, \$${i * 5 + 5 + parameterOffset}::integer)`);
|
|
686
686
|
const edgeParameters = flatten(edgeRecords, (e) => {
|
|
@@ -722,13 +722,13 @@ new_ancestor AS (
|
|
|
722
722
|
AS ev (hash, fact_type_id, ancestor_hash, ancestor_fact_type_id)
|
|
723
723
|
),
|
|
724
724
|
inserted_fact AS (
|
|
725
|
-
INSERT INTO
|
|
725
|
+
INSERT INTO ${schema}.fact (hash, fact_type_id, data)
|
|
726
726
|
SELECT hash, fact_type_id, data
|
|
727
727
|
FROM new_fact
|
|
728
728
|
RETURNING fact_id, fact_type_id, hash
|
|
729
729
|
),
|
|
730
730
|
inserted_edge AS (
|
|
731
|
-
INSERT INTO
|
|
731
|
+
INSERT INTO ${schema}.edge
|
|
732
732
|
(role_id, successor_fact_id, predecessor_fact_id)
|
|
733
733
|
SELECT
|
|
734
734
|
new_edge.role_id,
|
|
@@ -743,7 +743,7 @@ inserted_edge AS (
|
|
|
743
743
|
FROM inserted_fact
|
|
744
744
|
UNION ALL
|
|
745
745
|
SELECT fact_id, fact_type_id, hash
|
|
746
|
-
FROM
|
|
746
|
+
FROM ${schema}.fact
|
|
747
747
|
) AS predecessor
|
|
748
748
|
ON predecessor.hash = new_edge.predecessor_hash
|
|
749
749
|
AND predecessor.fact_type_id = new_edge.predecessor_fact_type_id
|
|
@@ -762,20 +762,20 @@ ancestor_id AS (
|
|
|
762
762
|
FROM inserted_fact
|
|
763
763
|
UNION ALL
|
|
764
764
|
SELECT fact_id, fact_type_id, hash
|
|
765
|
-
FROM
|
|
765
|
+
FROM ${schema}.fact
|
|
766
766
|
) AS ancestor
|
|
767
767
|
ON ancestor.hash = new_ancestor.ancestor_hash
|
|
768
768
|
AND ancestor.fact_type_id = new_ancestor.ancestor_fact_type_id
|
|
769
769
|
),
|
|
770
770
|
inserted_ancestor AS (
|
|
771
|
-
INSERT INTO
|
|
771
|
+
INSERT INTO ${schema}.ancestor
|
|
772
772
|
(fact_id, ancestor_fact_id)
|
|
773
773
|
SELECT ancestor_id.fact_id, ancestor_id.ancestor_fact_id
|
|
774
774
|
FROM ancestor_id
|
|
775
775
|
UNION ALL
|
|
776
776
|
SELECT ancestor_id.fact_id, ancestor.ancestor_fact_id
|
|
777
777
|
FROM ancestor_id
|
|
778
|
-
JOIN
|
|
778
|
+
JOIN ${schema}.ancestor
|
|
779
779
|
ON ancestor.fact_id = ancestor_id.ancestor_fact_id
|
|
780
780
|
ON CONFLICT DO NOTHING
|
|
781
781
|
)
|
|
@@ -816,11 +816,11 @@ function recursivePredecessors(factReference: FactReference, facts: FactRecord[]
|
|
|
816
816
|
});
|
|
817
817
|
}
|
|
818
818
|
|
|
819
|
-
async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient) {
|
|
819
|
+
async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient, schema: string) {
|
|
820
820
|
// Look up existing fact types
|
|
821
821
|
const publicKeys = flatten(envelopes, e => e.signatures.map(s => s.publicKey))
|
|
822
822
|
.filter(distinct);
|
|
823
|
-
const lookUpSql =
|
|
823
|
+
const lookUpSql = `SELECT public_key, public_key_id FROM ${schema}.public_key WHERE public_key=ANY($1);`;
|
|
824
824
|
const { rows: existingRows }: PublicKeyResult = await connection.query(lookUpSql, [publicKeys]);
|
|
825
825
|
const publicKeyIds = existingRows.reduce(
|
|
826
826
|
(map, row) => addFactType(map, row.public_key, row.public_key_id),
|
|
@@ -833,7 +833,7 @@ async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient
|
|
|
833
833
|
|
|
834
834
|
// Insert new fact types
|
|
835
835
|
const values = remainingPublicKeys.map((name, index) => `($${index + 1})`);
|
|
836
|
-
const insertSql =
|
|
836
|
+
const insertSql = `INSERT INTO ${schema}.public_key (public_key) VALUES ` + values.join(', ') +
|
|
837
837
|
' RETURNING public_key, public_key_id;';
|
|
838
838
|
const { rows: newRows }: PublicKeyResult = await connection.query(insertSql, remainingPublicKeys);
|
|
839
839
|
if (newRows.length !== remainingPublicKeys.length) {
|
|
@@ -846,7 +846,7 @@ async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient
|
|
|
846
846
|
return allPublicKeyIds;
|
|
847
847
|
}
|
|
848
848
|
|
|
849
|
-
async function insertSignatures(envelopes: FactEnvelope[], allFacts: FactMap, factTypes: FactTypeMap, publicKey: PublicKeyMap, connection: PoolClient) {
|
|
849
|
+
async function insertSignatures(envelopes: FactEnvelope[], allFacts: FactMap, factTypes: FactTypeMap, publicKey: PublicKeyMap, connection: PoolClient, schema: string) {
|
|
850
850
|
const signatureRecords = flatten(envelopes, envelope => envelope.signatures.map(signature => ({
|
|
851
851
|
factId: getFactId(allFacts, envelope.fact.hash, ensureGetFactTypeId(factTypes, envelope.fact.type)),
|
|
852
852
|
publicKeyId: getPublicKeyId(publicKey, signature.publicKey),
|
|
@@ -858,7 +858,7 @@ async function insertSignatures(envelopes: FactEnvelope[], allFacts: FactMap, fa
|
|
|
858
858
|
const signatureParameters = flatten(signatureRecords, s =>
|
|
859
859
|
[s.factId, s.publicKeyId, s.signature]);
|
|
860
860
|
|
|
861
|
-
const sql = `INSERT INTO
|
|
861
|
+
const sql = `INSERT INTO ${schema}.signature
|
|
862
862
|
(fact_id, public_key_id, signature)
|
|
863
863
|
(SELECT fact_id, public_key_id, signature
|
|
864
864
|
FROM (VALUES ${signatureValues.join(', ')}) AS v(fact_id, public_key_id, signature))
|
|
@@ -217,7 +217,7 @@ class QueryDescription {
|
|
|
217
217
|
return this.outputs.length;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
generateResultSqlQuery(): SpecificationSqlQuery {
|
|
220
|
+
generateResultSqlQuery(schema: string): SpecificationSqlQuery {
|
|
221
221
|
const columns = this.outputs
|
|
222
222
|
.map(output => `f${output.factIndex}.hash as hash${output.factIndex}, f${output.factIndex}.fact_id as id${output.factIndex}, f${output.factIndex}.data as data${output.factIndex}`)
|
|
223
223
|
.join(", ");
|
|
@@ -226,17 +226,17 @@ class QueryDescription {
|
|
|
226
226
|
const successorFact = this.inputs.find(i => i.factIndex === firstEdge.successorFactIndex);
|
|
227
227
|
const firstFactIndex = predecessorFact ? predecessorFact.factIndex : successorFact!.factIndex;
|
|
228
228
|
const writtenFactIndexes = new Set<number>().add(firstFactIndex);
|
|
229
|
-
const joins: string[] = generateJoins(this.edges, writtenFactIndexes);
|
|
229
|
+
const joins: string[] = generateJoins(this.edges, writtenFactIndexes, schema);
|
|
230
230
|
const inputWhereClauses = this.inputs
|
|
231
231
|
.map(input => `f${input.factIndex}.fact_type_id = $${input.factTypeParameter} AND f${input.factIndex}.hash = $${input.factHashParameter}`)
|
|
232
232
|
.join(" AND ");
|
|
233
233
|
const existentialWhereClauses = this.existentialConditions
|
|
234
|
-
.map(existentialCondition => ` AND ${existentialCondition.exists ? "EXISTS" : "NOT EXISTS"} (${generateExistentialWhereClause(existentialCondition, writtenFactIndexes)})`)
|
|
234
|
+
.map(existentialCondition => ` AND ${existentialCondition.exists ? "EXISTS" : "NOT EXISTS"} (${generateExistentialWhereClause(existentialCondition, writtenFactIndexes, schema)})`)
|
|
235
235
|
.join("");
|
|
236
236
|
const orderByClause = this.outputs
|
|
237
237
|
.map(output => `f${output.factIndex}.fact_id ASC`)
|
|
238
238
|
.join(", ");
|
|
239
|
-
const sql = `SELECT ${columns} FROM
|
|
239
|
+
const sql = `SELECT ${columns} FROM ${schema}.fact f${firstFactIndex}${joins.join("")} WHERE ${inputWhereClauses}${existentialWhereClauses} ORDER BY ${orderByClause}`;
|
|
240
240
|
return {
|
|
241
241
|
sql,
|
|
242
242
|
parameters: this.parameters,
|
|
@@ -322,13 +322,13 @@ function existentialsWithNewCondition(existentialConditions: ExistentialConditio
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
function generateJoins(edges: EdgeDescription[], writtenFactIndexes: Set<number
|
|
325
|
+
function generateJoins(edges: EdgeDescription[], writtenFactIndexes: Set<number>, schema: string) {
|
|
326
326
|
const joins: string[] = [];
|
|
327
327
|
edges.forEach(edge => {
|
|
328
328
|
if (writtenFactIndexes.has(edge.predecessorFactIndex)) {
|
|
329
329
|
if (writtenFactIndexes.has(edge.successorFactIndex)) {
|
|
330
330
|
joins.push(
|
|
331
|
-
` JOIN
|
|
331
|
+
` JOIN ${schema}.edge e${edge.edgeIndex}` +
|
|
332
332
|
` ON e${edge.edgeIndex}.predecessor_fact_id = f${edge.predecessorFactIndex}.fact_id` +
|
|
333
333
|
` AND e${edge.edgeIndex}.successor_fact_id = f${edge.successorFactIndex}.fact_id` +
|
|
334
334
|
` AND e${edge.edgeIndex}.role_id = $${edge.roleParameter}`
|
|
@@ -336,12 +336,12 @@ function generateJoins(edges: EdgeDescription[], writtenFactIndexes: Set<number>
|
|
|
336
336
|
}
|
|
337
337
|
else {
|
|
338
338
|
joins.push(
|
|
339
|
-
` JOIN
|
|
339
|
+
` JOIN ${schema}.edge e${edge.edgeIndex}` +
|
|
340
340
|
` ON e${edge.edgeIndex}.predecessor_fact_id = f${edge.predecessorFactIndex}.fact_id` +
|
|
341
341
|
` AND e${edge.edgeIndex}.role_id = $${edge.roleParameter}`
|
|
342
342
|
);
|
|
343
343
|
joins.push(
|
|
344
|
-
` JOIN
|
|
344
|
+
` JOIN ${schema}.fact f${edge.successorFactIndex}` +
|
|
345
345
|
` ON f${edge.successorFactIndex}.fact_id = e${edge.edgeIndex}.successor_fact_id`
|
|
346
346
|
);
|
|
347
347
|
writtenFactIndexes.add(edge.successorFactIndex);
|
|
@@ -349,12 +349,12 @@ function generateJoins(edges: EdgeDescription[], writtenFactIndexes: Set<number>
|
|
|
349
349
|
}
|
|
350
350
|
else if (writtenFactIndexes.has(edge.successorFactIndex)) {
|
|
351
351
|
joins.push(
|
|
352
|
-
` JOIN
|
|
352
|
+
` JOIN ${schema}.edge e${edge.edgeIndex}` +
|
|
353
353
|
` ON e${edge.edgeIndex}.successor_fact_id = f${edge.successorFactIndex}.fact_id` +
|
|
354
354
|
` AND e${edge.edgeIndex}.role_id = $${edge.roleParameter}`
|
|
355
355
|
);
|
|
356
356
|
joins.push(
|
|
357
|
-
` JOIN
|
|
357
|
+
` JOIN ${schema}.fact f${edge.predecessorFactIndex}` +
|
|
358
358
|
` ON f${edge.predecessorFactIndex}.fact_id = e${edge.edgeIndex}.predecessor_fact_id`
|
|
359
359
|
);
|
|
360
360
|
writtenFactIndexes.add(edge.predecessorFactIndex);
|
|
@@ -366,7 +366,7 @@ function generateJoins(edges: EdgeDescription[], writtenFactIndexes: Set<number>
|
|
|
366
366
|
return joins;
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
function generateExistentialWhereClause(existentialCondition: ExistentialConditionDescription, outerFactIndexes: Set<number
|
|
369
|
+
function generateExistentialWhereClause(existentialCondition: ExistentialConditionDescription, outerFactIndexes: Set<number>, schema: string): string {
|
|
370
370
|
const firstEdge = existentialCondition.edges[0];
|
|
371
371
|
const writtenFactIndexes = new Set<number>(outerFactIndexes);
|
|
372
372
|
const firstJoin: string[] = [];
|
|
@@ -381,7 +381,7 @@ function generateExistentialWhereClause(existentialCondition: ExistentialConditi
|
|
|
381
381
|
` AND e${firstEdge.edgeIndex}.role_id = $${firstEdge.roleParameter}`
|
|
382
382
|
);
|
|
383
383
|
firstJoin.push(
|
|
384
|
-
` JOIN
|
|
384
|
+
` JOIN ${schema}.fact f${firstEdge.successorFactIndex}` +
|
|
385
385
|
` ON f${firstEdge.successorFactIndex}.fact_id = e${firstEdge.edgeIndex}.successor_fact_id`
|
|
386
386
|
);
|
|
387
387
|
writtenFactIndexes.add(firstEdge.successorFactIndex);
|
|
@@ -393,7 +393,7 @@ function generateExistentialWhereClause(existentialCondition: ExistentialConditi
|
|
|
393
393
|
` AND e${firstEdge.edgeIndex}.role_id = $${firstEdge.roleParameter}`
|
|
394
394
|
);
|
|
395
395
|
firstJoin.push(
|
|
396
|
-
` JOIN
|
|
396
|
+
` JOIN ${schema}.fact f${firstEdge.predecessorFactIndex}` +
|
|
397
397
|
` ON f${firstEdge.predecessorFactIndex}.fact_id = e${firstEdge.edgeIndex}.predecessor_fact_id`
|
|
398
398
|
);
|
|
399
399
|
writtenFactIndexes.add(firstEdge.predecessorFactIndex);
|
|
@@ -401,15 +401,15 @@ function generateExistentialWhereClause(existentialCondition: ExistentialConditi
|
|
|
401
401
|
else {
|
|
402
402
|
throw new Error("Neither predecessor nor successor fact has been written");
|
|
403
403
|
}
|
|
404
|
-
const tailJoins: string[] = generateJoins(existentialCondition.edges.slice(1), writtenFactIndexes);
|
|
404
|
+
const tailJoins: string[] = generateJoins(existentialCondition.edges.slice(1), writtenFactIndexes, schema);
|
|
405
405
|
const joins = firstJoin.concat(tailJoins);
|
|
406
406
|
const inputWhereClauses = existentialCondition.inputs
|
|
407
407
|
.map(input => ` AND f${input.factIndex}.fact_type_id = $${input.factTypeParameter} AND f${input.factIndex}.hash = $${input.factHashParameter}`)
|
|
408
408
|
.join("");
|
|
409
409
|
const existentialWhereClauses = existentialCondition.existentialConditions
|
|
410
|
-
.map(e => ` AND ${e.exists ? "EXISTS" : "NOT EXISTS"} (${generateExistentialWhereClause(e, writtenFactIndexes)})`)
|
|
410
|
+
.map(e => ` AND ${e.exists ? "EXISTS" : "NOT EXISTS"} (${generateExistentialWhereClause(e, writtenFactIndexes, schema)})`)
|
|
411
411
|
.join("");
|
|
412
|
-
return `SELECT 1 FROM
|
|
412
|
+
return `SELECT 1 FROM ${schema}.edge e${firstEdge.edgeIndex}${joins.join("")} WHERE ${whereClause.join(" AND ")}${inputWhereClauses}${existentialWhereClauses}`;
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
type FactByLabel = {
|
|
@@ -868,24 +868,24 @@ function idsEqual(a: number[], b: number[]) {
|
|
|
868
868
|
return a.every((value, index) => value === b[index]);
|
|
869
869
|
}
|
|
870
870
|
|
|
871
|
-
export function resultSqlFromSpecification(start: FactReference[], specification: Specification, factTypes: FactTypeMap, roleMap: RoleMap): ResultComposer | null {
|
|
871
|
+
export function resultSqlFromSpecification(start: FactReference[], specification: Specification, factTypes: FactTypeMap, roleMap: RoleMap, schema: string): ResultComposer | null {
|
|
872
872
|
const descriptionBuilder = new ResultDescriptionBuilder(factTypes, roleMap);
|
|
873
873
|
const description = descriptionBuilder.buildDescription(start, specification);
|
|
874
874
|
|
|
875
875
|
if (!description.queryDescription.isSatisfiable()) {
|
|
876
876
|
return null;
|
|
877
877
|
}
|
|
878
|
-
return createResultComposer(description, 0);
|
|
878
|
+
return createResultComposer(description, 0, schema);
|
|
879
879
|
}
|
|
880
880
|
|
|
881
|
-
function createResultComposer(description: ResultDescription, parentFactIdLength: number): ResultComposer {
|
|
882
|
-
const sqlQuery = description.queryDescription.generateResultSqlQuery();
|
|
881
|
+
function createResultComposer(description: ResultDescription, parentFactIdLength: number, schema: string): ResultComposer {
|
|
882
|
+
const sqlQuery = description.queryDescription.generateResultSqlQuery(schema);
|
|
883
883
|
const resultProjection = description.resultProjection;
|
|
884
884
|
const childResultComposers = description.childResultDescriptions
|
|
885
885
|
.filter(child => child.queryDescription.isSatisfiable())
|
|
886
886
|
.map(child => ({
|
|
887
887
|
name: child.name,
|
|
888
|
-
resultComposer: createResultComposer(child, description.queryDescription.outputLength())
|
|
888
|
+
resultComposer: createResultComposer(child, description.queryDescription.outputLength(), schema)
|
|
889
889
|
}));
|
|
890
890
|
return new ResultComposer(sqlQuery, resultProjection, parentFactIdLength, childResultComposers);
|
|
891
891
|
}
|