@snowtop/ent 0.2.5 → 0.2.7
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/action.js +5 -5
- package/action/executor.d.ts +1 -1
- package/action/executor.js +4 -4
- package/action/experimental_action.js +5 -5
- package/action/operations.js +17 -7
- package/action/orchestrator.d.ts +2 -2
- package/action/orchestrator.js +17 -7
- package/action/privacy.d.ts +2 -2
- package/action/relative_value.js +3 -3
- package/auth/auth.d.ts +0 -1
- package/auth/auth.js +4 -5
- package/core/async_utils.d.ts +1 -0
- package/core/async_utils.js +29 -0
- package/core/base.d.ts +1 -1
- package/core/base.js +5 -5
- package/core/cache_utils.d.ts +1 -0
- package/core/cache_utils.js +28 -0
- package/core/clause.js +76 -67
- package/core/config.d.ts +3 -1
- package/core/config.js +29 -9
- package/core/context.d.ts +3 -2
- package/core/context.js +96 -25
- package/core/convert.d.ts +0 -1
- package/core/convert.js +16 -17
- package/core/date.js +1 -2
- package/core/db.js +17 -7
- package/core/ent.d.ts +4 -2
- package/core/ent.js +111 -106
- package/core/global_schema.js +6 -7
- package/core/loaders/assoc_count_loader.d.ts +2 -2
- package/core/loaders/assoc_count_loader.js +18 -8
- package/core/loaders/assoc_edge_loader.d.ts +5 -2
- package/core/loaders/assoc_edge_loader.js +87 -31
- package/core/loaders/index.d.ts +2 -0
- package/core/loaders/index.js +8 -1
- package/core/loaders/loader.d.ts +33 -0
- package/core/loaders/loader.js +159 -3
- package/core/loaders/object_loader.d.ts +7 -5
- package/core/loaders/object_loader.js +97 -74
- package/core/loaders/query_loader.d.ts +2 -2
- package/core/loaders/query_loader.js +60 -24
- package/core/loaders/raw_count_loader.d.ts +4 -4
- package/core/loaders/raw_count_loader.js +34 -24
- package/core/logger.js +6 -7
- package/core/metrics.d.ts +22 -0
- package/core/metrics.js +31 -0
- package/core/privacy.d.ts +2 -2
- package/core/privacy.js +4 -5
- package/core/query/assoc_query.js +17 -7
- package/core/query/query.js +17 -7
- package/core/query/shared_assoc_test.js +1 -2
- package/core/query_impl.js +4 -5
- package/core/viewer.d.ts +2 -2
- package/graphql/graphql_field_helpers.js +22 -22
- package/graphql/mutations/union.js +1 -2
- package/graphql/node_resolver.js +7 -7
- package/graphql/query/shared_assoc_test.js +1 -2
- package/graphql/scalars/date.js +8 -3
- package/graphql/scalars/time.d.ts +1 -1
- package/imports/dataz/example1/_auth.js +14 -10
- package/imports/index.js +18 -9
- package/index.d.ts +2 -1
- package/index.js +22 -9
- package/names/names.js +61 -18
- package/package.json +14 -17
- package/parse_schema/parse.js +2 -3
- package/schema/binary_field.js +3 -3
- package/schema/field.js +45 -35
- package/schema/json_field.js +7 -7
- package/schema/schema.js +12 -12
- package/schema/struct_field.js +4 -4
- package/schema/union_field.js +3 -3
- package/scripts/custom_compiler.js +17 -7
- package/scripts/custom_graphql.js +17 -7
- package/scripts/fix_action_exports.js +17 -7
- package/scripts/move_types.js +17 -7
- package/scripts/read_schema.js +17 -7
- package/testutils/action/complex_schemas.js +28 -18
- package/testutils/builder.d.ts +1 -1
- package/testutils/builder.js +7 -7
- package/testutils/db/fixture.js +1 -2
- package/testutils/db/temp_db.js +54 -44
- package/testutils/db/value.js +3 -4
- package/testutils/db_mock.js +12 -0
- package/testutils/ent-graphql-tests/index.d.ts +3 -3
- package/testutils/ent-graphql-tests/index.js +27 -18
- package/testutils/fake_data/const.js +2 -2
- package/testutils/fake_data/fake_contact.js +20 -10
- package/testutils/fake_data/fake_event.js +20 -10
- package/testutils/fake_data/fake_tag.js +21 -11
- package/testutils/fake_data/fake_user.js +21 -11
- package/testutils/fake_data/test_helpers.js +17 -17
- package/testutils/fake_data/user_query.js +19 -9
- package/testutils/parse_sql.js +151 -43
- package/testutils/query.js +2 -3
- package/testutils/soft_delete.js +17 -7
- package/testutils/test_edge_global_schema.js +17 -7
- package/testutils/write.js +20 -11
- package/tsc/ast.js +27 -18
- package/tsc/compilerOptions.js +22 -13
- package/tsc/move_generated.js +18 -9
- package/tsc/transform.js +18 -9
- package/tsc/transform_action.js +17 -7
- package/tsc/transform_schema.js +17 -7
|
@@ -15,32 +15,58 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
28
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
39
|
exports.AssocEdgeLoaderFactory = exports.AssocDirectEdgeLoader = exports.AssocEdgeLoader = void 0;
|
|
30
|
-
const dataloader_1 = __importDefault(require("dataloader"));
|
|
31
40
|
const memoizee_1 = __importDefault(require("memoizee"));
|
|
32
41
|
const clause = __importStar(require("../clause"));
|
|
33
42
|
const ent_1 = require("../ent");
|
|
34
|
-
const
|
|
43
|
+
const cache_utils_1 = require("../cache_utils");
|
|
35
44
|
const loader_1 = require("./loader");
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
function getDefaultOrderBy() {
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
column: "time",
|
|
49
|
+
direction: "DESC",
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
function getEffectiveOptions(options) {
|
|
54
|
+
return {
|
|
55
|
+
...options,
|
|
56
|
+
orderby: options.orderby ?? getDefaultOrderBy(),
|
|
57
|
+
limit: options.limit || (0, ent_1.getDefaultLimit)(),
|
|
58
|
+
disableTransformations: options.disableTransformations ?? false,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function createLoader(options, edgeType, edgeCtr, edgeData, context) {
|
|
62
|
+
const loaderName = `assocEdgeLoader:${edgeType}`;
|
|
63
|
+
const loaderOptions = {
|
|
64
|
+
maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
|
|
65
|
+
cacheMap: (0, loader_1.createLoaderCacheMap)({
|
|
40
66
|
tableName: edgeData.edgeTable,
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
return new
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
return new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
|
|
44
70
|
if (keys.length === 1) {
|
|
45
71
|
// 1 key, just be simple and move on
|
|
46
72
|
// same as AssocDirectEdgeLoader
|
|
@@ -48,6 +74,7 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
|
|
|
48
74
|
id1: keys[0],
|
|
49
75
|
edgeType: edgeType,
|
|
50
76
|
queryOptions: options,
|
|
77
|
+
context,
|
|
51
78
|
ctr: edgeCtr,
|
|
52
79
|
});
|
|
53
80
|
return [r];
|
|
@@ -59,14 +86,9 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
|
|
|
59
86
|
// store the index....
|
|
60
87
|
m.set(keys[i], i);
|
|
61
88
|
}
|
|
62
|
-
|
|
63
|
-
{
|
|
64
|
-
column: "time",
|
|
65
|
-
direction: "DESC",
|
|
66
|
-
},
|
|
67
|
-
];
|
|
89
|
+
const orderby = options.orderby ?? getDefaultOrderBy();
|
|
68
90
|
// TODO defaultEdgeQueryOptions
|
|
69
|
-
|
|
91
|
+
const limit = options.limit || (0, ent_1.getDefaultLimit)();
|
|
70
92
|
const tableName = edgeData.edgeTable;
|
|
71
93
|
const { cls: cls1, fields } = (0, ent_1.getEdgeClauseAndFields)(clause.Eq("edge_type", edgeType), {
|
|
72
94
|
queryOptions: options,
|
|
@@ -75,8 +97,8 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
|
|
|
75
97
|
tableName: tableName,
|
|
76
98
|
fields,
|
|
77
99
|
values: keys,
|
|
78
|
-
orderby
|
|
79
|
-
limit
|
|
100
|
+
orderby,
|
|
101
|
+
limit,
|
|
80
102
|
groupColumn: "id1",
|
|
81
103
|
clause: cls1,
|
|
82
104
|
});
|
|
@@ -91,7 +113,7 @@ function createLoader(options, edgeType, edgeCtr, edgeData) {
|
|
|
91
113
|
result[idx].push(new edgeCtr(row));
|
|
92
114
|
}
|
|
93
115
|
return result;
|
|
94
|
-
}, loaderOptions);
|
|
116
|
+
}, loaderOptions, edgeData.edgeTable);
|
|
95
117
|
}
|
|
96
118
|
class AssocEdgeLoader {
|
|
97
119
|
constructor(edgeType, edgeCtr, options, context) {
|
|
@@ -106,7 +128,7 @@ class AssocEdgeLoader {
|
|
|
106
128
|
if (!edgeData) {
|
|
107
129
|
throw new Error(`error loading edge data for ${this.edgeType}`);
|
|
108
130
|
}
|
|
109
|
-
this.loader = createLoader(this.options, this.edgeType, this.edgeCtr, edgeData);
|
|
131
|
+
this.loader = createLoader(this.options, this.edgeType, this.edgeCtr, edgeData, this.context);
|
|
110
132
|
return this.loader;
|
|
111
133
|
}
|
|
112
134
|
async load(id) {
|
|
@@ -144,8 +166,40 @@ class AssocDirectEdgeLoader {
|
|
|
144
166
|
this.edgeCtr = edgeCtr;
|
|
145
167
|
this.options = options;
|
|
146
168
|
this.context = context;
|
|
169
|
+
if (this.context) {
|
|
170
|
+
this.loaderFn = (0, memoizee_1.default)(this.getLoader);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async getLoader() {
|
|
174
|
+
if (this.loader) {
|
|
175
|
+
return this.loader;
|
|
176
|
+
}
|
|
177
|
+
const edgeData = await (0, ent_1.loadEdgeData)(this.edgeType);
|
|
178
|
+
if (!edgeData) {
|
|
179
|
+
throw new Error(`error loading edge data for ${this.edgeType}`);
|
|
180
|
+
}
|
|
181
|
+
const loaderName = `assocDirectEdgeLoader:${this.edgeType}`;
|
|
182
|
+
this.loader = new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
|
|
183
|
+
return Promise.all(keys.map((id) => (0, ent_1.loadCustomEdges)({
|
|
184
|
+
id1: id,
|
|
185
|
+
edgeType: this.edgeType,
|
|
186
|
+
context: this.context,
|
|
187
|
+
queryOptions: this.options,
|
|
188
|
+
ctr: this.edgeCtr,
|
|
189
|
+
})));
|
|
190
|
+
}, {
|
|
191
|
+
maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
|
|
192
|
+
cacheMap: (0, loader_1.createLoaderCacheMap)({
|
|
193
|
+
tableName: edgeData.edgeTable,
|
|
194
|
+
}),
|
|
195
|
+
}, edgeData.edgeTable);
|
|
196
|
+
return this.loader;
|
|
147
197
|
}
|
|
148
198
|
async load(id) {
|
|
199
|
+
if (this.loaderFn) {
|
|
200
|
+
const loader = await this.loaderFn();
|
|
201
|
+
return loader.load(id);
|
|
202
|
+
}
|
|
149
203
|
return (0, ent_1.loadCustomEdges)({
|
|
150
204
|
id1: id,
|
|
151
205
|
edgeType: this.edgeType,
|
|
@@ -173,7 +227,9 @@ class AssocDirectEdgeLoader {
|
|
|
173
227
|
ctr: this.edgeCtr,
|
|
174
228
|
});
|
|
175
229
|
}
|
|
176
|
-
clearAll() {
|
|
230
|
+
clearAll() {
|
|
231
|
+
this.loader && this.loader.clearAll();
|
|
232
|
+
}
|
|
177
233
|
}
|
|
178
234
|
exports.AssocDirectEdgeLoader = AssocDirectEdgeLoader;
|
|
179
235
|
class AssocEdgeLoaderFactory {
|
|
@@ -207,9 +263,9 @@ class AssocEdgeLoaderFactory {
|
|
|
207
263
|
if (options?.clause || !context) {
|
|
208
264
|
return new AssocDirectEdgeLoader(this.edgeType, edgeCtr, options, context);
|
|
209
265
|
}
|
|
210
|
-
|
|
211
|
-
const key = `${this.name}:limit:${
|
|
212
|
-
return (0, loader_1.getCustomLoader)(key, () => new AssocEdgeLoader(this.edgeType, ctr,
|
|
266
|
+
const effectiveOptions = getEffectiveOptions(options);
|
|
267
|
+
const key = `${this.name}:limit:${effectiveOptions.limit}:orderby:${(0, cache_utils_1.stableStringify)(effectiveOptions.orderby)}:disableTransformations:${effectiveOptions.disableTransformations}`;
|
|
268
|
+
return (0, loader_1.getCustomLoader)(key, () => new AssocEdgeLoader(this.edgeType, ctr, effectiveOptions, context), context);
|
|
213
269
|
}
|
|
214
270
|
}
|
|
215
271
|
exports.AssocEdgeLoaderFactory = AssocEdgeLoaderFactory;
|
package/core/loaders/index.d.ts
CHANGED
|
@@ -3,3 +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 { 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.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; } });
|
|
@@ -16,3 +16,10 @@ Object.defineProperty(exports, "AssocEdgeLoader", { enumerable: true, get: funct
|
|
|
16
16
|
Object.defineProperty(exports, "AssocEdgeLoaderFactory", { enumerable: true, get: function () { return assoc_edge_loader_1.AssocEdgeLoaderFactory; } });
|
|
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
|
+
var loader_1 = require("./loader");
|
|
20
|
+
Object.defineProperty(exports, "getLoaderCacheMaxEntries", { enumerable: true, get: function () { return loader_1.getLoaderCacheMaxEntries; } });
|
|
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; } });
|
|
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; } });
|
package/core/loaders/loader.d.ts
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
|
+
import DataLoader from "dataloader";
|
|
1
2
|
import { Loader, LoaderFactory, Context, DataOptions } from "../base";
|
|
3
|
+
export declare function getLoaderMaxBatchSize(): number;
|
|
4
|
+
export declare function setLoaderMaxBatchSize(size?: number | null): void;
|
|
5
|
+
export declare function getLoaderCacheMaxEntries(): number;
|
|
6
|
+
export declare function setLoaderCacheMaxEntries(size?: number | null): void;
|
|
2
7
|
export declare function getLoader<K, V>(factory: LoaderFactory<K, V>, create: () => Loader<K, V>, context?: Context): Loader<K, V>;
|
|
3
8
|
export declare function getCustomLoader<K, V>(key: string, create: () => Loader<K, V>, context?: Context): Loader<K, V>;
|
|
9
|
+
export type CacheMapLike<K, V> = {
|
|
10
|
+
get(key: K): V | undefined;
|
|
11
|
+
set(key: K, value: V): any;
|
|
12
|
+
delete(key: K): any;
|
|
13
|
+
clear(): any;
|
|
14
|
+
};
|
|
15
|
+
type CacheKeyFn<K> = (key: K) => any;
|
|
16
|
+
type BatchLoadFn<K, V> = (keys: readonly K[]) => PromiseLike<ArrayLike<V | Error>>;
|
|
17
|
+
export declare class InstrumentedDataLoader<K, V> extends DataLoader<K, V> {
|
|
18
|
+
constructor(loaderName: string, batchLoadFn: BatchLoadFn<K, V>, options: DataLoader.Options<K, V>, tableName?: string, cacheKeyFn?: (key: K) => unknown);
|
|
19
|
+
}
|
|
20
|
+
export declare class BoundedCacheMap<K, V> {
|
|
21
|
+
private cacheMap;
|
|
22
|
+
private maxEntries;
|
|
23
|
+
private cacheKeyFn?;
|
|
24
|
+
private order;
|
|
25
|
+
constructor(cacheMap: CacheMapLike<K, V>, maxEntries: number, cacheKeyFn?: CacheKeyFn<K> | undefined);
|
|
26
|
+
private normalizeKey;
|
|
27
|
+
private touch;
|
|
28
|
+
private evictIfNeeded;
|
|
29
|
+
get(key: K): V | undefined;
|
|
30
|
+
set(key: K, value: V): any;
|
|
31
|
+
delete(key: K): any;
|
|
32
|
+
clear(): any;
|
|
33
|
+
}
|
|
34
|
+
export declare function createBoundedCacheMap<K, V>(cacheMap: CacheMapLike<K, V>, cacheKeyFn?: CacheKeyFn<K>): CacheMapLike<K, V>;
|
|
35
|
+
export declare function createLoaderCacheMap<K, V>(options: DataOptions): CacheMapLike<K, V>;
|
|
4
36
|
export declare class CacheMap {
|
|
5
37
|
private options;
|
|
6
38
|
private m;
|
|
@@ -10,3 +42,4 @@ export declare class CacheMap {
|
|
|
10
42
|
delete(key: any): boolean;
|
|
11
43
|
clear(): void;
|
|
12
44
|
}
|
|
45
|
+
export {};
|
package/core/loaders/loader.js
CHANGED
|
@@ -1,7 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CacheMap = exports.
|
|
6
|
+
exports.CacheMap = exports.BoundedCacheMap = exports.InstrumentedDataLoader = void 0;
|
|
7
|
+
exports.getLoaderMaxBatchSize = getLoaderMaxBatchSize;
|
|
8
|
+
exports.setLoaderMaxBatchSize = setLoaderMaxBatchSize;
|
|
9
|
+
exports.getLoaderCacheMaxEntries = getLoaderCacheMaxEntries;
|
|
10
|
+
exports.setLoaderCacheMaxEntries = setLoaderCacheMaxEntries;
|
|
11
|
+
exports.getLoader = getLoader;
|
|
12
|
+
exports.getCustomLoader = getCustomLoader;
|
|
13
|
+
exports.createBoundedCacheMap = createBoundedCacheMap;
|
|
14
|
+
exports.createLoaderCacheMap = createLoaderCacheMap;
|
|
15
|
+
const dataloader_1 = __importDefault(require("dataloader"));
|
|
4
16
|
const logger_1 = require("../logger");
|
|
17
|
+
const metrics_1 = require("../metrics");
|
|
18
|
+
const DEFAULT_MAX_BATCH_SIZE = 1000;
|
|
19
|
+
let loaderMaxBatchSize = DEFAULT_MAX_BATCH_SIZE;
|
|
20
|
+
const DEFAULT_MAX_CACHE_ENTRIES = 1000;
|
|
21
|
+
let loaderCacheMaxEntries = DEFAULT_MAX_CACHE_ENTRIES;
|
|
22
|
+
function getLoaderMaxBatchSize() {
|
|
23
|
+
return loaderMaxBatchSize;
|
|
24
|
+
}
|
|
25
|
+
function setLoaderMaxBatchSize(size) {
|
|
26
|
+
if (size === undefined || size === null) {
|
|
27
|
+
loaderMaxBatchSize = DEFAULT_MAX_BATCH_SIZE;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!Number.isFinite(size) || size <= 0) {
|
|
31
|
+
throw new Error(`maxBatchSize must be a positive number`);
|
|
32
|
+
}
|
|
33
|
+
loaderMaxBatchSize = Math.floor(size);
|
|
34
|
+
}
|
|
35
|
+
function getLoaderCacheMaxEntries() {
|
|
36
|
+
return loaderCacheMaxEntries;
|
|
37
|
+
}
|
|
38
|
+
function setLoaderCacheMaxEntries(size) {
|
|
39
|
+
if (size === undefined || size === null) {
|
|
40
|
+
loaderCacheMaxEntries = DEFAULT_MAX_CACHE_ENTRIES;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (!Number.isFinite(size) || size < 0) {
|
|
44
|
+
throw new Error(`maxCacheEntries must be a non-negative number`);
|
|
45
|
+
}
|
|
46
|
+
loaderCacheMaxEntries = Math.floor(size);
|
|
47
|
+
}
|
|
5
48
|
// this is like factory factory FML
|
|
6
49
|
// helper function to handle context vs not
|
|
7
50
|
// and to keep the API clean for clients who shouldn't have to worry about this
|
|
@@ -14,7 +57,6 @@ function getLoader(factory, create, context) {
|
|
|
14
57
|
// g|set from context cache
|
|
15
58
|
return context.cache.getLoader(factory.name, create);
|
|
16
59
|
}
|
|
17
|
-
exports.getLoader = getLoader;
|
|
18
60
|
function getCustomLoader(key, create, context) {
|
|
19
61
|
// just create a new one every time if no context cache
|
|
20
62
|
if (!context?.cache) {
|
|
@@ -24,7 +66,121 @@ function getCustomLoader(key, create, context) {
|
|
|
24
66
|
// g|set from context cache
|
|
25
67
|
return context.cache.getLoader(key, create);
|
|
26
68
|
}
|
|
27
|
-
|
|
69
|
+
function instrumentCacheMap(cacheMap, tableName, cacheKeyFn) {
|
|
70
|
+
if (!cacheMap || !tableName) {
|
|
71
|
+
return cacheMap;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
get(key) {
|
|
75
|
+
const value = cacheMap.get(key);
|
|
76
|
+
if (value !== undefined) {
|
|
77
|
+
const hook = (0, metrics_1.getOnDataLoaderCacheHit)();
|
|
78
|
+
if (hook) {
|
|
79
|
+
hook({
|
|
80
|
+
tableName,
|
|
81
|
+
key: cacheKeyFn ? cacheKeyFn(key) : key,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
},
|
|
87
|
+
set(key, value) {
|
|
88
|
+
return cacheMap.set(key, value);
|
|
89
|
+
},
|
|
90
|
+
delete(key) {
|
|
91
|
+
return cacheMap.delete(key);
|
|
92
|
+
},
|
|
93
|
+
clear() {
|
|
94
|
+
return cacheMap.clear();
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
class InstrumentedDataLoader extends dataloader_1.default {
|
|
99
|
+
constructor(loaderName, batchLoadFn, options, tableName, cacheKeyFn) {
|
|
100
|
+
const wrappedBatchFn = async (keys) => {
|
|
101
|
+
if (keys.length) {
|
|
102
|
+
const hook = (0, metrics_1.getOnDataLoaderBatch)();
|
|
103
|
+
if (hook) {
|
|
104
|
+
hook({
|
|
105
|
+
loaderName,
|
|
106
|
+
batchSize: keys.length,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return batchLoadFn(keys);
|
|
111
|
+
};
|
|
112
|
+
const cacheMap = instrumentCacheMap(options.cacheMap, tableName, cacheKeyFn);
|
|
113
|
+
const loaderOptions = cacheMap === options.cacheMap ? options : { ...options, cacheMap };
|
|
114
|
+
super(wrappedBatchFn, loaderOptions);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.InstrumentedDataLoader = InstrumentedDataLoader;
|
|
118
|
+
class BoundedCacheMap {
|
|
119
|
+
constructor(cacheMap, maxEntries, cacheKeyFn) {
|
|
120
|
+
this.cacheMap = cacheMap;
|
|
121
|
+
this.maxEntries = maxEntries;
|
|
122
|
+
this.cacheKeyFn = cacheKeyFn;
|
|
123
|
+
this.order = new Map();
|
|
124
|
+
}
|
|
125
|
+
normalizeKey(key) {
|
|
126
|
+
return this.cacheKeyFn ? this.cacheKeyFn(key) : key;
|
|
127
|
+
}
|
|
128
|
+
touch(normalizedKey, key) {
|
|
129
|
+
if (this.order.has(normalizedKey)) {
|
|
130
|
+
this.order.delete(normalizedKey);
|
|
131
|
+
}
|
|
132
|
+
this.order.set(normalizedKey, key);
|
|
133
|
+
}
|
|
134
|
+
evictIfNeeded() {
|
|
135
|
+
while (this.order.size > this.maxEntries) {
|
|
136
|
+
const oldest = this.order.entries().next().value;
|
|
137
|
+
if (!oldest) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const [normalizedKey, key] = oldest;
|
|
141
|
+
this.order.delete(normalizedKey);
|
|
142
|
+
this.cacheMap.delete(key);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
get(key) {
|
|
146
|
+
const value = this.cacheMap.get(key);
|
|
147
|
+
if (value !== undefined) {
|
|
148
|
+
const normalizedKey = this.normalizeKey(key);
|
|
149
|
+
this.touch(normalizedKey, key);
|
|
150
|
+
}
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
set(key, value) {
|
|
154
|
+
const normalizedKey = this.normalizeKey(key);
|
|
155
|
+
this.touch(normalizedKey, key);
|
|
156
|
+
const result = this.cacheMap.set(key, value);
|
|
157
|
+
this.evictIfNeeded();
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
delete(key) {
|
|
161
|
+
const normalizedKey = this.normalizeKey(key);
|
|
162
|
+
this.order.delete(normalizedKey);
|
|
163
|
+
return this.cacheMap.delete(key);
|
|
164
|
+
}
|
|
165
|
+
clear() {
|
|
166
|
+
this.order.clear();
|
|
167
|
+
return this.cacheMap.clear();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.BoundedCacheMap = BoundedCacheMap;
|
|
171
|
+
function createBoundedCacheMap(cacheMap, cacheKeyFn) {
|
|
172
|
+
const maxEntries = getLoaderCacheMaxEntries();
|
|
173
|
+
if (maxEntries <= 0) {
|
|
174
|
+
return cacheMap;
|
|
175
|
+
}
|
|
176
|
+
return new BoundedCacheMap(cacheMap, maxEntries, cacheKeyFn);
|
|
177
|
+
}
|
|
178
|
+
function createLoaderCacheMap(options) {
|
|
179
|
+
const baseMap = (0, logger_1.logEnabled)("query")
|
|
180
|
+
? new CacheMap(options)
|
|
181
|
+
: new Map();
|
|
182
|
+
return createBoundedCacheMap(baseMap);
|
|
183
|
+
}
|
|
28
184
|
class CacheMap {
|
|
29
185
|
constructor(options) {
|
|
30
186
|
this.options = options;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { ID, Data, SelectDataOptions, Context, Loader, LoaderFactory } from "../base";
|
|
2
|
+
import { mapWithConcurrency } from "../async_utils";
|
|
2
3
|
import * as clause from "../clause";
|
|
4
|
+
export declare function setClauseLoaderConcurrency(limit: number): void;
|
|
5
|
+
export { mapWithConcurrency };
|
|
3
6
|
export declare class ObjectLoader<TQueryData extends Data = Data, TResultData extends Data = TQueryData, K = keyof TQueryData> implements Loader<ID, TResultData | null>, Loader<clause.Clause<TQueryData, K>, TResultData[] | null> {
|
|
4
7
|
private options;
|
|
5
|
-
context?: Context
|
|
8
|
+
context?: Context | undefined;
|
|
6
9
|
private toPrime?;
|
|
7
10
|
private idLoader;
|
|
8
11
|
private clauseLoader;
|
|
9
12
|
private primedLoaders;
|
|
10
13
|
private memoizedInitPrime;
|
|
11
|
-
constructor(options: SelectDataOptions, context?: Context
|
|
14
|
+
constructor(options: SelectDataOptions, context?: Context | undefined, toPrime?: ObjectLoaderFactory<TResultData>[] | undefined);
|
|
12
15
|
getOptions(): SelectDataOptions;
|
|
13
16
|
private initPrime;
|
|
14
17
|
load(key: ID): Promise<TResultData | null>;
|
|
@@ -25,9 +28,9 @@ export declare class ObjectLoader<TQueryData extends Data = Data, TResultData ex
|
|
|
25
28
|
}
|
|
26
29
|
export declare class ObjectCountLoader<V extends Data = Data, K = keyof V> implements Loader<clause.Clause<V, K>, number> {
|
|
27
30
|
private options;
|
|
28
|
-
context?: Context
|
|
31
|
+
context?: Context | undefined;
|
|
29
32
|
private loader;
|
|
30
|
-
constructor(options: SelectDataOptions, context?: Context
|
|
33
|
+
constructor(options: SelectDataOptions, context?: Context | undefined);
|
|
31
34
|
getOptions(): SelectDataOptions;
|
|
32
35
|
load(key: clause.Clause<V, K>): Promise<number>;
|
|
33
36
|
clearAll(): void;
|
|
@@ -46,4 +49,3 @@ export declare class ObjectLoaderFactory<V extends Data = Data> implements Loade
|
|
|
46
49
|
createCountLoader<K = keyof V>(context?: Context): ObjectCountLoader<V, K>;
|
|
47
50
|
addToPrime(factory: ObjectLoaderFactory<V>): this;
|
|
48
51
|
}
|
|
49
|
-
export {};
|