@snowtop/ent 0.2.6 → 0.2.8
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/action/executor.js +4 -4
- package/action/operations.js +3 -0
- package/action/orchestrator.js +10 -12
- package/action/topological_sort.d.ts +9 -0
- package/action/topological_sort.js +46 -0
- package/core/async_utils.d.ts +1 -0
- package/core/async_utils.js +29 -0
- package/core/base.d.ts +12 -5
- package/core/clause.d.ts +3 -5
- package/core/clause.js +32 -0
- package/core/config.d.ts +28 -2
- package/core/config.js +14 -1
- package/core/context.d.ts +3 -1
- package/core/context.js +90 -26
- package/core/db.d.ts +12 -2
- package/core/db.js +102 -7
- package/core/dev_schema.d.ts +9 -0
- package/core/dev_schema.js +306 -0
- package/core/ent.d.ts +5 -7
- package/core/ent.js +33 -48
- package/core/extensions.d.ts +25 -0
- package/core/extensions.js +220 -0
- package/core/loaders/assoc_count_loader.js +3 -6
- package/core/loaders/assoc_edge_loader.d.ts +3 -0
- package/core/loaders/assoc_edge_loader.js +48 -19
- package/core/loaders/index.d.ts +2 -1
- package/core/loaders/index.js +5 -1
- package/core/loaders/loader.d.ts +31 -0
- package/core/loaders/loader.js +141 -2
- package/core/loaders/object_loader.d.ts +2 -2
- package/core/loaders/object_loader.js +39 -57
- package/core/loaders/query_loader.d.ts +2 -5
- package/core/loaders/query_loader.js +45 -24
- package/core/loaders/raw_count_loader.d.ts +2 -2
- package/core/loaders/raw_count_loader.js +12 -14
- package/core/memoize.d.ts +1 -0
- package/core/memoize.js +15 -0
- package/core/metrics.d.ts +22 -0
- package/core/metrics.js +31 -0
- package/core/query/custom_clause_query.js +5 -1
- package/core/query/query.d.ts +1 -1
- package/core/query/query.js +10 -7
- package/core/query_expression.d.ts +6 -0
- package/core/query_expression.js +2 -0
- package/core/query_impl.d.ts +19 -3
- package/core/query_impl.js +148 -35
- package/index.d.ts +7 -2
- package/index.js +12 -2
- package/package.json +1 -7
- package/parse_schema/parse.d.ts +2 -12
- package/parse_schema/parse.js +22 -41
- package/schema/index.d.ts +1 -1
- package/schema/schema.d.ts +20 -1
- package/scripts/custom_graphql.js +12 -5
- package/scripts/fix_action_exports.js +1 -1
- package/scripts/migrate_v0.1.js +2 -5
- package/scripts/move_types.js +1 -1
- package/scripts/read_schema.js +2 -5
- package/testutils/builder.js +1 -2
- package/testutils/parse_sql.js +1 -1
- package/tsc/compilerOptions.d.ts +2 -2
- package/tsc/compilerOptions.js +12 -18
- package/tsc/move_generated.js +2 -2
- package/tsc/transform.d.ts +1 -1
- package/tsc/transform.js +16 -2
- package/tsc/transform_action.d.ts +1 -1
- package/tsc/transform_action.js +1 -1
- package/tsc/transform_ent.d.ts +1 -1
- package/tsc/transform_ent.js +1 -1
- package/tsc/transform_schema.d.ts +1 -1
- package/tsc/transform_schema.js +2 -2
- /package/core/{loaders/cache_utils.d.ts → cache_utils.d.ts} +0 -0
- /package/core/{loaders/cache_utils.js → cache_utils.js} +0 -0
package/core/ent.js
CHANGED
|
@@ -32,9 +32,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.assocEdgeLoader = exports.AssocEdgeData = exports.AssocEdge = void 0;
|
|
40
37
|
exports.rowIsError = rowIsError;
|
|
@@ -71,6 +68,7 @@ exports.editRow = editRow;
|
|
|
71
68
|
exports.editRowSync = editRowSync;
|
|
72
69
|
exports.deleteRows = deleteRows;
|
|
73
70
|
exports.deleteRowsSync = deleteRowsSync;
|
|
71
|
+
exports.decodeCursorPayload = decodeCursorPayload;
|
|
74
72
|
exports.getCursor = getCursor;
|
|
75
73
|
exports.loadEdgeData = loadEdgeData;
|
|
76
74
|
exports.loadEdgeDatas = loadEdgeDatas;
|
|
@@ -90,7 +88,7 @@ exports.applyPrivacyPolicyForRows = applyPrivacyPolicyForRows;
|
|
|
90
88
|
exports.getEdgeTypeInGroup = getEdgeTypeInGroup;
|
|
91
89
|
const db_1 = __importStar(require("./db"));
|
|
92
90
|
const privacy_1 = require("./privacy");
|
|
93
|
-
const
|
|
91
|
+
const async_utils_1 = require("./async_utils");
|
|
94
92
|
const clause = __importStar(require("./clause"));
|
|
95
93
|
const global_schema_1 = require("./global_schema");
|
|
96
94
|
const loader_1 = require("./loaders/loader");
|
|
@@ -125,15 +123,13 @@ class entCacheMap {
|
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
function createAssocEdgeConfigLoader(options) {
|
|
126
|
+
const loaderName = `assocEdgeConfigLoader:${options.tableName}`;
|
|
128
127
|
const loaderOptions = {
|
|
129
128
|
maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
|
|
129
|
+
cacheMap: (0, loader_1.createLoaderCacheMap)(options),
|
|
130
130
|
};
|
|
131
|
-
// if query logging is enabled, we should log what's happening with loader
|
|
132
|
-
if ((0, logger_1.logEnabled)("query")) {
|
|
133
|
-
loaderOptions.cacheMap = new loader_1.CacheMap(options);
|
|
134
|
-
}
|
|
135
131
|
// something here brokwn with strict:true
|
|
136
|
-
return new
|
|
132
|
+
return new loader_1.InstrumentedDataLoader(loaderName, async (ids) => {
|
|
137
133
|
if (!ids.length) {
|
|
138
134
|
return [];
|
|
139
135
|
}
|
|
@@ -155,7 +151,7 @@ function createAssocEdgeConfigLoader(options) {
|
|
|
155
151
|
}
|
|
156
152
|
}
|
|
157
153
|
return ids.map((id) => rowMap.get(id) ?? null);
|
|
158
|
-
}, loaderOptions);
|
|
154
|
+
}, loaderOptions, options.tableName);
|
|
159
155
|
}
|
|
160
156
|
// used to wrap errors that would eventually be thrown in ents
|
|
161
157
|
// not an Error because DataLoader automatically rejects that
|
|
@@ -177,48 +173,23 @@ function setEntLoaderPrivacyConcurrencyLimit(limit) {
|
|
|
177
173
|
function getEntLoaderPrivacyConcurrencyLimit() {
|
|
178
174
|
return entLoaderPrivacyConcurrencyLimit;
|
|
179
175
|
}
|
|
180
|
-
async function mapWithConcurrency(items, limit, mapper) {
|
|
181
|
-
if (!items.length) {
|
|
182
|
-
return [];
|
|
183
|
-
}
|
|
184
|
-
const results = new Array(items.length);
|
|
185
|
-
const concurrency = limit === Infinity
|
|
186
|
-
? items.length
|
|
187
|
-
: Number.isFinite(limit) && limit > 0
|
|
188
|
-
? Math.floor(limit)
|
|
189
|
-
: 1;
|
|
190
|
-
let nextIndex = 0;
|
|
191
|
-
const workers = new Array(Math.min(concurrency, items.length))
|
|
192
|
-
.fill(null)
|
|
193
|
-
.map(async () => {
|
|
194
|
-
while (true) {
|
|
195
|
-
const currentIndex = nextIndex;
|
|
196
|
-
if (currentIndex >= items.length) {
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
nextIndex += 1;
|
|
200
|
-
results[currentIndex] = await mapper(items[currentIndex], currentIndex);
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
await Promise.all(workers);
|
|
204
|
-
return results;
|
|
205
|
-
}
|
|
206
176
|
function createEntLoader(viewer, options, map) {
|
|
177
|
+
const loaderName = `entLoader:${options.loaderFactory.name}`;
|
|
178
|
+
const tableName = options.loaderFactory.options?.tableName;
|
|
207
179
|
// share the cache across loaders even if we create a new instance
|
|
208
180
|
const loaderOptions = {
|
|
209
181
|
maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
|
|
210
182
|
};
|
|
211
|
-
loaderOptions.cacheMap = map;
|
|
212
|
-
return new
|
|
183
|
+
loaderOptions.cacheMap = (0, loader_1.createBoundedCacheMap)(map);
|
|
184
|
+
return new loader_1.InstrumentedDataLoader(loaderName, async (ids) => {
|
|
213
185
|
if (!ids.length) {
|
|
214
186
|
return [];
|
|
215
187
|
}
|
|
216
|
-
const tableName = options.loaderFactory.options?.tableName;
|
|
217
188
|
const loader = options.loaderFactory.createLoader(viewer.context);
|
|
218
189
|
const rows = await loader.loadMany(ids);
|
|
219
190
|
// this is a loader which should return the same order based on passed-in ids
|
|
220
191
|
// so let's depend on that...
|
|
221
|
-
return mapWithConcurrency(rows, getEntLoaderPrivacyConcurrencyLimit(), async (row, idx) => {
|
|
192
|
+
return (0, async_utils_1.mapWithConcurrency)(rows, getEntLoaderPrivacyConcurrencyLimit(), async (row, idx) => {
|
|
222
193
|
// db error
|
|
223
194
|
if (rowIsError(row)) {
|
|
224
195
|
if (row instanceof Error) {
|
|
@@ -239,7 +210,7 @@ function createEntLoader(viewer, options, map) {
|
|
|
239
210
|
}
|
|
240
211
|
return r;
|
|
241
212
|
});
|
|
242
|
-
}, loaderOptions);
|
|
213
|
+
}, loaderOptions, tableName);
|
|
243
214
|
}
|
|
244
215
|
class EntLoader {
|
|
245
216
|
constructor(viewer, options) {
|
|
@@ -637,13 +608,13 @@ async function loadRow(options) {
|
|
|
637
608
|
return row;
|
|
638
609
|
}
|
|
639
610
|
}
|
|
640
|
-
const
|
|
641
|
-
logQuery(query,
|
|
611
|
+
const queryData = (0, query_impl_1.buildQueryData)(options);
|
|
612
|
+
logQuery(queryData.query, queryData.logValues);
|
|
642
613
|
const pool = db_1.default.getInstance().getPool();
|
|
643
|
-
const res = await pool.query(query,
|
|
614
|
+
const res = await pool.query(queryData.query, queryData.values);
|
|
644
615
|
if (res.rowCount != 1) {
|
|
645
616
|
if (res.rowCount > 1) {
|
|
646
|
-
(0, logger_1.log)("error", "got more than one row for query " + query);
|
|
617
|
+
(0, logger_1.log)("error", "got more than one row for query " + queryData.query);
|
|
647
618
|
}
|
|
648
619
|
return null;
|
|
649
620
|
}
|
|
@@ -682,8 +653,8 @@ async function loadRows(options) {
|
|
|
682
653
|
return rows;
|
|
683
654
|
}
|
|
684
655
|
}
|
|
685
|
-
const
|
|
686
|
-
const r = await performRawQuery(query,
|
|
656
|
+
const queryData = (0, query_impl_1.buildQueryData)(options);
|
|
657
|
+
const r = await performRawQuery(queryData.query, queryData.values, queryData.logValues);
|
|
687
658
|
if (cache) {
|
|
688
659
|
// put the rows in the cache...
|
|
689
660
|
cache.primeCache(options, r);
|
|
@@ -692,6 +663,12 @@ async function loadRows(options) {
|
|
|
692
663
|
}
|
|
693
664
|
// this is used for queries when we select multiple ids at once
|
|
694
665
|
function buildGroupQuery(options) {
|
|
666
|
+
if (options.fields.some((field) => typeof field === "object" && "expression" in field)) {
|
|
667
|
+
throw new Error("group queries do not support computed select expressions");
|
|
668
|
+
}
|
|
669
|
+
if (options.orderby && (0, query_impl_1.orderByHasExpressions)(options.orderby)) {
|
|
670
|
+
throw new Error("group queries do not support computed order expressions");
|
|
671
|
+
}
|
|
695
672
|
const fields = [...options.fields, "row_number()"];
|
|
696
673
|
let cls = clause.In(options.groupColumn, ...options.values);
|
|
697
674
|
if (options.clause) {
|
|
@@ -930,6 +907,14 @@ class AssocEdge {
|
|
|
930
907
|
}
|
|
931
908
|
}
|
|
932
909
|
exports.AssocEdge = AssocEdge;
|
|
910
|
+
// UTF-8-safe cursor encoding (btoa only supports Latin-1 code units).
|
|
911
|
+
function encodeCursorPayload(json) {
|
|
912
|
+
return Buffer.from(json, "utf8").toString("base64");
|
|
913
|
+
}
|
|
914
|
+
// Inverse of encodeCursorPayload; exported for pagination decode in query.ts
|
|
915
|
+
function decodeCursorPayload(encoded) {
|
|
916
|
+
return Buffer.from(encoded, "base64").toString("utf8");
|
|
917
|
+
}
|
|
933
918
|
// TODO eventually update this for sortCol time unique keys
|
|
934
919
|
function getCursor(opts) {
|
|
935
920
|
const { row, cursorKeys, rowKeys } = opts;
|
|
@@ -947,7 +932,7 @@ function getCursor(opts) {
|
|
|
947
932
|
const rowKey = rowKeys?.[i] || cursorKey;
|
|
948
933
|
parts.push([cursorKey, convert(row[rowKey])]);
|
|
949
934
|
}
|
|
950
|
-
return
|
|
935
|
+
return encodeCursorPayload(JSON.stringify(parts));
|
|
951
936
|
}
|
|
952
937
|
class AssocEdgeData {
|
|
953
938
|
constructor(data) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Pool } from "pg";
|
|
2
|
+
import type { RuntimeDBExtension } from "./config";
|
|
3
|
+
import type { ResolvedDevSchema } from "./dev_schema";
|
|
4
|
+
export interface InstalledDBExtension {
|
|
5
|
+
name: string;
|
|
6
|
+
version: string;
|
|
7
|
+
installSchema?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ExtensionTypeParser {
|
|
10
|
+
name: string;
|
|
11
|
+
parse(value: string | null): unknown;
|
|
12
|
+
}
|
|
13
|
+
export interface ExtensionRuntimeHandler {
|
|
14
|
+
name: string;
|
|
15
|
+
runtimeSchemas?: string[];
|
|
16
|
+
types?: ExtensionTypeParser[];
|
|
17
|
+
validate?(installed: InstalledDBExtension, extension: RuntimeDBExtension): void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export declare function registerExtensionRuntime(handler: ExtensionRuntimeHandler): void;
|
|
20
|
+
export declare function clearExtensionRuntimes(): void;
|
|
21
|
+
export declare function normalizeExtensions(extensions: RuntimeDBExtension[]): RuntimeDBExtension[];
|
|
22
|
+
export declare function resolveExtensions(cfg?: RuntimeDBExtension[]): RuntimeDBExtension[];
|
|
23
|
+
export declare function getExtensionSearchPathSchemas(extensions: RuntimeDBExtension[]): string[];
|
|
24
|
+
export declare function buildExtensionSearchPath(resolvedDevSchema: ResolvedDevSchema, extensions: RuntimeDBExtension[]): string | undefined;
|
|
25
|
+
export declare function initializeExtensions(pool: Pick<Pool, "query">, extensions: RuntimeDBExtension[]): Promise<void>;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerExtensionRuntime = registerExtensionRuntime;
|
|
4
|
+
exports.clearExtensionRuntimes = clearExtensionRuntimes;
|
|
5
|
+
exports.normalizeExtensions = normalizeExtensions;
|
|
6
|
+
exports.resolveExtensions = resolveExtensions;
|
|
7
|
+
exports.getExtensionSearchPathSchemas = getExtensionSearchPathSchemas;
|
|
8
|
+
exports.buildExtensionSearchPath = buildExtensionSearchPath;
|
|
9
|
+
exports.initializeExtensions = initializeExtensions;
|
|
10
|
+
const pg_1 = require("pg");
|
|
11
|
+
const TEXT_ARRAY_OID = 1009;
|
|
12
|
+
const runtimeHandlers = new Map();
|
|
13
|
+
const registeredTypeOIDs = new Set();
|
|
14
|
+
function normalizeProvisionedBy(extension) {
|
|
15
|
+
if (extension.provisionedBy === "ent" ||
|
|
16
|
+
extension.provisionedBy === "external") {
|
|
17
|
+
return extension.provisionedBy;
|
|
18
|
+
}
|
|
19
|
+
if (extension.provisionedBy) {
|
|
20
|
+
throw new Error(`invalid provisionedBy ${extension.provisionedBy} for db extension ${extension.name}`);
|
|
21
|
+
}
|
|
22
|
+
return "ent";
|
|
23
|
+
}
|
|
24
|
+
function normalizeRuntimeHandler(handler) {
|
|
25
|
+
const typeHandlers = new Map();
|
|
26
|
+
for (const typeHandler of handler.types || []) {
|
|
27
|
+
typeHandlers.set(typeHandler.name, typeHandler);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
...handler,
|
|
31
|
+
runtimeSchemas: [...new Set(handler.runtimeSchemas || [])],
|
|
32
|
+
types: [...typeHandlers.values()],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function mergeRuntimeHandlers(lhs, rhs) {
|
|
36
|
+
const mergedTypes = new Map();
|
|
37
|
+
for (const typeHandler of lhs.types || []) {
|
|
38
|
+
mergedTypes.set(typeHandler.name, typeHandler);
|
|
39
|
+
}
|
|
40
|
+
for (const typeHandler of rhs.types || []) {
|
|
41
|
+
mergedTypes.set(typeHandler.name, typeHandler);
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
name: rhs.name,
|
|
45
|
+
runtimeSchemas: [
|
|
46
|
+
...new Set([
|
|
47
|
+
...(lhs.runtimeSchemas || []),
|
|
48
|
+
...(rhs.runtimeSchemas || []),
|
|
49
|
+
]),
|
|
50
|
+
],
|
|
51
|
+
types: [...mergedTypes.values()],
|
|
52
|
+
validate: rhs.validate || lhs.validate,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function getRegisteredRuntimeHandlers() {
|
|
56
|
+
return [...runtimeHandlers.values()].sort((lhs, rhs) => lhs.name.localeCompare(rhs.name));
|
|
57
|
+
}
|
|
58
|
+
function registerExtensionRuntime(handler) {
|
|
59
|
+
const normalized = normalizeRuntimeHandler(handler);
|
|
60
|
+
const existing = runtimeHandlers.get(normalized.name);
|
|
61
|
+
runtimeHandlers.set(normalized.name, existing ? mergeRuntimeHandlers(existing, normalized) : normalized);
|
|
62
|
+
}
|
|
63
|
+
function clearExtensionRuntimes() {
|
|
64
|
+
runtimeHandlers.clear();
|
|
65
|
+
registeredTypeOIDs.clear();
|
|
66
|
+
}
|
|
67
|
+
function normalizeExtensions(extensions) {
|
|
68
|
+
return [...extensions]
|
|
69
|
+
.map((extension) => ({
|
|
70
|
+
...extension,
|
|
71
|
+
provisionedBy: normalizeProvisionedBy(extension),
|
|
72
|
+
runtimeSchemas: extension.runtimeSchemas || [],
|
|
73
|
+
dropCascade: extension.dropCascade === true,
|
|
74
|
+
}))
|
|
75
|
+
.sort((lhs, rhs) => lhs.name.localeCompare(rhs.name));
|
|
76
|
+
}
|
|
77
|
+
function resolveExtensions(cfg) {
|
|
78
|
+
return normalizeExtensions(cfg || []);
|
|
79
|
+
}
|
|
80
|
+
function getExtensionSearchPathSchemas(extensions) {
|
|
81
|
+
const normalizedExtensions = normalizeExtensions(extensions);
|
|
82
|
+
const configuredExtensions = new Map(normalizedExtensions.map((extension) => [extension.name, extension]));
|
|
83
|
+
const seen = new Set();
|
|
84
|
+
const schemas = [];
|
|
85
|
+
function addSchemas(runtimeSchemas) {
|
|
86
|
+
for (const schema of runtimeSchemas) {
|
|
87
|
+
if (!schema || seen.has(schema)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
seen.add(schema);
|
|
91
|
+
schemas.push(schema);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const extension of normalizedExtensions) {
|
|
95
|
+
addSchemas(extension.runtimeSchemas || []);
|
|
96
|
+
}
|
|
97
|
+
for (const handler of getRegisteredRuntimeHandlers()) {
|
|
98
|
+
const configured = configuredExtensions.get(handler.name);
|
|
99
|
+
addSchemas(configured
|
|
100
|
+
? configured.runtimeSchemas || []
|
|
101
|
+
: handler.runtimeSchemas || []);
|
|
102
|
+
}
|
|
103
|
+
return schemas;
|
|
104
|
+
}
|
|
105
|
+
function buildExtensionSearchPath(resolvedDevSchema, extensions) {
|
|
106
|
+
const schemas = [];
|
|
107
|
+
if (resolvedDevSchema.enabled && resolvedDevSchema.schemaName) {
|
|
108
|
+
schemas.push(resolvedDevSchema.schemaName);
|
|
109
|
+
}
|
|
110
|
+
for (const schema of getExtensionSearchPathSchemas(extensions)) {
|
|
111
|
+
if (!schemas.includes(schema)) {
|
|
112
|
+
schemas.push(schema);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (resolvedDevSchema.enabled &&
|
|
116
|
+
resolvedDevSchema.includePublic &&
|
|
117
|
+
!schemas.includes("public")) {
|
|
118
|
+
schemas.push("public");
|
|
119
|
+
}
|
|
120
|
+
if (!resolvedDevSchema.enabled &&
|
|
121
|
+
schemas.length > 0 &&
|
|
122
|
+
!schemas.includes("public")) {
|
|
123
|
+
schemas.push("public");
|
|
124
|
+
}
|
|
125
|
+
if (schemas.length === 0) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
return schemas.join(",");
|
|
129
|
+
}
|
|
130
|
+
async function getInstalledExtensions(pool, extensions) {
|
|
131
|
+
if (extensions.length === 0) {
|
|
132
|
+
return new Map();
|
|
133
|
+
}
|
|
134
|
+
const res = await pool.query(`
|
|
135
|
+
SELECT
|
|
136
|
+
extname,
|
|
137
|
+
extversion,
|
|
138
|
+
extnamespace::regnamespace::text AS install_schema
|
|
139
|
+
FROM pg_extension
|
|
140
|
+
WHERE extname = ANY($1::text[])
|
|
141
|
+
`, [extensions.map((extension) => extension.name)]);
|
|
142
|
+
const installed = new Map();
|
|
143
|
+
for (const row of res.rows) {
|
|
144
|
+
installed.set(row.extname, {
|
|
145
|
+
name: row.extname,
|
|
146
|
+
version: row.extversion,
|
|
147
|
+
installSchema: row.install_schema,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return installed;
|
|
151
|
+
}
|
|
152
|
+
function registerArrayParser(arrayOID, parse) {
|
|
153
|
+
if (!arrayOID || registeredTypeOIDs.has(arrayOID)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const parseTextArray = pg_1.types.getTypeParser(TEXT_ARRAY_OID);
|
|
157
|
+
pg_1.types.setTypeParser(arrayOID, (value) => {
|
|
158
|
+
if (value === null) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const parsed = parseTextArray(value);
|
|
162
|
+
return parsed.map((entry) => parse(entry));
|
|
163
|
+
});
|
|
164
|
+
registeredTypeOIDs.add(arrayOID);
|
|
165
|
+
}
|
|
166
|
+
async function initializeRegisteredTypeParsers(pool, configuredExtensions) {
|
|
167
|
+
const registeredTypes = new Map();
|
|
168
|
+
for (const handler of getRegisteredRuntimeHandlers()) {
|
|
169
|
+
for (const typeHandler of handler.types || []) {
|
|
170
|
+
registeredTypes.set(typeHandler.name, {
|
|
171
|
+
extensionName: handler.name,
|
|
172
|
+
parse: typeHandler.parse,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (registeredTypes.size === 0) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const res = await pool.query(`
|
|
180
|
+
SELECT oid, typname, typarray
|
|
181
|
+
FROM pg_type
|
|
182
|
+
WHERE typname = ANY($1::text[])
|
|
183
|
+
`, [[...registeredTypes.keys()]]);
|
|
184
|
+
const rowsByType = new Map(res.rows.map((row) => [row.typname, row]));
|
|
185
|
+
for (const [typeName, typeHandler] of registeredTypes.entries()) {
|
|
186
|
+
const row = rowsByType.get(typeName);
|
|
187
|
+
if (!row) {
|
|
188
|
+
if (configuredExtensions.has(typeHandler.extensionName)) {
|
|
189
|
+
throw new Error(`required pg type "${typeName}" for db extension "${typeHandler.extensionName}" was not found`);
|
|
190
|
+
}
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (!registeredTypeOIDs.has(row.oid)) {
|
|
194
|
+
pg_1.types.setTypeParser(row.oid, typeHandler.parse);
|
|
195
|
+
registeredTypeOIDs.add(row.oid);
|
|
196
|
+
}
|
|
197
|
+
registerArrayParser(row.typarray, typeHandler.parse);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async function initializeExtensions(pool, extensions) {
|
|
201
|
+
const normalizedExtensions = normalizeExtensions(extensions);
|
|
202
|
+
const configuredExtensions = new Map(normalizedExtensions.map((extension) => [extension.name, extension]));
|
|
203
|
+
const installedExtensions = await getInstalledExtensions(pool, normalizedExtensions);
|
|
204
|
+
for (const extension of normalizedExtensions) {
|
|
205
|
+
const installed = installedExtensions.get(extension.name);
|
|
206
|
+
if (!installed) {
|
|
207
|
+
throw new Error(`required db extension "${extension.name}" is not installed`);
|
|
208
|
+
}
|
|
209
|
+
if (extension.version && extension.version !== installed.version) {
|
|
210
|
+
throw new Error(`required db extension "${extension.name}" version "${extension.version}" but found "${installed.version}"`);
|
|
211
|
+
}
|
|
212
|
+
if (extension.installSchema &&
|
|
213
|
+
extension.installSchema !== installed.installSchema) {
|
|
214
|
+
throw new Error(`required db extension "${extension.name}" install schema "${extension.installSchema}" but found "${installed.installSchema}"`);
|
|
215
|
+
}
|
|
216
|
+
const handler = runtimeHandlers.get(extension.name);
|
|
217
|
+
await handler?.validate?.(installed, extension);
|
|
218
|
+
}
|
|
219
|
+
await initializeRegisteredTypeParsers(pool, configuredExtensions);
|
|
220
|
+
}
|
|
@@ -32,23 +32,20 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.AssocEdgeCountLoaderFactory = exports.AssocEdgeCountLoader = void 0;
|
|
40
37
|
const ent_1 = require("../ent");
|
|
41
38
|
const clause = __importStar(require("../clause"));
|
|
42
39
|
const loader_1 = require("./loader");
|
|
43
40
|
const raw_count_loader_1 = require("./raw_count_loader");
|
|
44
|
-
const
|
|
41
|
+
const memoize_1 = require("../memoize");
|
|
45
42
|
class AssocEdgeCountLoader {
|
|
46
43
|
constructor(edgeType, context, options) {
|
|
47
44
|
this.edgeType = edgeType;
|
|
48
45
|
this.context = context;
|
|
49
46
|
this.options = options;
|
|
50
47
|
if (context) {
|
|
51
|
-
this.loaderFn = (0,
|
|
48
|
+
this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
51
|
async getLoader() {
|
|
@@ -63,7 +60,7 @@ class AssocEdgeCountLoader {
|
|
|
63
60
|
tableName: edgeData.edgeTable,
|
|
64
61
|
groupCol: "id1",
|
|
65
62
|
clause: cls,
|
|
66
|
-
});
|
|
63
|
+
}, this.context);
|
|
67
64
|
return this.loader;
|
|
68
65
|
}
|
|
69
66
|
async load(id) {
|
|
@@ -23,7 +23,10 @@ export declare class AssocDirectEdgeLoader<T extends AssocEdge> implements Loade
|
|
|
23
23
|
private edgeCtr;
|
|
24
24
|
private options?;
|
|
25
25
|
context?: Context | undefined;
|
|
26
|
+
private loader;
|
|
27
|
+
private loaderFn;
|
|
26
28
|
constructor(edgeType: string, edgeCtr: AssocEdgeConstructor<T>, options?: EdgeQueryableDataOptions | undefined, context?: Context | undefined);
|
|
29
|
+
private getLoader;
|
|
27
30
|
load(id: ID): Promise<T[]>;
|
|
28
31
|
loadTwoWay(id: ID): Promise<T[]>;
|
|
29
32
|
loadEdgeForID2(id: ID, id2: ID): Promise<T | undefined>;
|
|
@@ -32,17 +32,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
36
|
exports.AssocEdgeLoaderFactory = exports.AssocDirectEdgeLoader = exports.AssocEdgeLoader = void 0;
|
|
40
|
-
const dataloader_1 = __importDefault(require("dataloader"));
|
|
41
|
-
const memoizee_1 = __importDefault(require("memoizee"));
|
|
42
37
|
const clause = __importStar(require("../clause"));
|
|
43
38
|
const ent_1 = require("../ent");
|
|
44
|
-
const
|
|
45
|
-
const
|
|
39
|
+
const memoize_1 = require("../memoize");
|
|
40
|
+
const query_impl_1 = require("../query_impl");
|
|
46
41
|
const loader_1 = require("./loader");
|
|
47
42
|
function getDefaultOrderBy() {
|
|
48
43
|
return [
|
|
@@ -60,16 +55,15 @@ function getEffectiveOptions(options) {
|
|
|
60
55
|
disableTransformations: options.disableTransformations ?? false,
|
|
61
56
|
};
|
|
62
57
|
}
|
|
63
|
-
function createLoader(options, edgeType, edgeCtr, edgeData) {
|
|
58
|
+
function createLoader(options, edgeType, edgeCtr, edgeData, context) {
|
|
59
|
+
const loaderName = `assocEdgeLoader:${edgeType}`;
|
|
64
60
|
const loaderOptions = {
|
|
65
61
|
maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
|
|
66
|
-
|
|
67
|
-
if ((0, logger_1.logEnabled)("query")) {
|
|
68
|
-
loaderOptions.cacheMap = new loader_1.CacheMap({
|
|
62
|
+
cacheMap: (0, loader_1.createLoaderCacheMap)({
|
|
69
63
|
tableName: edgeData.edgeTable,
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
return new
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
return new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
|
|
73
67
|
if (keys.length === 1) {
|
|
74
68
|
// 1 key, just be simple and move on
|
|
75
69
|
// same as AssocDirectEdgeLoader
|
|
@@ -77,6 +71,7 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
|
|
|
77
71
|
id1: keys[0],
|
|
78
72
|
edgeType: edgeType,
|
|
79
73
|
queryOptions: options,
|
|
74
|
+
context,
|
|
80
75
|
ctr: edgeCtr,
|
|
81
76
|
});
|
|
82
77
|
return [r];
|
|
@@ -115,7 +110,7 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
|
|
|
115
110
|
result[idx].push(new edgeCtr(row));
|
|
116
111
|
}
|
|
117
112
|
return result;
|
|
118
|
-
}, loaderOptions);
|
|
113
|
+
}, loaderOptions, edgeData.edgeTable);
|
|
119
114
|
}
|
|
120
115
|
class AssocEdgeLoader {
|
|
121
116
|
constructor(edgeType, edgeCtr, options, context) {
|
|
@@ -123,14 +118,14 @@ class AssocEdgeLoader {
|
|
|
123
118
|
this.edgeCtr = edgeCtr;
|
|
124
119
|
this.options = options;
|
|
125
120
|
this.context = context;
|
|
126
|
-
this.loaderFn = (0,
|
|
121
|
+
this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
|
|
127
122
|
}
|
|
128
123
|
async getLoader() {
|
|
129
124
|
const edgeData = await (0, ent_1.loadEdgeData)(this.edgeType);
|
|
130
125
|
if (!edgeData) {
|
|
131
126
|
throw new Error(`error loading edge data for ${this.edgeType}`);
|
|
132
127
|
}
|
|
133
|
-
this.loader = createLoader(this.options, this.edgeType, this.edgeCtr, edgeData);
|
|
128
|
+
this.loader = createLoader(this.options, this.edgeType, this.edgeCtr, edgeData, this.context);
|
|
134
129
|
return this.loader;
|
|
135
130
|
}
|
|
136
131
|
async load(id) {
|
|
@@ -168,8 +163,40 @@ class AssocDirectEdgeLoader {
|
|
|
168
163
|
this.edgeCtr = edgeCtr;
|
|
169
164
|
this.options = options;
|
|
170
165
|
this.context = context;
|
|
166
|
+
if (this.context) {
|
|
167
|
+
this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async getLoader() {
|
|
171
|
+
if (this.loader) {
|
|
172
|
+
return this.loader;
|
|
173
|
+
}
|
|
174
|
+
const edgeData = await (0, ent_1.loadEdgeData)(this.edgeType);
|
|
175
|
+
if (!edgeData) {
|
|
176
|
+
throw new Error(`error loading edge data for ${this.edgeType}`);
|
|
177
|
+
}
|
|
178
|
+
const loaderName = `assocDirectEdgeLoader:${this.edgeType}`;
|
|
179
|
+
this.loader = new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
|
|
180
|
+
return Promise.all(keys.map((id) => (0, ent_1.loadCustomEdges)({
|
|
181
|
+
id1: id,
|
|
182
|
+
edgeType: this.edgeType,
|
|
183
|
+
context: this.context,
|
|
184
|
+
queryOptions: this.options,
|
|
185
|
+
ctr: this.edgeCtr,
|
|
186
|
+
})));
|
|
187
|
+
}, {
|
|
188
|
+
maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
|
|
189
|
+
cacheMap: (0, loader_1.createLoaderCacheMap)({
|
|
190
|
+
tableName: edgeData.edgeTable,
|
|
191
|
+
}),
|
|
192
|
+
}, edgeData.edgeTable);
|
|
193
|
+
return this.loader;
|
|
171
194
|
}
|
|
172
195
|
async load(id) {
|
|
196
|
+
if (this.loaderFn) {
|
|
197
|
+
const loader = await this.loaderFn();
|
|
198
|
+
return loader.load(id);
|
|
199
|
+
}
|
|
173
200
|
return (0, ent_1.loadCustomEdges)({
|
|
174
201
|
id1: id,
|
|
175
202
|
edgeType: this.edgeType,
|
|
@@ -197,7 +224,9 @@ class AssocDirectEdgeLoader {
|
|
|
197
224
|
ctr: this.edgeCtr,
|
|
198
225
|
});
|
|
199
226
|
}
|
|
200
|
-
clearAll() {
|
|
227
|
+
clearAll() {
|
|
228
|
+
this.loader && this.loader.clearAll();
|
|
229
|
+
}
|
|
201
230
|
}
|
|
202
231
|
exports.AssocDirectEdgeLoader = AssocDirectEdgeLoader;
|
|
203
232
|
class AssocEdgeLoaderFactory {
|
|
@@ -232,7 +261,7 @@ class AssocEdgeLoaderFactory {
|
|
|
232
261
|
return new AssocDirectEdgeLoader(this.edgeType, edgeCtr, options, context);
|
|
233
262
|
}
|
|
234
263
|
const effectiveOptions = getEffectiveOptions(options);
|
|
235
|
-
const key = `${this.name}:limit:${effectiveOptions.limit}:orderby:${(0,
|
|
264
|
+
const key = `${this.name}:limit:${effectiveOptions.limit}:orderby:${(0, query_impl_1.getOrderByKey)(effectiveOptions.orderby ?? getDefaultOrderBy())}:disableTransformations:${effectiveOptions.disableTransformations}`;
|
|
236
265
|
return (0, loader_1.getCustomLoader)(key, () => new AssocEdgeLoader(this.edgeType, ctr, effectiveOptions, context), context);
|
|
237
266
|
}
|
|
238
267
|
}
|
package/core/loaders/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { RawCountLoader, RawCountLoaderFactory } from "./raw_count_loader";
|
|
|
3
3
|
export { AssocEdgeCountLoader, AssocEdgeCountLoaderFactory, } from "./assoc_count_loader";
|
|
4
4
|
export { AssocDirectEdgeLoader, AssocEdgeLoader, AssocEdgeLoaderFactory, } from "./assoc_edge_loader";
|
|
5
5
|
export { QueryLoaderFactory } from "./query_loader";
|
|
6
|
-
export { getLoaderMaxBatchSize, setLoaderMaxBatchSize } from "./loader";
|
|
6
|
+
export { getLoaderCacheMaxEntries, getLoaderMaxBatchSize, setLoaderCacheMaxEntries, setLoaderMaxBatchSize, } from "./loader";
|
|
7
|
+
export { setClauseLoaderConcurrency } from "./object_loader";
|
package/core/loaders/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setLoaderMaxBatchSize = exports.getLoaderMaxBatchSize = exports.QueryLoaderFactory = exports.AssocEdgeLoaderFactory = exports.AssocEdgeLoader = exports.AssocDirectEdgeLoader = exports.AssocEdgeCountLoaderFactory = exports.AssocEdgeCountLoader = exports.RawCountLoaderFactory = exports.RawCountLoader = exports.ObjectLoaderFactory = exports.ObjectLoader = void 0;
|
|
3
|
+
exports.setClauseLoaderConcurrency = exports.setLoaderMaxBatchSize = exports.setLoaderCacheMaxEntries = exports.getLoaderMaxBatchSize = exports.getLoaderCacheMaxEntries = exports.QueryLoaderFactory = exports.AssocEdgeLoaderFactory = exports.AssocEdgeLoader = exports.AssocDirectEdgeLoader = exports.AssocEdgeCountLoaderFactory = exports.AssocEdgeCountLoader = exports.RawCountLoaderFactory = exports.RawCountLoader = exports.ObjectLoaderFactory = exports.ObjectLoader = void 0;
|
|
4
4
|
var object_loader_1 = require("./object_loader");
|
|
5
5
|
Object.defineProperty(exports, "ObjectLoader", { enumerable: true, get: function () { return object_loader_1.ObjectLoader; } });
|
|
6
6
|
Object.defineProperty(exports, "ObjectLoaderFactory", { enumerable: true, get: function () { return object_loader_1.ObjectLoaderFactory; } });
|
|
@@ -17,5 +17,9 @@ Object.defineProperty(exports, "AssocEdgeLoaderFactory", { enumerable: true, get
|
|
|
17
17
|
var query_loader_1 = require("./query_loader");
|
|
18
18
|
Object.defineProperty(exports, "QueryLoaderFactory", { enumerable: true, get: function () { return query_loader_1.QueryLoaderFactory; } });
|
|
19
19
|
var loader_1 = require("./loader");
|
|
20
|
+
Object.defineProperty(exports, "getLoaderCacheMaxEntries", { enumerable: true, get: function () { return loader_1.getLoaderCacheMaxEntries; } });
|
|
20
21
|
Object.defineProperty(exports, "getLoaderMaxBatchSize", { enumerable: true, get: function () { return loader_1.getLoaderMaxBatchSize; } });
|
|
22
|
+
Object.defineProperty(exports, "setLoaderCacheMaxEntries", { enumerable: true, get: function () { return loader_1.setLoaderCacheMaxEntries; } });
|
|
21
23
|
Object.defineProperty(exports, "setLoaderMaxBatchSize", { enumerable: true, get: function () { return loader_1.setLoaderMaxBatchSize; } });
|
|
24
|
+
var object_loader_2 = require("./object_loader");
|
|
25
|
+
Object.defineProperty(exports, "setClauseLoaderConcurrency", { enumerable: true, get: function () { return object_loader_2.setClauseLoaderConcurrency; } });
|