jinaga-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/dist/authentication/authentication-device.d.ts +20 -0
- package/dist/authentication/authentication-device.js +61 -0
- package/dist/authentication/authentication-device.js.map +1 -0
- package/dist/authentication/authentication-impl.d.ts +21 -0
- package/dist/authentication/authentication-impl.js +61 -0
- package/dist/authentication/authentication-impl.js.map +1 -0
- package/dist/authentication/authentication-session.d.ts +23 -0
- package/dist/authentication/authentication-session.js +85 -0
- package/dist/authentication/authentication-session.js.map +1 -0
- package/dist/authentication/authentication.d.ts +5 -0
- package/dist/authentication/authentication.js +3 -0
- package/dist/authentication/authentication.js.map +1 -0
- package/dist/authentication.d.ts +17 -0
- package/dist/authentication.js +52 -0
- package/dist/authentication.js.map +1 -0
- package/dist/authorization/authorization-keystore.d.ts +13 -0
- package/dist/authorization/authorization-keystore.js +61 -0
- package/dist/authorization/authorization-keystore.js.map +1 -0
- package/dist/http/node-http.d.ts +7 -0
- package/dist/http/node-http.js +126 -0
- package/dist/http/node-http.js.map +1 -0
- package/dist/http/router.d.ts +20 -0
- package/dist/http/router.js +223 -0
- package/dist/http/router.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/jinaga-server.d.ts +18 -0
- package/dist/jinaga-server.js +101 -0
- package/dist/jinaga-server.js.map +1 -0
- package/dist/keystore.d.ts +9 -0
- package/dist/keystore.js +3 -0
- package/dist/keystore.js.map +1 -0
- package/dist/memory/memory-keystore.d.ts +16 -0
- package/dist/memory/memory-keystore.js +86 -0
- package/dist/memory/memory-keystore.js.map +1 -0
- package/dist/postgres/connection.d.ts +12 -0
- package/dist/postgres/connection.js +83 -0
- package/dist/postgres/connection.js.map +1 -0
- package/dist/postgres/edge-record.d.ts +9 -0
- package/dist/postgres/edge-record.js +30 -0
- package/dist/postgres/edge-record.js.map +1 -0
- package/dist/postgres/maps.d.ts +21 -0
- package/dist/postgres/maps.js +86 -0
- package/dist/postgres/maps.js.map +1 -0
- package/dist/postgres/postgres-keystore.d.ts +20 -0
- package/dist/postgres/postgres-keystore.js +168 -0
- package/dist/postgres/postgres-keystore.js.map +1 -0
- package/dist/postgres/postgres-store.d.ts +20 -0
- package/dist/postgres/postgres-store.js +717 -0
- package/dist/postgres/postgres-store.js.map +1 -0
- package/dist/postgres/query-description-builder.d.ts +13 -0
- package/dist/postgres/query-description-builder.js +104 -0
- package/dist/postgres/query-description-builder.js.map +1 -0
- package/dist/postgres/query-description.d.ts +71 -0
- package/dist/postgres/query-description.js +256 -0
- package/dist/postgres/query-description.js.map +1 -0
- package/dist/postgres/specification-result-sql.d.ts +41 -0
- package/dist/postgres/specification-result-sql.js +260 -0
- package/dist/postgres/specification-result-sql.js.map +1 -0
- package/dist/postgres/specification-sql.d.ts +3 -0
- package/dist/postgres/specification-sql.js +119 -0
- package/dist/postgres/specification-sql.js.map +1 -0
- package/dist/postgres/sql.d.ts +10 -0
- package/dist/postgres/sql.js +396 -0
- package/dist/postgres/sql.js.map +1 -0
- package/dist/util/fn.d.ts +6 -0
- package/dist/util/fn.js +81 -0
- package/dist/util/fn.js.map +1 -0
- package/dist/util/promise.d.ts +1 -0
- package/dist/util/promise.js +10 -0
- package/dist/util/promise.js.map +1 -0
- package/docs/registrations.sql +22 -0
- package/docs/specification.txt +41 -0
- package/docs/sql-generator.gv +25 -0
- package/integration-test/docker-compose.yaml +13 -0
- package/integration-test/jinaga-test/Dockerfile +12 -0
- package/integration-test/jinaga-test/jinaga.test.js +425 -0
- package/integration-test/jinaga-test/package-lock.json +6767 -0
- package/integration-test/jinaga-test/package.json +25 -0
- package/integration-test/postgres/0-init-app-db.sh +16 -0
- package/integration-test/postgres/1-setup.sql +219 -0
- package/integration-test/postgres/2-grant.sh +17 -0
- package/integration-test/postgres/Dockerfile +5 -0
- package/integration-test/run.sh +17 -0
- package/integration-test/start_db.sh +2 -0
- package/integration-test/stop_db.sh +3 -0
- package/integration-test/test.sh +8 -0
- package/interactive/index.js +56 -0
- package/jest.config.js +12 -0
- package/package.json +51 -0
- package/scripts/combined.sql +46 -0
- package/scripts/cte.sql +55 -0
- package/scripts/separate.sql +27 -0
- package/setup.sh +34 -0
- package/setup.sql +329 -0
- package/src/authentication/authentication-device.ts +68 -0
- package/src/authentication/authentication-impl.ts +59 -0
- package/src/authentication/authentication-session.ts +95 -0
- package/src/authentication/authentication.ts +6 -0
- package/src/authentication.ts +45 -0
- package/src/authorization/authorization-keystore.ts +67 -0
- package/src/http/node-http.ts +106 -0
- package/src/http/router.ts +237 -0
- package/src/index.ts +1 -0
- package/src/jinaga-server.ts +125 -0
- package/src/keystore.ts +10 -0
- package/src/memory/memory-keystore.ts +93 -0
- package/src/postgres/connection.ts +73 -0
- package/src/postgres/edge-record.ts +36 -0
- package/src/postgres/maps.ts +89 -0
- package/src/postgres/postgres-keystore.ts +167 -0
- package/src/postgres/postgres-store.ts +874 -0
- package/src/postgres/query-description-builder.ts +116 -0
- package/src/postgres/query-description.ts +385 -0
- package/src/postgres/specification-result-sql.ts +362 -0
- package/src/postgres/specification-sql.ts +138 -0
- package/src/postgres/sql.ts +482 -0
- package/src/util/fn.ts +63 -0
- package/src/util/promise.ts +5 -0
- package/test/authorization/authorizationSpec.ts +209 -0
- package/test/postgres/postgresSpec.ts +385 -0
- package/test/postgres/postgresSpecificationSpec.ts +742 -0
- package/test/reporter.js +25 -0
- package/tsconfig.json +25 -0
- package/upgrade.sh +21 -0
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PostgresStore = void 0;
|
|
13
|
+
const jinaga_1 = require("jinaga");
|
|
14
|
+
const fn_1 = require("../util/fn");
|
|
15
|
+
const connection_1 = require("./connection");
|
|
16
|
+
const edge_record_1 = require("./edge-record");
|
|
17
|
+
const maps_1 = require("./maps");
|
|
18
|
+
const specification_result_sql_1 = require("./specification-result-sql");
|
|
19
|
+
const specification_sql_1 = require("./specification-sql");
|
|
20
|
+
const sql_1 = require("./sql");
|
|
21
|
+
function loadFactReference(r) {
|
|
22
|
+
return {
|
|
23
|
+
type: r.type,
|
|
24
|
+
hash: r.hash
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function loadFactTuple(labels, row) {
|
|
28
|
+
const facts = labels.map(label => {
|
|
29
|
+
const hashColumn = `hash${label.index}`;
|
|
30
|
+
const hash = row[hashColumn];
|
|
31
|
+
if (hash === null) {
|
|
32
|
+
const columns = Object.keys(row);
|
|
33
|
+
throw new Error(`Cannot find column '${hashColumn}'. Available columns: ${columns.join(', ')}`);
|
|
34
|
+
}
|
|
35
|
+
const fact = {
|
|
36
|
+
type: label.type,
|
|
37
|
+
hash
|
|
38
|
+
};
|
|
39
|
+
return fact;
|
|
40
|
+
});
|
|
41
|
+
const bookmark = row.bookmark;
|
|
42
|
+
return {
|
|
43
|
+
facts,
|
|
44
|
+
bookmark: bookmark.join(".")
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function loadFactPath(pathLength, factTypeNames, r) {
|
|
48
|
+
let path = [];
|
|
49
|
+
for (let i = 0; i < pathLength; i++) {
|
|
50
|
+
const hash = r['hash' + (i + 2)];
|
|
51
|
+
if (!hash) {
|
|
52
|
+
throw new Error(`Cannot find column 'hash${i + 2}'`);
|
|
53
|
+
}
|
|
54
|
+
path.push({
|
|
55
|
+
type: factTypeNames[i],
|
|
56
|
+
hash: hash
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return path;
|
|
60
|
+
}
|
|
61
|
+
class PostgresStore {
|
|
62
|
+
constructor(postgresUri) {
|
|
63
|
+
this.factTypeMap = (0, maps_1.emptyFactTypeMap)();
|
|
64
|
+
this.roleMap = (0, maps_1.emptyRoleMap)();
|
|
65
|
+
this.connectionFactory = new connection_1.ConnectionFactory(postgresUri);
|
|
66
|
+
}
|
|
67
|
+
close() {
|
|
68
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
69
|
+
yield this.connectionFactory.close();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
save(envelopes) {
|
|
73
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
74
|
+
if (envelopes.length > 0) {
|
|
75
|
+
const facts = envelopes.map(e => e.fact);
|
|
76
|
+
if (facts.some(f => !f.hash || !f.type)) {
|
|
77
|
+
throw new Error('Attempted to save a fact with no hash or type.');
|
|
78
|
+
}
|
|
79
|
+
const { newEnvelopes, factTypes, roles } = yield this.connectionFactory.withTransaction((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
const factTypes = yield storeFactTypes(facts, this.factTypeMap, connection);
|
|
81
|
+
const existingFacts = yield findExistingFacts(facts, factTypes, connection);
|
|
82
|
+
const newFacts = facts.filter(f => !(0, maps_1.hasFact)(existingFacts, f.hash, factTypes.get(f.type)));
|
|
83
|
+
if (newFacts.length === 0) {
|
|
84
|
+
return {
|
|
85
|
+
newEnvelopes: [],
|
|
86
|
+
factTypes,
|
|
87
|
+
roles: (0, maps_1.emptyRoleMap)()
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const roles = yield storeRoles(newFacts, factTypes, (0, maps_1.copyRoleMap)(this.roleMap), connection);
|
|
91
|
+
const allFacts = yield insertFactsEdgesAndAncestors(newFacts, factTypes, existingFacts, connection, roles);
|
|
92
|
+
const newEnvelopes = envelopes.filter(envelope => newFacts.some((0, jinaga_1.factReferenceEquals)(envelope.fact)));
|
|
93
|
+
if (newEnvelopes.length === 0) {
|
|
94
|
+
return {
|
|
95
|
+
newEnvelopes,
|
|
96
|
+
factTypes,
|
|
97
|
+
roles
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const publicKeys = yield storePublicKeys(newEnvelopes, connection);
|
|
101
|
+
yield insertSignatures(newEnvelopes, allFacts, factTypes, publicKeys, connection);
|
|
102
|
+
return {
|
|
103
|
+
newEnvelopes,
|
|
104
|
+
factTypes,
|
|
105
|
+
roles
|
|
106
|
+
};
|
|
107
|
+
}));
|
|
108
|
+
this.factTypeMap = (0, maps_1.mergeFactTypes)(this.factTypeMap, factTypes);
|
|
109
|
+
this.roleMap = (0, maps_1.mergeRoleMaps)(this.roleMap, roles);
|
|
110
|
+
return newEnvelopes;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
query(start, query) {
|
|
118
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
+
if (query.steps.length === 0) {
|
|
120
|
+
return [[start]];
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const factTypes = yield this.loadFactTypesFromSteps(query.steps, start.type);
|
|
124
|
+
const roleMap = yield this.loadRolesFromSteps(query.steps, factTypes, start.type);
|
|
125
|
+
const sqlQuery = (0, sql_1.sqlFromSteps)(start, query.steps, factTypes, roleMap);
|
|
126
|
+
if (!sqlQuery) {
|
|
127
|
+
throw new Error(`Could not generate SQL for query "${query.toDescriptiveString()}" starting at "${start.type}"`);
|
|
128
|
+
}
|
|
129
|
+
if (sqlQuery.empty) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
const { rows } = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
133
|
+
return yield connection.query(sqlQuery.sql, sqlQuery.parameters);
|
|
134
|
+
}));
|
|
135
|
+
return rows.map(row => loadFactPath(sqlQuery.pathLength, sqlQuery.factTypeNames, row));
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
throw new Error(`Could not generate SQL for query "${query.toDescriptiveString()}" starting at "${start.type}": ${e}`);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
read(start, specification) {
|
|
143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
144
|
+
const factTypes = yield this.loadFactTypesFromSpecification(specification);
|
|
145
|
+
const roleMap = yield this.loadRolesFromSpecification(specification, factTypes);
|
|
146
|
+
const composer = (0, specification_result_sql_1.resultSqlFromSpecification)(start, specification, factTypes, roleMap);
|
|
147
|
+
if (composer === null) {
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
const sqlQueryTree = composer.getSqlQueries();
|
|
151
|
+
const resultSets = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
152
|
+
return yield executeQueryTree(sqlQueryTree, connection);
|
|
153
|
+
}));
|
|
154
|
+
return composer.compose(resultSets);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
streamsFromSpecification(start, bookmarks, limit, specification) {
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
const factTypes = yield this.loadFactTypesFromSpecification(specification);
|
|
160
|
+
const roleMap = yield this.loadRolesFromSpecification(specification, factTypes);
|
|
161
|
+
const sqlQueries = (0, specification_sql_1.sqlFromSpecification)(start, bookmarks, limit, specification, factTypes, roleMap);
|
|
162
|
+
const streams = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
163
|
+
const streams = [];
|
|
164
|
+
for (const sqlQuery of sqlQueries) {
|
|
165
|
+
try {
|
|
166
|
+
const { rows } = yield connection.query(sqlQuery.sql, sqlQuery.parameters);
|
|
167
|
+
const tuples = rows.map(row => loadFactTuple(sqlQuery.labels, row));
|
|
168
|
+
streams.push({
|
|
169
|
+
labels: sqlQuery.labels.map(l => l.name),
|
|
170
|
+
tuples,
|
|
171
|
+
bookmark: tuples.length > 0 ? tuples[tuples.length - 1].bookmark : sqlQuery.bookmark
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
throw new Error(`Could not execute query "${sqlQuery.sql}", parameters ${sqlQuery.parameters}:\n${error}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return streams;
|
|
179
|
+
}));
|
|
180
|
+
return streams;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
loadFactTypesFromSteps(steps, startType) {
|
|
184
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
185
|
+
const factTypes = this.factTypeMap;
|
|
186
|
+
const unknownFactTypes = [...allFactTypes(steps), startType]
|
|
187
|
+
.filter(factType => !factTypes.has(factType))
|
|
188
|
+
.filter(fn_1.distinct);
|
|
189
|
+
if (unknownFactTypes.length > 0) {
|
|
190
|
+
const loadedFactTypes = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
191
|
+
return yield loadFactTypes(unknownFactTypes, connection);
|
|
192
|
+
}));
|
|
193
|
+
const merged = (0, maps_1.mergeFactTypes)(this.factTypeMap, loadedFactTypes);
|
|
194
|
+
this.factTypeMap = merged;
|
|
195
|
+
return merged;
|
|
196
|
+
}
|
|
197
|
+
return factTypes;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
loadFactTypesFromSpecification(specification) {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
const factTypes = this.factTypeMap;
|
|
203
|
+
const unknownFactTypes = (0, jinaga_1.getAllFactTypes)(specification)
|
|
204
|
+
.filter(factType => !factTypes.has(factType));
|
|
205
|
+
if (unknownFactTypes.length > 0) {
|
|
206
|
+
const loadedFactTypes = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
207
|
+
return yield loadFactTypes(unknownFactTypes, connection);
|
|
208
|
+
}));
|
|
209
|
+
const merged = (0, maps_1.mergeFactTypes)(this.factTypeMap, loadedFactTypes);
|
|
210
|
+
this.factTypeMap = merged;
|
|
211
|
+
return merged;
|
|
212
|
+
}
|
|
213
|
+
return factTypes;
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
loadRolesFromSteps(steps, factTypes, initialType) {
|
|
217
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
+
const roleMap = this.roleMap;
|
|
219
|
+
const unknownRoles = allRoles(steps, factTypes, (0, maps_1.getFactTypeId)(factTypes, initialType))
|
|
220
|
+
.filter(r => !(0, maps_1.hasRole)(roleMap, r.defining_fact_type_id, r.role));
|
|
221
|
+
if (unknownRoles.length > 0) {
|
|
222
|
+
const loadedRoles = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
223
|
+
return yield loadRoles(unknownRoles, roleMap, connection);
|
|
224
|
+
}));
|
|
225
|
+
const merged = (0, maps_1.mergeRoleMaps)(this.roleMap, loadedRoles);
|
|
226
|
+
this.roleMap = merged;
|
|
227
|
+
return merged;
|
|
228
|
+
}
|
|
229
|
+
return roleMap;
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
loadRolesFromSpecification(specification, factTypes) {
|
|
233
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
234
|
+
const roleMap = this.roleMap;
|
|
235
|
+
const unknownRoles = (0, jinaga_1.getAllRoles)(specification)
|
|
236
|
+
.map(r => ({
|
|
237
|
+
defining_fact_type_id: (0, maps_1.getFactTypeId)(factTypes, r.definingFactType),
|
|
238
|
+
role: r.name
|
|
239
|
+
}))
|
|
240
|
+
.filter(r => !(0, maps_1.hasRole)(roleMap, r.defining_fact_type_id, r.role));
|
|
241
|
+
if (unknownRoles.length > 0) {
|
|
242
|
+
const loadedRoles = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
243
|
+
return yield loadRoles(unknownRoles, roleMap, connection);
|
|
244
|
+
}));
|
|
245
|
+
const merged = (0, maps_1.mergeRoleMaps)(this.roleMap, loadedRoles);
|
|
246
|
+
this.roleMap = merged;
|
|
247
|
+
return merged;
|
|
248
|
+
}
|
|
249
|
+
return roleMap;
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
whichExist(references) {
|
|
253
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
254
|
+
if (references.length === 0) {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
const factTypes = yield this.loadFactTypesFromReferences(references);
|
|
258
|
+
const factValues = references.map((f, i) => `(\$${i * 2 + 1}, \$${i * 2 + 2}::integer)`);
|
|
259
|
+
const factParameters = (0, fn_1.flatten)(references, (f) => [f.hash, factTypes.get(f.type)]);
|
|
260
|
+
const sql = 'SELECT f.fact_type_id, f.hash ' +
|
|
261
|
+
'FROM public.fact f ' +
|
|
262
|
+
'JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id) ' +
|
|
263
|
+
' ON v.fact_type_id = f.fact_type_id AND v.hash = f.hash ';
|
|
264
|
+
const result = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
return yield connection.query(sql, factParameters);
|
|
266
|
+
}));
|
|
267
|
+
const existing = references.filter(r => result.rows.some(row => row.fact_type_id === factTypes.get(r.type) && row.hash === r.hash));
|
|
268
|
+
return existing;
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
load(references) {
|
|
272
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
273
|
+
if (references.length === 0) {
|
|
274
|
+
return [];
|
|
275
|
+
}
|
|
276
|
+
const factTypes = yield this.loadFactTypesFromReferences(references);
|
|
277
|
+
const factValues = references.map((f, i) => `(\$${i * 2 + 1}, \$${i * 2 + 2}::integer)`);
|
|
278
|
+
const factParameters = (0, fn_1.flatten)(references, (f) => [f.hash, factTypes.get(f.type)]);
|
|
279
|
+
const sql = 'SELECT f.fact_type_id, t.name, f.hash, f.data ' +
|
|
280
|
+
'FROM public.fact f ' +
|
|
281
|
+
'JOIN public.fact_type t ' +
|
|
282
|
+
' ON f.fact_type_id = t.fact_type_id ' +
|
|
283
|
+
'JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id) ' +
|
|
284
|
+
' ON v.fact_type_id = f.fact_type_id AND v.hash = f.hash ' +
|
|
285
|
+
'UNION ' +
|
|
286
|
+
'SELECT f2.fact_type_id, t.name, f2.hash, f2.data ' +
|
|
287
|
+
'FROM public.fact f1 ' +
|
|
288
|
+
'JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id) ' +
|
|
289
|
+
' ON v.fact_type_id = f1.fact_type_id AND v.hash = f1.hash ' +
|
|
290
|
+
'JOIN public.ancestor a ' +
|
|
291
|
+
' ON a.fact_id = f1.fact_id ' +
|
|
292
|
+
'JOIN public.fact f2 ' +
|
|
293
|
+
' ON f2.fact_id = a.ancestor_fact_id ' +
|
|
294
|
+
'JOIN public.fact_type t ' +
|
|
295
|
+
' ON t.fact_type_id = f2.fact_type_id;';
|
|
296
|
+
const result = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
297
|
+
return yield connection.query(sql, factParameters);
|
|
298
|
+
}));
|
|
299
|
+
const resultFactTypes = result.rows.reduce((factTypes, r) => (0, maps_1.addFactType)(factTypes, r.name, r.fact_type_id), (0, maps_1.emptyFactTypeMap)());
|
|
300
|
+
this.factTypeMap = (0, maps_1.mergeFactTypes)(this.factTypeMap, resultFactTypes);
|
|
301
|
+
return result.rows.map((r) => {
|
|
302
|
+
const { fields, predecessors } = r.data;
|
|
303
|
+
return {
|
|
304
|
+
type: r.name,
|
|
305
|
+
hash: r.hash,
|
|
306
|
+
fields,
|
|
307
|
+
predecessors
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
loadFactTypesFromReferences(references) {
|
|
313
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
314
|
+
const factTypes = this.factTypeMap;
|
|
315
|
+
const newFactTypes = references
|
|
316
|
+
.map(reference => reference.type)
|
|
317
|
+
.filter(type => !factTypes.has(type))
|
|
318
|
+
.filter(fn_1.distinct);
|
|
319
|
+
if (newFactTypes.length > 0) {
|
|
320
|
+
const loadedFactTypes = yield this.connectionFactory.with((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
321
|
+
return yield loadFactTypes(newFactTypes, connection);
|
|
322
|
+
}));
|
|
323
|
+
const mergedFactTypes = (0, maps_1.mergeFactTypes)(factTypes, loadedFactTypes);
|
|
324
|
+
this.factTypeMap = mergedFactTypes;
|
|
325
|
+
return mergedFactTypes;
|
|
326
|
+
}
|
|
327
|
+
return factTypes;
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
exports.PostgresStore = PostgresStore;
|
|
332
|
+
function executeQueryTree(sqlQueryTree, connection) {
|
|
333
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
334
|
+
const sqlQuery = sqlQueryTree.sqlQuery;
|
|
335
|
+
const { rows } = yield connection.query(sqlQuery.sql, sqlQuery.parameters);
|
|
336
|
+
const resultSets = {
|
|
337
|
+
resultSet: rows,
|
|
338
|
+
childResultSets: []
|
|
339
|
+
};
|
|
340
|
+
for (const child of sqlQueryTree.childQueries) {
|
|
341
|
+
const childResultSet = yield executeQueryTree(child, connection);
|
|
342
|
+
resultSets.childResultSets.push(Object.assign({ name: child.name }, childResultSet));
|
|
343
|
+
}
|
|
344
|
+
return resultSets;
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
function predecessorTypes(predecessor) {
|
|
348
|
+
if (Array.isArray(predecessor)) {
|
|
349
|
+
return predecessor.map(p => p.type);
|
|
350
|
+
}
|
|
351
|
+
return [predecessor.type];
|
|
352
|
+
}
|
|
353
|
+
function predecessorCollectionTypes(predecessors) {
|
|
354
|
+
return Object.keys(predecessors).flatMap(key => predecessorTypes(predecessors[key]));
|
|
355
|
+
}
|
|
356
|
+
function storeFactTypes(facts, factTypes, connection) {
|
|
357
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
358
|
+
const newFactTypes = facts
|
|
359
|
+
.flatMap(fact => [fact.type, ...predecessorCollectionTypes(fact.predecessors)])
|
|
360
|
+
.filter(type => !factTypes.has(type))
|
|
361
|
+
.filter(fn_1.distinct);
|
|
362
|
+
if (newFactTypes.length === 0) {
|
|
363
|
+
return factTypes;
|
|
364
|
+
}
|
|
365
|
+
// Look up existing fact types
|
|
366
|
+
const loadedFactTypes = yield loadFactTypes(newFactTypes, connection);
|
|
367
|
+
const remainingNames = newFactTypes.filter(type => !loadedFactTypes.has(type));
|
|
368
|
+
if (remainingNames.length === 0) {
|
|
369
|
+
return (0, maps_1.mergeFactTypes)(loadedFactTypes, factTypes);
|
|
370
|
+
}
|
|
371
|
+
// Insert new fact types
|
|
372
|
+
const values = remainingNames.map((name, index) => `($${index + 1})`);
|
|
373
|
+
const insertSql = 'INSERT INTO public.fact_type (name) VALUES ' + values.join(', ') +
|
|
374
|
+
' RETURNING fact_type_id, name;';
|
|
375
|
+
const { rows: newRows } = yield connection.query(insertSql, remainingNames);
|
|
376
|
+
if (newRows.length !== remainingNames.length) {
|
|
377
|
+
throw new Error('Failed to insert all new fact types.');
|
|
378
|
+
}
|
|
379
|
+
const allFactTypes = newRows.reduce((map, row) => (0, maps_1.addFactType)(map, row.name, row.fact_type_id), (0, maps_1.mergeFactTypes)(loadedFactTypes, factTypes));
|
|
380
|
+
return allFactTypes;
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
function loadFactTypes(factTypeNames, connection) {
|
|
384
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
385
|
+
const lookUpSql = 'SELECT name, fact_type_id FROM public.fact_type WHERE name=ANY($1);';
|
|
386
|
+
const { rows: existingRows } = yield connection.query(lookUpSql, [factTypeNames]);
|
|
387
|
+
const factTypeIds = existingRows.reduce((map, row) => (0, maps_1.addFactType)(map, row.name, row.fact_type_id), (0, maps_1.emptyFactTypeMap)());
|
|
388
|
+
return factTypeIds;
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
function storeRoles(facts, factTypes, roleMap, connection) {
|
|
392
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
393
|
+
// Find distinct roles
|
|
394
|
+
const roles = (0, fn_1.flatten)(facts, fact => {
|
|
395
|
+
const defining_fact_type_id = factTypes.get(fact.type);
|
|
396
|
+
return Object.keys(fact.predecessors).map(role => ({
|
|
397
|
+
role,
|
|
398
|
+
defining_fact_type_id
|
|
399
|
+
}));
|
|
400
|
+
}).filter((role, index, array) => array.findIndex(r => r.role === role.role &&
|
|
401
|
+
r.defining_fact_type_id === role.defining_fact_type_id) === index);
|
|
402
|
+
if (roles.length > 0) {
|
|
403
|
+
// Look up existing roles
|
|
404
|
+
const roleIds = yield loadRoles(roles, roleMap, connection);
|
|
405
|
+
const remainingRoles = roles.filter(role => !(0, maps_1.hasRole)(roleIds, role.defining_fact_type_id, role.role));
|
|
406
|
+
if (remainingRoles.length === 0) {
|
|
407
|
+
return roleIds;
|
|
408
|
+
}
|
|
409
|
+
// Insert new roles
|
|
410
|
+
const remainingRoleValues = remainingRoles.map((role, index) => `($${index * 2 + 1}, $${index * 2 + 2}::integer)`);
|
|
411
|
+
const insertSql = 'INSERT INTO public.role (name, defining_fact_type_id) VALUES ' +
|
|
412
|
+
remainingRoleValues.join(', ') +
|
|
413
|
+
' RETURNING role_id, name, defining_fact_type_id;';
|
|
414
|
+
const remainingRoleParameters = (0, fn_1.flatten)(remainingRoles, (role) => [
|
|
415
|
+
role.role,
|
|
416
|
+
role.defining_fact_type_id
|
|
417
|
+
]);
|
|
418
|
+
const { rows: newRows } = yield connection.query(insertSql, remainingRoleParameters);
|
|
419
|
+
if (newRows.length !== remainingRoles.length) {
|
|
420
|
+
throw new Error('Failed to insert all new roles.');
|
|
421
|
+
}
|
|
422
|
+
const allRoleIds = newRows.reduce((map, row) => (0, maps_1.addRole)(map, row.defining_fact_type_id, row.name, row.role_id), roleIds);
|
|
423
|
+
return allRoleIds;
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
return roleMap;
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
function loadRoles(roles, roleMap, connection) {
|
|
431
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
432
|
+
const roleValues = roles.map((role, index) => `($${index * 2 + 1}, $${index * 2 + 2}::integer)`);
|
|
433
|
+
const roleParameters = (0, fn_1.flatten)(roles, (role) => [
|
|
434
|
+
role.role,
|
|
435
|
+
role.defining_fact_type_id
|
|
436
|
+
]);
|
|
437
|
+
const lookUpSql = 'SELECT role.name, role.defining_fact_type_id, role.role_id' +
|
|
438
|
+
' FROM public.role' +
|
|
439
|
+
' JOIN (VALUES ' + roleValues.join(', ') + ') AS v (name, defining_fact_type_id)' +
|
|
440
|
+
' ON v.name = role.name AND v.defining_fact_type_id = role.defining_fact_type_id;';
|
|
441
|
+
const { rows } = yield connection.query(lookUpSql, roleParameters);
|
|
442
|
+
const roleIds = rows.reduce((map, row) => (0, maps_1.addRole)(map, row.defining_fact_type_id, row.name, row.role_id), roleMap);
|
|
443
|
+
return roleIds;
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
function findExistingFacts(facts, factTypes, connection) {
|
|
447
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
448
|
+
if (facts.length > 0) {
|
|
449
|
+
const factReferences = facts.flatMap(fact => [
|
|
450
|
+
...predecessorsOf(fact),
|
|
451
|
+
fact
|
|
452
|
+
]);
|
|
453
|
+
const factValues = factReferences.map((f, i) => `(\$${i * 2 + 1}, \$${i * 2 + 2}::integer)`);
|
|
454
|
+
const factParameters = factReferences.flatMap((f) => [f.hash, factTypes.get(f.type)]);
|
|
455
|
+
const sql = 'SELECT fact_id, fact.fact_type_id, fact.hash' +
|
|
456
|
+
' FROM public.fact' +
|
|
457
|
+
' JOIN (VALUES ' + factValues.join(', ') + ') AS v (hash, fact_type_id)' +
|
|
458
|
+
' ON v.fact_type_id = fact.fact_type_id AND v.hash = fact.hash;';
|
|
459
|
+
const { rows } = yield connection.query(sql, factParameters);
|
|
460
|
+
const existingFacts = rows.reduce((map, row) => (0, maps_1.addFact)(map, row.hash, row.fact_type_id, row.fact_id), (0, maps_1.emptyFactMap)());
|
|
461
|
+
return existingFacts;
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
return (0, maps_1.emptyFactMap)();
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
function insertFactsEdgesAndAncestors(facts, factTypes, existingFacts, connection, roles) {
|
|
469
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
470
|
+
if (facts.length === 0) {
|
|
471
|
+
return (0, maps_1.emptyFactMap)();
|
|
472
|
+
}
|
|
473
|
+
const { sql, parameters } = sqlInsertFacts(facts, roles, factTypes);
|
|
474
|
+
const { rows } = yield connection.query(sql, parameters);
|
|
475
|
+
if (rows.length !== facts.length) {
|
|
476
|
+
throw new Error('Failed to insert all new facts.');
|
|
477
|
+
}
|
|
478
|
+
const allFacts = rows.reduce((map, row) => (0, maps_1.addFact)(map, row.hash, row.fact_type_id, row.fact_id), existingFacts);
|
|
479
|
+
return allFacts;
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
function sqlInsertFacts(facts, roles, factTypes) {
|
|
483
|
+
const factValues = facts.map((f, i) => `(\$${i * 3 + 1}, \$${i * 3 + 2}::integer, \$${i * 3 + 3}::jsonb)`);
|
|
484
|
+
const factParameters = (0, fn_1.flatten)(facts, (f) => [f.hash, factTypes.get(f.type), {
|
|
485
|
+
fields: f.fields,
|
|
486
|
+
predecessors: (0, jinaga_1.canonicalPredecessors)(f.predecessors)
|
|
487
|
+
}]);
|
|
488
|
+
const edgeRecords = (0, fn_1.flatten)(facts, fact => (0, edge_record_1.makeEdgeRecords)(fact));
|
|
489
|
+
if (edgeRecords.length > 0) {
|
|
490
|
+
return sqlInsertFactsEdgesAndAncestors(facts, factParameters, edgeRecords, factTypes, roles, factValues);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
return {
|
|
494
|
+
sql: 'INSERT INTO public.fact (hash, fact_type_id, data) VALUES ' +
|
|
495
|
+
factValues.join(', ') +
|
|
496
|
+
' RETURNING fact_id, hash, fact_type_id;',
|
|
497
|
+
parameters: factParameters
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function sqlInsertFactsEdgesAndAncestors(facts, factParameters, edgeRecords, factTypes, roles, factValues) {
|
|
502
|
+
let parameterOffset = factParameters.length;
|
|
503
|
+
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)`);
|
|
504
|
+
const edgeParameters = (0, fn_1.flatten)(edgeRecords, (e) => {
|
|
505
|
+
const successor_fact_type_id = (0, maps_1.getFactTypeId)(factTypes, e.successor_type);
|
|
506
|
+
const predecessor_fact_type_id = (0, maps_1.getFactTypeId)(factTypes, e.predecessor_type);
|
|
507
|
+
return [
|
|
508
|
+
e.successor_hash,
|
|
509
|
+
successor_fact_type_id,
|
|
510
|
+
e.predecessor_hash,
|
|
511
|
+
predecessor_fact_type_id,
|
|
512
|
+
(0, maps_1.getRoleId)(roles, successor_fact_type_id, e.role)
|
|
513
|
+
];
|
|
514
|
+
});
|
|
515
|
+
parameterOffset += edgeParameters.length;
|
|
516
|
+
const ancestors = ancestorRecords(facts);
|
|
517
|
+
const ancestorValues = ancestors.map((a, i) => `(\$${i * 4 + 1 + parameterOffset}, \$${i * 4 + 2 + parameterOffset}::integer, \$${i * 4 + 3 + parameterOffset}, \$${i * 4 + 4 + parameterOffset}::integer)`);
|
|
518
|
+
const ancestorParameters = (0, fn_1.flatten)(ancestors, (a) => [
|
|
519
|
+
a.fact.hash,
|
|
520
|
+
factTypes.get(a.fact.type),
|
|
521
|
+
a.ancestor.hash,
|
|
522
|
+
factTypes.get(a.ancestor.type)
|
|
523
|
+
]);
|
|
524
|
+
const sql = `WITH new_fact AS (
|
|
525
|
+
SELECT hash, fact_type_id, data
|
|
526
|
+
FROM (VALUES ${factValues.join(', ')})
|
|
527
|
+
AS fv (hash, fact_type_id, data)
|
|
528
|
+
),
|
|
529
|
+
new_edge AS (
|
|
530
|
+
SELECT successor_hash, successor_fact_type_id, predecessor_hash, predecessor_fact_type_id, role_id
|
|
531
|
+
FROM (VALUES ${edgeValues.join(', ')})
|
|
532
|
+
AS ev (successor_hash, successor_fact_type_id, predecessor_hash, predecessor_fact_type_id, role_id)
|
|
533
|
+
),
|
|
534
|
+
new_ancestor AS (
|
|
535
|
+
SELECT hash, fact_type_id, ancestor_hash, ancestor_fact_type_id
|
|
536
|
+
FROM (VALUES ${ancestorValues.join(', ')})
|
|
537
|
+
AS ev (hash, fact_type_id, ancestor_hash, ancestor_fact_type_id)
|
|
538
|
+
),
|
|
539
|
+
inserted_fact AS (
|
|
540
|
+
INSERT INTO public.fact (hash, fact_type_id, data)
|
|
541
|
+
SELECT hash, fact_type_id, data
|
|
542
|
+
FROM new_fact
|
|
543
|
+
RETURNING fact_id, fact_type_id, hash
|
|
544
|
+
),
|
|
545
|
+
inserted_edge AS (
|
|
546
|
+
INSERT INTO public.edge
|
|
547
|
+
(role_id, successor_fact_id, predecessor_fact_id)
|
|
548
|
+
SELECT
|
|
549
|
+
new_edge.role_id,
|
|
550
|
+
successor.fact_id,
|
|
551
|
+
predecessor.fact_id
|
|
552
|
+
FROM new_edge
|
|
553
|
+
JOIN inserted_fact AS successor
|
|
554
|
+
ON successor.hash = new_edge.successor_hash
|
|
555
|
+
AND successor.fact_type_id = new_edge.successor_fact_type_id
|
|
556
|
+
JOIN (
|
|
557
|
+
SELECT fact_id, fact_type_id, hash
|
|
558
|
+
FROM inserted_fact
|
|
559
|
+
UNION ALL
|
|
560
|
+
SELECT fact_id, fact_type_id, hash
|
|
561
|
+
FROM public.fact
|
|
562
|
+
) AS predecessor
|
|
563
|
+
ON predecessor.hash = new_edge.predecessor_hash
|
|
564
|
+
AND predecessor.fact_type_id = new_edge.predecessor_fact_type_id
|
|
565
|
+
ON CONFLICT DO NOTHING
|
|
566
|
+
),
|
|
567
|
+
ancestor_id AS (
|
|
568
|
+
SELECT
|
|
569
|
+
fact.fact_id,
|
|
570
|
+
ancestor.fact_id AS ancestor_fact_id
|
|
571
|
+
FROM new_ancestor
|
|
572
|
+
JOIN inserted_fact AS fact
|
|
573
|
+
ON fact.hash = new_ancestor.hash
|
|
574
|
+
AND fact.fact_type_id = new_ancestor.fact_type_id
|
|
575
|
+
JOIN (
|
|
576
|
+
SELECT fact_id, fact_type_id, hash
|
|
577
|
+
FROM inserted_fact
|
|
578
|
+
UNION ALL
|
|
579
|
+
SELECT fact_id, fact_type_id, hash
|
|
580
|
+
FROM public.fact
|
|
581
|
+
) AS ancestor
|
|
582
|
+
ON ancestor.hash = new_ancestor.ancestor_hash
|
|
583
|
+
AND ancestor.fact_type_id = new_ancestor.ancestor_fact_type_id
|
|
584
|
+
),
|
|
585
|
+
inserted_ancestor AS (
|
|
586
|
+
INSERT INTO public.ancestor
|
|
587
|
+
(fact_id, ancestor_fact_id)
|
|
588
|
+
SELECT ancestor_id.fact_id, ancestor_id.ancestor_fact_id
|
|
589
|
+
FROM ancestor_id
|
|
590
|
+
UNION ALL
|
|
591
|
+
SELECT ancestor_id.fact_id, ancestor.ancestor_fact_id
|
|
592
|
+
FROM ancestor_id
|
|
593
|
+
JOIN public.ancestor
|
|
594
|
+
ON ancestor.fact_id = ancestor_id.ancestor_fact_id
|
|
595
|
+
ON CONFLICT DO NOTHING
|
|
596
|
+
)
|
|
597
|
+
SELECT fact_id, fact_type_id, hash
|
|
598
|
+
FROM inserted_fact;`;
|
|
599
|
+
const parameters = [...factParameters, ...edgeParameters, ...ancestorParameters];
|
|
600
|
+
return { sql, parameters };
|
|
601
|
+
}
|
|
602
|
+
function ancestorRecords(facts) {
|
|
603
|
+
return facts.flatMap(fact => {
|
|
604
|
+
const factReference = { hash: fact.hash, type: fact.type };
|
|
605
|
+
const ancestorReferences = recursivePredecessors(factReference, facts);
|
|
606
|
+
return ancestorReferences.map(ancestor => ({
|
|
607
|
+
fact: factReference,
|
|
608
|
+
ancestor
|
|
609
|
+
}));
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
function recursivePredecessors(factReference, facts) {
|
|
613
|
+
return facts
|
|
614
|
+
.filter(f => f.hash === factReference.hash && f.type === factReference.type)
|
|
615
|
+
.flatMap(fact => {
|
|
616
|
+
const predecessorReferences = Object.keys(fact.predecessors).flatMap(role => {
|
|
617
|
+
const predecessors = fact.predecessors[role];
|
|
618
|
+
if (Array.isArray(predecessors)) {
|
|
619
|
+
return predecessors;
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
return [predecessors];
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
const ancestorReferences = predecessorReferences.flatMap(predecessor => recursivePredecessors(predecessor, facts));
|
|
626
|
+
return [...predecessorReferences, ...ancestorReferences];
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
function storePublicKeys(envelopes, connection) {
|
|
630
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
631
|
+
// Look up existing fact types
|
|
632
|
+
const publicKeys = (0, fn_1.flatten)(envelopes, e => e.signatures.map(s => s.publicKey))
|
|
633
|
+
.filter(fn_1.distinct);
|
|
634
|
+
const lookUpSql = 'SELECT public_key, public_key_id FROM public.public_key WHERE public_key=ANY($1);';
|
|
635
|
+
const { rows: existingRows } = yield connection.query(lookUpSql, [publicKeys]);
|
|
636
|
+
const publicKeyIds = existingRows.reduce((map, row) => (0, maps_1.addFactType)(map, row.public_key, row.public_key_id), (0, maps_1.emptyPublicKeyMap)());
|
|
637
|
+
const remainingPublicKeys = publicKeys.filter(pk => !publicKeyIds.has(pk));
|
|
638
|
+
if (remainingPublicKeys.length === 0) {
|
|
639
|
+
return publicKeyIds;
|
|
640
|
+
}
|
|
641
|
+
// Insert new fact types
|
|
642
|
+
const values = remainingPublicKeys.map((name, index) => `($${index + 1})`);
|
|
643
|
+
const insertSql = 'INSERT INTO public.public_key (public_key) VALUES ' + values.join(', ') +
|
|
644
|
+
' RETURNING public_key, public_key_id;';
|
|
645
|
+
const { rows: newRows } = yield connection.query(insertSql, remainingPublicKeys);
|
|
646
|
+
if (newRows.length !== remainingPublicKeys.length) {
|
|
647
|
+
throw new Error('Failed to insert all new public keys.');
|
|
648
|
+
}
|
|
649
|
+
const allPublicKeyIds = newRows.reduce((map, row) => (0, maps_1.addFactType)(map, row.public_key, row.public_key_id), publicKeyIds);
|
|
650
|
+
return allPublicKeyIds;
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
function insertSignatures(envelopes, allFacts, factTypes, publicKey, connection) {
|
|
654
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
655
|
+
const signatureRecords = (0, fn_1.flatten)(envelopes, envelope => envelope.signatures.map(signature => ({
|
|
656
|
+
factId: (0, maps_1.getFactId)(allFacts, envelope.fact.hash, (0, maps_1.getFactTypeId)(factTypes, envelope.fact.type)),
|
|
657
|
+
publicKeyId: (0, maps_1.getPublicKeyId)(publicKey, signature.publicKey),
|
|
658
|
+
signature: signature.signature
|
|
659
|
+
})));
|
|
660
|
+
if (signatureRecords.length > 0) {
|
|
661
|
+
const signatureValues = signatureRecords.map((s, i) => `($${i * 3 + 1}::integer, $${i * 3 + 2}::integer, $${i * 3 + 3})`);
|
|
662
|
+
const signatureParameters = (0, fn_1.flatten)(signatureRecords, s => [s.factId, s.publicKeyId, s.signature]);
|
|
663
|
+
const sql = `INSERT INTO public.signature
|
|
664
|
+
(fact_id, public_key_id, signature)
|
|
665
|
+
(SELECT fact_id, public_key_id, signature
|
|
666
|
+
FROM (VALUES ${signatureValues.join(', ')}) AS v(fact_id, public_key_id, signature))
|
|
667
|
+
ON CONFLICT DO NOTHING`;
|
|
668
|
+
yield connection.query(sql, signatureParameters);
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
function allFactTypes(steps) {
|
|
673
|
+
const factTypes = steps
|
|
674
|
+
.filter(step => step instanceof jinaga_1.PropertyCondition && step.name === 'type')
|
|
675
|
+
.map(step => step.value);
|
|
676
|
+
const childFactTypes = steps
|
|
677
|
+
.filter(step => step instanceof jinaga_1.ExistentialCondition)
|
|
678
|
+
.flatMap(step => allFactTypes(step.steps));
|
|
679
|
+
return [...factTypes, ...childFactTypes].filter(fn_1.distinct);
|
|
680
|
+
}
|
|
681
|
+
function allRoles(steps, factTypes, initialTypeId) {
|
|
682
|
+
let roles = [];
|
|
683
|
+
let defining_fact_type_id = initialTypeId;
|
|
684
|
+
let role = undefined;
|
|
685
|
+
for (const step of steps) {
|
|
686
|
+
if (step instanceof jinaga_1.PropertyCondition) {
|
|
687
|
+
if (step.name === 'type') {
|
|
688
|
+
defining_fact_type_id = (0, maps_1.getFactTypeId)(factTypes, step.value);
|
|
689
|
+
if (defining_fact_type_id && role) {
|
|
690
|
+
roles.push({ defining_fact_type_id, role });
|
|
691
|
+
}
|
|
692
|
+
role = undefined;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
else if (step instanceof jinaga_1.Join) {
|
|
696
|
+
if (step.direction === jinaga_1.Direction.Predecessor) {
|
|
697
|
+
if (defining_fact_type_id) {
|
|
698
|
+
roles.push({ defining_fact_type_id, role: step.role });
|
|
699
|
+
}
|
|
700
|
+
role = undefined;
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
role = step.role;
|
|
704
|
+
}
|
|
705
|
+
defining_fact_type_id = undefined;
|
|
706
|
+
}
|
|
707
|
+
else if (step instanceof jinaga_1.ExistentialCondition) {
|
|
708
|
+
roles = roles.concat(allRoles(step.steps, factTypes, defining_fact_type_id));
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return roles;
|
|
712
|
+
}
|
|
713
|
+
function predecessorsOf(fact) {
|
|
714
|
+
const references = Object.values(fact.predecessors).flatMap(predecessor => Array.isArray(predecessor) ? predecessor : [predecessor]);
|
|
715
|
+
return references;
|
|
716
|
+
}
|
|
717
|
+
//# sourceMappingURL=postgres-store.js.map
|