jinaga-server 2.1.8 → 2.3.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/authorization/authorization-keystore.d.ts +2 -2
- package/dist/authorization/authorization-keystore.js +10 -10
- package/dist/authorization/authorization-keystore.js.map +1 -1
- package/dist/jinaga-server.d.ts +2 -2
- package/dist/jinaga-server.js +17 -29
- 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 +4 -1
- package/dist/postgres/postgres-store.js +60 -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/authorization/authorization-keystore.ts +11 -11
- package/src/jinaga-server.ts +26 -40
- package/src/postgres/postgres-keystore.ts +4 -4
- package/src/postgres/postgres-store.ts +61 -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
- package/dist/http/node-http.d.ts +0 -7
- package/dist/http/node-http.js +0 -135
- package/dist/http/node-http.js.map +0 -1
- package/src/http/node-http.ts +0 -115
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jinaga-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Application-agnostic back end for web applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"express": "^4.18.1",
|
|
46
|
-
"jinaga": "^5.
|
|
46
|
+
"jinaga": "^5.3.0",
|
|
47
47
|
"node-forge": "^1.3.1",
|
|
48
48
|
"passport": "^0.6.0",
|
|
49
49
|
"pg": "^8.7.1"
|
|
@@ -19,12 +19,12 @@ export class AuthorizationKeystore implements Authorization {
|
|
|
19
19
|
private authorizationEngine: AuthorizationEngine | null;
|
|
20
20
|
|
|
21
21
|
constructor(
|
|
22
|
-
private
|
|
22
|
+
private store: Storage,
|
|
23
23
|
private keystore: Keystore,
|
|
24
|
-
authorizationRules: AuthorizationRules | null
|
|
25
|
-
|
|
24
|
+
authorizationRules: AuthorizationRules | null
|
|
25
|
+
) {
|
|
26
26
|
this.authorizationEngine = authorizationRules &&
|
|
27
|
-
new AuthorizationEngine(authorizationRules,
|
|
27
|
+
new AuthorizationEngine(authorizationRules, store);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
async getOrCreateUserFact(userIdentity: UserIdentity) {
|
|
@@ -35,29 +35,29 @@ export class AuthorizationKeystore implements Authorization {
|
|
|
35
35
|
signatures: []
|
|
36
36
|
}
|
|
37
37
|
];
|
|
38
|
-
await this.
|
|
38
|
+
await this.store.save(envelopes);
|
|
39
39
|
return userFact;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
query(userIdentity: UserIdentity, start: FactReference, query: Query) {
|
|
43
|
-
return this.
|
|
43
|
+
return this.store.query(start, query);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
read(userIdentity: UserIdentity, start: FactReference[], specification: Specification) {
|
|
47
|
-
return this.
|
|
47
|
+
return this.store.read(start, specification);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
feed(userIdentity: UserIdentity, feed: Feed, bookmark: string): Promise<FactFeed> {
|
|
51
|
-
return this.
|
|
51
|
+
return this.store.feed(feed, bookmark);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
load(userIdentity: UserIdentity, references: FactReference[]) {
|
|
55
|
-
return this.
|
|
55
|
+
return this.store.load(references);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
async save(userIdentity: UserIdentity | null, facts: FactRecord[]) {
|
|
59
59
|
if (!this.authorizationEngine) {
|
|
60
|
-
const envelopes = await this.
|
|
60
|
+
const envelopes = await this.store.save(facts.map(fact => ({
|
|
61
61
|
fact,
|
|
62
62
|
signatures: []
|
|
63
63
|
})));
|
|
@@ -68,7 +68,7 @@ export class AuthorizationKeystore implements Authorization {
|
|
|
68
68
|
const authorizedFacts = await this.authorizationEngine.authorizeFacts(facts, userFact);
|
|
69
69
|
if (userIdentity) {
|
|
70
70
|
const signedFacts = await this.keystore.signFacts(userIdentity, authorizedFacts);
|
|
71
|
-
const envelopes = await this.
|
|
71
|
+
const envelopes = await this.store.save(signedFacts);
|
|
72
72
|
return envelopes.map(envelope => envelope.fact);
|
|
73
73
|
}
|
|
74
74
|
else {
|
package/src/jinaga-server.ts
CHANGED
|
@@ -5,9 +5,7 @@ import {
|
|
|
5
5
|
AuthorizationNoOp,
|
|
6
6
|
AuthorizationRules,
|
|
7
7
|
FactManager,
|
|
8
|
-
Fork,
|
|
9
|
-
HttpNetwork,
|
|
10
|
-
Jinaga,
|
|
8
|
+
Fork, Jinaga,
|
|
11
9
|
MemoryStore,
|
|
12
10
|
Model,
|
|
13
11
|
Network,
|
|
@@ -17,17 +15,13 @@ import {
|
|
|
17
15
|
PassThroughFork,
|
|
18
16
|
Storage,
|
|
19
17
|
SyncStatusNotifier,
|
|
20
|
-
Trace,
|
|
21
|
-
TransientFork,
|
|
22
|
-
UserIdentity,
|
|
23
|
-
WebClient
|
|
18
|
+
Trace, UserIdentity
|
|
24
19
|
} from "jinaga";
|
|
25
20
|
import { Pool } from "pg";
|
|
26
21
|
|
|
27
22
|
import { AuthenticationDevice } from "./authentication/authentication-device";
|
|
28
23
|
import { AuthenticationSession } from "./authentication/authentication-session";
|
|
29
24
|
import { AuthorizationKeystore } from "./authorization/authorization-keystore";
|
|
30
|
-
import { NodeHttpConnection } from "./http/node-http";
|
|
31
25
|
import { HttpRouter, RequestUser } from "./http/router";
|
|
32
26
|
import { Keystore } from "./keystore";
|
|
33
27
|
import { MemoryFeedCache } from "./memory/memory-feed-cache";
|
|
@@ -37,11 +31,11 @@ import { PostgresStore } from "./postgres/postgres-store";
|
|
|
37
31
|
|
|
38
32
|
export type JinagaServerConfig = {
|
|
39
33
|
pgStore?: string | Pool,
|
|
34
|
+
pgStoreSchema?: string,
|
|
40
35
|
pgKeystore?: string | Pool,
|
|
41
|
-
|
|
36
|
+
pgKeystoreSchema?: string,
|
|
42
37
|
model?: Model,
|
|
43
|
-
authorization?: (a: AuthorizationRules) => AuthorizationRules
|
|
44
|
-
httpTimeoutSeconds?: number
|
|
38
|
+
authorization?: (a: AuthorizationRules) => AuthorizationRules
|
|
45
39
|
};
|
|
46
40
|
|
|
47
41
|
export type JinagaServerInstance = {
|
|
@@ -62,14 +56,14 @@ export class JinagaServer {
|
|
|
62
56
|
const pools: { [uri: string]: Pool } = {};
|
|
63
57
|
const store = createStore(config, pools);
|
|
64
58
|
const source = new ObservableSourceImpl(store);
|
|
65
|
-
const fork =
|
|
59
|
+
const fork = new PassThroughFork(store);
|
|
66
60
|
const keystore = createKeystore(config, pools);
|
|
67
61
|
const authorizationRules = config.authorization ? config.authorization(new AuthorizationRules(config.model)) : null;
|
|
68
62
|
const authorization = createAuthorization(authorizationRules, store, keystore);
|
|
69
63
|
const feedCache = new MemoryFeedCache();
|
|
70
64
|
const router = new HttpRouter(authorization, feedCache);
|
|
71
65
|
const authentication = createAuthentication(store, keystore, authorizationRules);
|
|
72
|
-
const network =
|
|
66
|
+
const network = new NetworkNoOp();
|
|
73
67
|
const factManager = new FactManager(authentication, fork, source, store, network);
|
|
74
68
|
const j: Jinaga = new Jinaga(factManager, syncStatusNotifier);
|
|
75
69
|
|
|
@@ -92,7 +86,7 @@ export class JinagaServer {
|
|
|
92
86
|
function createStore(config: JinagaServerConfig, pools: { [uri: string]: Pool }): Storage {
|
|
93
87
|
if (config.pgStore) {
|
|
94
88
|
const pool = getPool(config.pgStore, pools);
|
|
95
|
-
const store = new PostgresStore(pool);
|
|
89
|
+
const store = new PostgresStore(pool, validateSchema(config.pgStoreSchema));
|
|
96
90
|
return store;
|
|
97
91
|
}
|
|
98
92
|
else {
|
|
@@ -101,25 +95,14 @@ function createStore(config: JinagaServerConfig, pools: { [uri: string]: Pool })
|
|
|
101
95
|
}
|
|
102
96
|
|
|
103
97
|
function createFork(config: JinagaServerConfig, store: Storage, syncStatusNotifier: SyncStatusNotifier): Fork {
|
|
104
|
-
|
|
105
|
-
const httpConnection = new NodeHttpConnection(config.httpEndpoint);
|
|
106
|
-
const httpTimeoutSeconds = config.httpTimeoutSeconds || 5;
|
|
107
|
-
const webClient = new WebClient(httpConnection, syncStatusNotifier, {
|
|
108
|
-
timeoutSeconds: httpTimeoutSeconds
|
|
109
|
-
});
|
|
110
|
-
const fork = new TransientFork(store, webClient);
|
|
111
|
-
return fork;
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
return new PassThroughFork(store);
|
|
115
|
-
}
|
|
98
|
+
return new PassThroughFork(store);
|
|
116
99
|
}
|
|
117
100
|
|
|
118
101
|
function createKeystore(config: JinagaServerConfig, pools: { [uri: string]: Pool }): Keystore | null {
|
|
119
102
|
const uriOrPool = config.pgKeystore;
|
|
120
103
|
if (uriOrPool) {
|
|
121
104
|
const pool = getPool(uriOrPool, pools);
|
|
122
|
-
const keystore = new PostgresKeystore(pool);
|
|
105
|
+
const keystore = new PostgresKeystore(pool, validateSchema(config.pgKeystoreSchema));
|
|
123
106
|
return keystore;
|
|
124
107
|
}
|
|
125
108
|
else {
|
|
@@ -142,18 +125,7 @@ function createAuthentication(store: Storage, keystore: Keystore | null, authori
|
|
|
142
125
|
}
|
|
143
126
|
|
|
144
127
|
function createNetwork(config: JinagaServerConfig): Network {
|
|
145
|
-
|
|
146
|
-
const httpConnection = new NodeHttpConnection(config.httpEndpoint);
|
|
147
|
-
const httpTimeoutSeconds = config.httpTimeoutSeconds || 5;
|
|
148
|
-
const syncStatusNotifier = new SyncStatusNotifier();
|
|
149
|
-
const webClient = new WebClient(httpConnection, syncStatusNotifier, {
|
|
150
|
-
timeoutSeconds: httpTimeoutSeconds
|
|
151
|
-
});
|
|
152
|
-
return new HttpNetwork(webClient);
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
return new NetworkNoOp();
|
|
156
|
-
}
|
|
128
|
+
return new NetworkNoOp();
|
|
157
129
|
}
|
|
158
130
|
|
|
159
131
|
function getPool(uriOrPool: string | Pool, pools: { [uri: string]: Pool; }): Pool {
|
|
@@ -222,4 +194,18 @@ async function withSession(store: Storage, keystore: Keystore | null, authorizat
|
|
|
222
194
|
const factManager = new FactManager(authentication, fork, observableSource, store, network);
|
|
223
195
|
const j = new Jinaga(factManager, syncStatusNotifier);
|
|
224
196
|
await callback(j);
|
|
225
|
-
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function validateSchema(schema: string | undefined): string {
|
|
200
|
+
if (!schema) {
|
|
201
|
+
return "public";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Verify that the schema is a valid Postgres schema name.
|
|
205
|
+
// https://www.postgresql.org/docs/9.1/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
|
|
206
|
+
if (!/^[a-z_][a-z0-9_$]*$/.test(schema)) {
|
|
207
|
+
throw new Error(`Invalid schema name: ${schema}. Schema names must start with a letter or underscore, and contain only letters, numbers, and underscores.`);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return schema;
|
|
211
|
+
}
|
|
@@ -14,7 +14,7 @@ export class PostgresKeystore implements Keystore {
|
|
|
14
14
|
private connectionFactory: ConnectionFactory;
|
|
15
15
|
private cache: Map<string, KeyPair> = new Map();
|
|
16
16
|
|
|
17
|
-
constructor (pool: Pool) {
|
|
17
|
+
constructor (pool: Pool, private schema: string) {
|
|
18
18
|
this.connectionFactory = new ConnectionFactory(pool);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -77,7 +77,7 @@ export class PostgresKeystore implements Keystore {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
private async selectKeyPair(connection: PoolClient, userIdentity: UserIdentity): Promise<KeyPair> {
|
|
80
|
-
const { rows } = await connection.query(
|
|
80
|
+
const { rows } = await connection.query(`SELECT public_key, private_key FROM ${this.schema}.user WHERE provider = $1 AND user_identifier = $2`,
|
|
81
81
|
[userIdentity.provider, userIdentity.id]);
|
|
82
82
|
if (rows.length > 1) {
|
|
83
83
|
throw new Error('Duplicate entries found in the keystore');
|
|
@@ -104,7 +104,7 @@ export class PostgresKeystore implements Keystore {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
private async selectOrInsertKeyPair(connection: PoolClient, userIdentity: UserIdentity): Promise<KeyPair> {
|
|
107
|
-
const { rows } = await connection.query(
|
|
107
|
+
const { rows } = await connection.query(`SELECT public_key, private_key FROM ${this.schema}.user WHERE provider = $1 AND user_identifier = $2`,
|
|
108
108
|
[userIdentity.provider, userIdentity.id]);
|
|
109
109
|
if (rows.length > 1) {
|
|
110
110
|
throw new Error('Duplicate entries found in the keystore');
|
|
@@ -124,7 +124,7 @@ export class PostgresKeystore implements Keystore {
|
|
|
124
124
|
const keypair = pki.rsa.generateKeyPair({ bits: 2048 });
|
|
125
125
|
const privatePem = pki.privateKeyToPem(keypair.privateKey);
|
|
126
126
|
const publicPem = pki.publicKeyToPem(keypair.publicKey);
|
|
127
|
-
await connection.query(
|
|
127
|
+
await connection.query(`INSERT INTO ${this.schema}.user (provider, user_identifier, private_key, public_key) VALUES ($1, $2, $3, $4)`,
|
|
128
128
|
[userIdentity.provider, userIdentity.id, privatePem, publicPem]);
|
|
129
129
|
return { publicPem, privatePem };
|
|
130
130
|
}
|
|
@@ -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;
|
|
@@ -476,6 +476,14 @@ export class PostgresStore implements Storage {
|
|
|
476
476
|
saveBookmark(feed: string, bookmark: string): Promise<void> {
|
|
477
477
|
throw new Error("Method not implemented.");
|
|
478
478
|
}
|
|
479
|
+
|
|
480
|
+
getMruDate(specificationHash: string): Promise<Date | null> {
|
|
481
|
+
throw new Error("Method not implemented.");
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
setMruDate(specificationHash: string, mruDate: Date): Promise<void> {
|
|
485
|
+
throw new Error("Method not implemented.");
|
|
486
|
+
}
|
|
479
487
|
}
|
|
480
488
|
|
|
481
489
|
async function executeQueryTree(sqlQueryTree: SqlQueryTree, connection: PoolClient): Promise<ResultSetTree> {
|
|
@@ -506,7 +514,7 @@ function predecessorCollectionTypes(predecessors: PredecessorCollection): string
|
|
|
506
514
|
return Object.keys(predecessors).flatMap(key => predecessorTypes(predecessors[key]));
|
|
507
515
|
}
|
|
508
516
|
|
|
509
|
-
async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient) {
|
|
517
|
+
async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient, schema: string) {
|
|
510
518
|
const newFactTypes = facts
|
|
511
519
|
.flatMap(fact => [fact.type, ...predecessorCollectionTypes(fact.predecessors)])
|
|
512
520
|
.filter(type => !factTypes.has(type))
|
|
@@ -516,7 +524,7 @@ async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, conne
|
|
|
516
524
|
}
|
|
517
525
|
|
|
518
526
|
// Look up existing fact types
|
|
519
|
-
const loadedFactTypes = await loadFactTypes(newFactTypes, connection);
|
|
527
|
+
const loadedFactTypes = await loadFactTypes(newFactTypes, connection, schema);
|
|
520
528
|
const remainingNames = newFactTypes.filter(type => !loadedFactTypes.has(type));
|
|
521
529
|
if (remainingNames.length === 0) {
|
|
522
530
|
return mergeFactTypes(loadedFactTypes, factTypes);
|
|
@@ -524,7 +532,7 @@ async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, conne
|
|
|
524
532
|
|
|
525
533
|
// Insert new fact types
|
|
526
534
|
const values = remainingNames.map((name, index) => `($${index + 1})`);
|
|
527
|
-
const insertSql =
|
|
535
|
+
const insertSql = `INSERT INTO ${schema}.fact_type (name) VALUES ` + values.join(', ') +
|
|
528
536
|
' RETURNING fact_type_id, name;';
|
|
529
537
|
const { rows: newRows }: FactTypeResult = await connection.query(insertSql, remainingNames);
|
|
530
538
|
if (newRows.length !== remainingNames.length) {
|
|
@@ -537,8 +545,8 @@ async function storeFactTypes(facts: FactRecord[], factTypes: FactTypeMap, conne
|
|
|
537
545
|
return allFactTypes;
|
|
538
546
|
}
|
|
539
547
|
|
|
540
|
-
async function loadFactTypes(factTypeNames: string[], connection: PoolClient) {
|
|
541
|
-
const lookUpSql =
|
|
548
|
+
async function loadFactTypes(factTypeNames: string[], connection: PoolClient, schema: string) {
|
|
549
|
+
const lookUpSql = `SELECT name, fact_type_id FROM ${schema}.fact_type WHERE name=ANY($1);`;
|
|
542
550
|
const { rows: existingRows }: FactTypeResult = await connection.query(lookUpSql, [factTypeNames]);
|
|
543
551
|
const factTypeIds = existingRows.reduce(
|
|
544
552
|
(map, row) => addFactType(map, row.name, row.fact_type_id),
|
|
@@ -547,7 +555,7 @@ async function loadFactTypes(factTypeNames: string[], connection: PoolClient) {
|
|
|
547
555
|
return factTypeIds;
|
|
548
556
|
}
|
|
549
557
|
|
|
550
|
-
async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap: RoleMap, connection: PoolClient) {
|
|
558
|
+
async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap: RoleMap, connection: PoolClient, schema: string) {
|
|
551
559
|
// Find distinct roles
|
|
552
560
|
const roles = flatten(facts, fact => {
|
|
553
561
|
const successor_type_id = ensureGetFactTypeId(factTypes, fact.type);
|
|
@@ -562,7 +570,7 @@ async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap:
|
|
|
562
570
|
|
|
563
571
|
if (roles.length > 0) {
|
|
564
572
|
// Look up existing roles
|
|
565
|
-
const roleIds = await loadRoles(roles, roleMap, connection);
|
|
573
|
+
const roleIds = await loadRoles(roles, roleMap, connection, schema);
|
|
566
574
|
const remainingRoles = roles.filter(role => !hasRole(
|
|
567
575
|
roleIds, role.successor_type_id, role.role));
|
|
568
576
|
if (remainingRoles.length === 0) {
|
|
@@ -572,7 +580,7 @@ async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap:
|
|
|
572
580
|
// Insert new roles
|
|
573
581
|
const remainingRoleValues = remainingRoles.map((role, index) =>
|
|
574
582
|
`($${index * 2 + 1}, $${index * 2 + 2}::integer)`);
|
|
575
|
-
const insertSql =
|
|
583
|
+
const insertSql = `INSERT INTO ${schema}.role (name, defining_fact_type_id) VALUES ` +
|
|
576
584
|
remainingRoleValues.join(', ') +
|
|
577
585
|
' RETURNING role_id, name, defining_fact_type_id;';
|
|
578
586
|
const remainingRoleParameters = flatten(remainingRoles, (role) => [
|
|
@@ -594,7 +602,7 @@ async function storeRoles(facts: FactRecord[], factTypes: FactTypeMap, roleMap:
|
|
|
594
602
|
}
|
|
595
603
|
}
|
|
596
604
|
|
|
597
|
-
async function loadRoles(roles: { role: string; successor_type_id: number; }[], roleMap: RoleMap, connection: PoolClient) {
|
|
605
|
+
async function loadRoles(roles: { role: string; successor_type_id: number; }[], roleMap: RoleMap, connection: PoolClient, schema: string) {
|
|
598
606
|
const roleValues = roles.map((role, index) =>
|
|
599
607
|
`($${index * 2 + 1}, $${index * 2 + 2}::integer)`);
|
|
600
608
|
const roleParameters = flatten(roles, (role) => [
|
|
@@ -603,7 +611,7 @@ async function loadRoles(roles: { role: string; successor_type_id: number; }[],
|
|
|
603
611
|
]);
|
|
604
612
|
|
|
605
613
|
const lookUpSql = 'SELECT role.name, role.defining_fact_type_id, role.role_id' +
|
|
606
|
-
|
|
614
|
+
` FROM ${schema}.role` +
|
|
607
615
|
' JOIN (VALUES ' + roleValues.join(', ') + ') AS v (name, defining_fact_type_id)' +
|
|
608
616
|
' ON v.name = role.name AND v.defining_fact_type_id = role.defining_fact_type_id;';
|
|
609
617
|
const { rows }: RoleResult = await connection.query(lookUpSql, roleParameters);
|
|
@@ -614,7 +622,7 @@ async function loadRoles(roles: { role: string; successor_type_id: number; }[],
|
|
|
614
622
|
return roleIds;
|
|
615
623
|
}
|
|
616
624
|
|
|
617
|
-
async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient) {
|
|
625
|
+
async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, connection: PoolClient, schema: string) {
|
|
618
626
|
if (facts.length > 0) {
|
|
619
627
|
const factReferences: FactReference[] = facts.flatMap(fact => [
|
|
620
628
|
...predecessorsOf(fact),
|
|
@@ -626,7 +634,7 @@ async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, co
|
|
|
626
634
|
[f.hash, factTypes.get(f.type)]);
|
|
627
635
|
|
|
628
636
|
const sql = 'SELECT fact_id, fact.fact_type_id, fact.hash' +
|
|
629
|
-
|
|
637
|
+
` FROM ${schema}.fact` +
|
|
630
638
|
' JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id)' +
|
|
631
639
|
' ON v.fact_type_id = fact.fact_type_id AND v.hash = fact.hash;';
|
|
632
640
|
const { rows }: FactResult = await connection.query(sql, factParameters);
|
|
@@ -641,12 +649,12 @@ async function findExistingFacts(facts: FactRecord[], factTypes: FactTypeMap, co
|
|
|
641
649
|
}
|
|
642
650
|
}
|
|
643
651
|
|
|
644
|
-
async function insertFactsEdgesAndAncestors(facts: FactRecord[], factTypes: FactTypeMap, existingFacts: Map<string, Map<number, number>>, connection: PoolClient, roles: RoleMap) {
|
|
652
|
+
async function insertFactsEdgesAndAncestors(facts: FactRecord[], factTypes: FactTypeMap, existingFacts: Map<string, Map<number, number>>, connection: PoolClient, roles: RoleMap, schema: string) {
|
|
645
653
|
if (facts.length === 0) {
|
|
646
654
|
return emptyFactMap();
|
|
647
655
|
}
|
|
648
656
|
|
|
649
|
-
const { sql, parameters } = sqlInsertFacts(facts, roles, factTypes);
|
|
657
|
+
const { sql, parameters } = sqlInsertFacts(facts, roles, factTypes, schema);
|
|
650
658
|
|
|
651
659
|
const { rows }: FactResult = await connection.query(sql, parameters);
|
|
652
660
|
if (rows.length !== facts.length) {
|
|
@@ -659,7 +667,7 @@ async function insertFactsEdgesAndAncestors(facts: FactRecord[], factTypes: Fact
|
|
|
659
667
|
return allFacts;
|
|
660
668
|
}
|
|
661
669
|
|
|
662
|
-
function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactTypeMap) {
|
|
670
|
+
function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactTypeMap, schema: string) {
|
|
663
671
|
const factValues = facts.map((f, i) => `(\$${i * 3 + 1}, \$${i * 3 + 2}::integer, \$${i * 3 + 3}::jsonb)`);
|
|
664
672
|
const factParameters = flatten(facts, (f) => [f.hash, ensureGetFactTypeId(factTypes, f.type), {
|
|
665
673
|
fields: f.fields,
|
|
@@ -668,11 +676,11 @@ function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactType
|
|
|
668
676
|
|
|
669
677
|
const edgeRecords = flatten(facts, fact => makeEdgeRecords(fact));
|
|
670
678
|
if (edgeRecords.length > 0) {
|
|
671
|
-
return sqlInsertFactsEdgesAndAncestors(facts, factParameters, edgeRecords, factTypes, roles, factValues);
|
|
679
|
+
return sqlInsertFactsEdgesAndAncestors(facts, factParameters, edgeRecords, factTypes, roles, factValues, schema);
|
|
672
680
|
}
|
|
673
681
|
else {
|
|
674
682
|
return {
|
|
675
|
-
sql:
|
|
683
|
+
sql: `INSERT INTO ${schema}.fact (hash, fact_type_id, data) VALUES ` +
|
|
676
684
|
factValues.join(', ') +
|
|
677
685
|
' RETURNING fact_id, hash, fact_type_id;',
|
|
678
686
|
parameters: factParameters
|
|
@@ -680,7 +688,7 @@ function sqlInsertFacts(facts: FactRecord[], roles: RoleMap, factTypes: FactType
|
|
|
680
688
|
}
|
|
681
689
|
}
|
|
682
690
|
|
|
683
|
-
function sqlInsertFactsEdgesAndAncestors(facts: FactRecord[], factParameters: (string | number | { fields: {}; predecessors: PredecessorCollection; })[], edgeRecords: EdgeRecord[], factTypes: FactTypeMap, roles: RoleMap, factValues: string[]) {
|
|
691
|
+
function sqlInsertFactsEdgesAndAncestors(facts: FactRecord[], factParameters: (string | number | { fields: {}; predecessors: PredecessorCollection; })[], edgeRecords: EdgeRecord[], factTypes: FactTypeMap, roles: RoleMap, factValues: string[], schema: string) {
|
|
684
692
|
let parameterOffset = factParameters.length;
|
|
685
693
|
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
694
|
const edgeParameters = flatten(edgeRecords, (e) => {
|
|
@@ -722,13 +730,13 @@ new_ancestor AS (
|
|
|
722
730
|
AS ev (hash, fact_type_id, ancestor_hash, ancestor_fact_type_id)
|
|
723
731
|
),
|
|
724
732
|
inserted_fact AS (
|
|
725
|
-
INSERT INTO
|
|
733
|
+
INSERT INTO ${schema}.fact (hash, fact_type_id, data)
|
|
726
734
|
SELECT hash, fact_type_id, data
|
|
727
735
|
FROM new_fact
|
|
728
736
|
RETURNING fact_id, fact_type_id, hash
|
|
729
737
|
),
|
|
730
738
|
inserted_edge AS (
|
|
731
|
-
INSERT INTO
|
|
739
|
+
INSERT INTO ${schema}.edge
|
|
732
740
|
(role_id, successor_fact_id, predecessor_fact_id)
|
|
733
741
|
SELECT
|
|
734
742
|
new_edge.role_id,
|
|
@@ -743,7 +751,7 @@ inserted_edge AS (
|
|
|
743
751
|
FROM inserted_fact
|
|
744
752
|
UNION ALL
|
|
745
753
|
SELECT fact_id, fact_type_id, hash
|
|
746
|
-
FROM
|
|
754
|
+
FROM ${schema}.fact
|
|
747
755
|
) AS predecessor
|
|
748
756
|
ON predecessor.hash = new_edge.predecessor_hash
|
|
749
757
|
AND predecessor.fact_type_id = new_edge.predecessor_fact_type_id
|
|
@@ -762,20 +770,20 @@ ancestor_id AS (
|
|
|
762
770
|
FROM inserted_fact
|
|
763
771
|
UNION ALL
|
|
764
772
|
SELECT fact_id, fact_type_id, hash
|
|
765
|
-
FROM
|
|
773
|
+
FROM ${schema}.fact
|
|
766
774
|
) AS ancestor
|
|
767
775
|
ON ancestor.hash = new_ancestor.ancestor_hash
|
|
768
776
|
AND ancestor.fact_type_id = new_ancestor.ancestor_fact_type_id
|
|
769
777
|
),
|
|
770
778
|
inserted_ancestor AS (
|
|
771
|
-
INSERT INTO
|
|
779
|
+
INSERT INTO ${schema}.ancestor
|
|
772
780
|
(fact_id, ancestor_fact_id)
|
|
773
781
|
SELECT ancestor_id.fact_id, ancestor_id.ancestor_fact_id
|
|
774
782
|
FROM ancestor_id
|
|
775
783
|
UNION ALL
|
|
776
784
|
SELECT ancestor_id.fact_id, ancestor.ancestor_fact_id
|
|
777
785
|
FROM ancestor_id
|
|
778
|
-
JOIN
|
|
786
|
+
JOIN ${schema}.ancestor
|
|
779
787
|
ON ancestor.fact_id = ancestor_id.ancestor_fact_id
|
|
780
788
|
ON CONFLICT DO NOTHING
|
|
781
789
|
)
|
|
@@ -816,11 +824,11 @@ function recursivePredecessors(factReference: FactReference, facts: FactRecord[]
|
|
|
816
824
|
});
|
|
817
825
|
}
|
|
818
826
|
|
|
819
|
-
async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient) {
|
|
827
|
+
async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient, schema: string) {
|
|
820
828
|
// Look up existing fact types
|
|
821
829
|
const publicKeys = flatten(envelopes, e => e.signatures.map(s => s.publicKey))
|
|
822
830
|
.filter(distinct);
|
|
823
|
-
const lookUpSql =
|
|
831
|
+
const lookUpSql = `SELECT public_key, public_key_id FROM ${schema}.public_key WHERE public_key=ANY($1);`;
|
|
824
832
|
const { rows: existingRows }: PublicKeyResult = await connection.query(lookUpSql, [publicKeys]);
|
|
825
833
|
const publicKeyIds = existingRows.reduce(
|
|
826
834
|
(map, row) => addFactType(map, row.public_key, row.public_key_id),
|
|
@@ -833,7 +841,7 @@ async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient
|
|
|
833
841
|
|
|
834
842
|
// Insert new fact types
|
|
835
843
|
const values = remainingPublicKeys.map((name, index) => `($${index + 1})`);
|
|
836
|
-
const insertSql =
|
|
844
|
+
const insertSql = `INSERT INTO ${schema}.public_key (public_key) VALUES ` + values.join(', ') +
|
|
837
845
|
' RETURNING public_key, public_key_id;';
|
|
838
846
|
const { rows: newRows }: PublicKeyResult = await connection.query(insertSql, remainingPublicKeys);
|
|
839
847
|
if (newRows.length !== remainingPublicKeys.length) {
|
|
@@ -846,7 +854,7 @@ async function storePublicKeys(envelopes: FactEnvelope[], connection: PoolClient
|
|
|
846
854
|
return allPublicKeyIds;
|
|
847
855
|
}
|
|
848
856
|
|
|
849
|
-
async function insertSignatures(envelopes: FactEnvelope[], allFacts: FactMap, factTypes: FactTypeMap, publicKey: PublicKeyMap, connection: PoolClient) {
|
|
857
|
+
async function insertSignatures(envelopes: FactEnvelope[], allFacts: FactMap, factTypes: FactTypeMap, publicKey: PublicKeyMap, connection: PoolClient, schema: string) {
|
|
850
858
|
const signatureRecords = flatten(envelopes, envelope => envelope.signatures.map(signature => ({
|
|
851
859
|
factId: getFactId(allFacts, envelope.fact.hash, ensureGetFactTypeId(factTypes, envelope.fact.type)),
|
|
852
860
|
publicKeyId: getPublicKeyId(publicKey, signature.publicKey),
|
|
@@ -858,7 +866,7 @@ async function insertSignatures(envelopes: FactEnvelope[], allFacts: FactMap, fa
|
|
|
858
866
|
const signatureParameters = flatten(signatureRecords, s =>
|
|
859
867
|
[s.factId, s.publicKeyId, s.signature]);
|
|
860
868
|
|
|
861
|
-
const sql = `INSERT INTO
|
|
869
|
+
const sql = `INSERT INTO ${schema}.signature
|
|
862
870
|
(fact_id, public_key_id, signature)
|
|
863
871
|
(SELECT fact_id, public_key_id, signature
|
|
864
872
|
FROM (VALUES ${signatureValues.join(', ')}) AS v(fact_id, public_key_id, signature))
|