jinaga-server 2.1.8 → 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.
@@ -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
- 'FROM public.fact f ' +
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
- 'FROM public.fact f ' +
419
- 'JOIN public.fact_type t ' +
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
- 'FROM public.fact f1 ' +
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
- 'JOIN public.ancestor a ' +
428
+ `JOIN ${this.schema}.ancestor a ` +
429
429
  ' ON a.fact_id = f1.fact_id ' +
430
- 'JOIN public.fact f2 ' +
430
+ `JOIN ${this.schema}.fact f2 ` +
431
431
  ' ON f2.fact_id = a.ancestor_fact_id ' +
432
- 'JOIN public.fact_type t ' +
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 = 'INSERT INTO public.fact_type (name) VALUES ' + values.join(', ') +
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 = 'SELECT name, fact_type_id FROM public.fact_type WHERE name=ANY($1);';
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 = 'INSERT INTO public.role (name, defining_fact_type_id) VALUES ' +
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
- ' FROM public.role' +
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
- ' FROM public.fact' +
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: 'INSERT INTO public.fact (hash, fact_type_id, data) VALUES ' +
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 public.fact (hash, fact_type_id, data)
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 public.edge
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 public.fact
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 public.fact
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 public.ancestor
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 public.ancestor
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 = 'SELECT public_key, public_key_id FROM public.public_key WHERE public_key=ANY($1);';
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 = 'INSERT INTO public.public_key (public_key) VALUES ' + values.join(', ') +
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 public.signature
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 public.fact f${firstFactIndex}${joins.join("")} WHERE ${inputWhereClauses}${existentialWhereClauses} ORDER BY ${orderByClause}`;
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 public.edge e${edge.edgeIndex}` +
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 public.edge e${edge.edgeIndex}` +
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 public.fact f${edge.successorFactIndex}` +
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 public.edge e${edge.edgeIndex}` +
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 public.fact f${edge.predecessorFactIndex}` +
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>): string {
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 public.fact f${firstEdge.successorFactIndex}` +
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 public.fact f${firstEdge.predecessorFactIndex}` +
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 public.edge e${firstEdge.edgeIndex}${joins.join("")} WHERE ${whereClause.join(" AND ")}${inputWhereClauses}${existentialWhereClauses}`;
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
  }