orchid-graphql 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,432 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ createGraphResolver: () => createGraphResolver,
24
+ cursor: () => defineCursorPaginator,
25
+ defineCursorPaginator: () => defineCursorPaginator,
26
+ defineFieldResolver: () => defineFieldResolver,
27
+ definePageResolver: () => definePageResolver,
28
+ defineRelationResolver: () => defineRelationResolver,
29
+ defineTableResolver: () => defineTableResolver,
30
+ field: () => defineFieldResolver,
31
+ graph: () => createGraphResolver,
32
+ page: () => definePageResolver,
33
+ relation: () => defineRelationResolver,
34
+ table: () => defineTableResolver
35
+ });
36
+ module.exports = __toCommonJS(src_exports);
37
+
38
+ // src/paginators/base.ts
39
+ var s = Symbol();
40
+ function set_query_page_result(query, get_page) {
41
+ function _get_page(data) {
42
+ if (!Array.isArray(data)) {
43
+ throw new Error(`Paginator called for single result query.`);
44
+ }
45
+ return get_page(data);
46
+ }
47
+ const { handleResult } = query.query;
48
+ query.query.handleResult = (...args) => {
49
+ const data = handleResult(...args);
50
+ return _get_page(data);
51
+ };
52
+ query.query[s] = _get_page;
53
+ return query;
54
+ }
55
+ function get_query_pagination_handler(query) {
56
+ return query.query[s];
57
+ }
58
+
59
+ // src/paginators/cursor.ts
60
+ function defineCursorPaginator(options = {}) {
61
+ return new CursorPaginator(options);
62
+ }
63
+ var CursorPaginator = class {
64
+ path = ["nodes"];
65
+ options;
66
+ fields;
67
+ constructor(options = {}) {
68
+ this.options = {
69
+ fields: ["id"],
70
+ take: 10,
71
+ ...options
72
+ };
73
+ this.fields = this.options.fields.map((field) => {
74
+ if (field.startsWith("-")) {
75
+ return { name: field.slice(1), desc: true };
76
+ } else {
77
+ return { name: field, desc: false };
78
+ }
79
+ });
80
+ }
81
+ paginate(query, args = {}) {
82
+ const take = args.take ?? this.options.take;
83
+ const { cursor } = args;
84
+ console.log("paginating query", query);
85
+ query = query.clear("order");
86
+ for (const field of this.fields) {
87
+ query = query.select(field.name).order({ [field.name]: field.desc ? "DESC" : "ASC" });
88
+ }
89
+ if (cursor) {
90
+ query = this._set_query_cursor(query, cursor);
91
+ }
92
+ query = query.limit(take + 1);
93
+ query = set_query_page_result(query, (nodes) => {
94
+ let cursor2;
95
+ if (nodes.length > take) {
96
+ cursor2 = this._create_cursor(nodes[take - 1]);
97
+ nodes = nodes.slice(0, take);
98
+ }
99
+ return { nodes, cursor: cursor2 };
100
+ });
101
+ return query;
102
+ }
103
+ _create_cursor(instance) {
104
+ return JSON.stringify(
105
+ this.fields.map((field) => {
106
+ const value = instance[field.name];
107
+ if (value === void 0) {
108
+ throw new Error(
109
+ `Unable to create cursor: undefined field ${field.name}`
110
+ );
111
+ }
112
+ return String(value);
113
+ })
114
+ );
115
+ }
116
+ _set_query_cursor(query, cursor) {
117
+ const values = JSON.parse(cursor);
118
+ const left = [];
119
+ const right = [];
120
+ const expr_values = {};
121
+ for (let i = 0; i < this.fields.length; ++i) {
122
+ const field = this.fields[i];
123
+ const expressions = field.desc ? right : left;
124
+ const placeholders = field.desc ? left : right;
125
+ expressions.push(`"${field.name}"`);
126
+ const placeholder = `value${i}`;
127
+ placeholders.push("$" + placeholder);
128
+ expr_values[placeholder] = values[i];
129
+ }
130
+ return query.where(
131
+ query.raw(`(${left.join(",")}) > (${right.join(",")})`, expr_values)
132
+ );
133
+ }
134
+ };
135
+
136
+ // src/utils/query-context.ts
137
+ var graphql = Symbol("graphql");
138
+ function set_query_context(query, context) {
139
+ ;
140
+ query.query[graphql] = context;
141
+ }
142
+ function get_query_context(query) {
143
+ return query.query[graphql];
144
+ }
145
+
146
+ // src/utils/run-after.ts
147
+ function run_after_query(query, transform) {
148
+ return query.afterQuery(async (_, result) => {
149
+ if (Array.isArray(result)) {
150
+ const result1 = await Promise.all(result.map(transform));
151
+ return result1.filter(Boolean);
152
+ } else if (result) {
153
+ return transform(result);
154
+ } else {
155
+ return result;
156
+ }
157
+ });
158
+ }
159
+
160
+ // src/resolvers/field.ts
161
+ function defineFieldResolver(options = {}) {
162
+ const { tableField, modify, transform } = options;
163
+ return function resolve(query, options2) {
164
+ const { field } = options2;
165
+ if (modify) {
166
+ return modify(query, options2);
167
+ } else {
168
+ query = query.select({ [field]: tableField || field });
169
+ }
170
+ if (transform) {
171
+ const context = get_query_context(query);
172
+ query = run_after_query(query, async (instance) => {
173
+ instance[field] = await transform(instance[field], instance, context);
174
+ return instance;
175
+ });
176
+ }
177
+ return query;
178
+ };
179
+ }
180
+
181
+ // src/resolvers/graph.ts
182
+ var import_graphql_parse_resolve_info = require("graphql-parse-resolve-info");
183
+ function createGraphResolver(types, options) {
184
+ return new GraphResolver(types, options);
185
+ }
186
+ var GraphResolver = class {
187
+ constructor(tables, options = {}) {
188
+ this.tables = tables;
189
+ this.options = options;
190
+ }
191
+ resolve(query, { info, context, filters }) {
192
+ set_query_context(query, context);
193
+ const tree = this._get_resolve_tree(info);
194
+ return this._resolve_type({ query, tree, filters });
195
+ }
196
+ resolvePage(query, paginator, { info, context, filters }) {
197
+ set_query_context(query, context);
198
+ const tree = this._get_resolve_tree(info);
199
+ return this._resolve_page({ query, tree, paginator, filters });
200
+ }
201
+ _get_resolve_tree(info) {
202
+ return (0, import_graphql_parse_resolve_info.parseResolveInfo)(info);
203
+ }
204
+ _resolve_type({
205
+ tree,
206
+ query,
207
+ filters
208
+ }) {
209
+ const type = Object.keys(tree.fieldsByTypeName)[0];
210
+ const table_resolver = this.tables[type];
211
+ if (!table_resolver) {
212
+ throw new Error(`Table resolver not found for type ${type}.`);
213
+ }
214
+ return table_resolver({ tree, type, query, filters, graph: this });
215
+ }
216
+ _resolve_page({
217
+ tree,
218
+ query,
219
+ paginator,
220
+ filters
221
+ }) {
222
+ const { args } = tree;
223
+ for (const field of paginator.path) {
224
+ const type = Object.keys(tree.fieldsByTypeName)[0];
225
+ tree = tree.fieldsByTypeName[type][field];
226
+ }
227
+ query = this._resolve_type({ query, tree, filters });
228
+ return paginator.paginate(query, args);
229
+ }
230
+ };
231
+
232
+ // src/resolvers/page.ts
233
+ var import_pqb = require("pqb");
234
+ function definePageResolver(paginator, options = {}) {
235
+ const { tableField, filters, modify } = options;
236
+ return defineFieldResolver({
237
+ modify: (query, { field, tree, graph }) => query.select({
238
+ [field]: (q) => {
239
+ const page_query = graph._resolve_page({
240
+ tree,
241
+ query: q[tableField || field],
242
+ paginator,
243
+ filters
244
+ });
245
+ const get_page = get_query_pagination_handler(page_query);
246
+ (0, import_pqb.addParserToQuery)(page_query.query, field, get_page);
247
+ return modify ? modify(page_query, tree) : page_query;
248
+ }
249
+ })
250
+ });
251
+ }
252
+
253
+ // src/resolvers/relation.ts
254
+ function defineRelationResolver(options = {}) {
255
+ const { tableField, filters, modify } = options;
256
+ return defineFieldResolver({
257
+ modify: (query, { field, tree, graph }) => query.select({
258
+ [field]: (q) => {
259
+ const relation_query = graph._resolve_type({
260
+ tree,
261
+ query: q[tableField || field],
262
+ filters
263
+ });
264
+ return modify ? modify(relation_query, tree) : relation_query;
265
+ }
266
+ })
267
+ });
268
+ }
269
+
270
+ // src/utils/is-plain-object.ts
271
+ function is_plain_object(obj) {
272
+ return typeof obj === "object" && !Array.isArray(obj);
273
+ }
274
+
275
+ // src/filters/filters.ts
276
+ function is_scalar(value) {
277
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
278
+ }
279
+ function apply_filters({
280
+ query,
281
+ filters,
282
+ args,
283
+ modifiers
284
+ }) {
285
+ if (!filters) {
286
+ return query;
287
+ }
288
+ const filter_obj = args?.filter;
289
+ if (!filter_obj) {
290
+ return query;
291
+ }
292
+ if (!is_plain_object(filter_obj)) {
293
+ throw new Error(`Invalid filter: ${filter_obj}, must be object.`);
294
+ }
295
+ for (const [field, value] of Object.entries(filter_obj)) {
296
+ if (value === void 0) {
297
+ continue;
298
+ }
299
+ if (modifiers?.[field]) {
300
+ query = modifiers[field](query, value);
301
+ } else {
302
+ const [dbfield, op0] = field.split("__");
303
+ const op = op0?.toLowerCase() || "exact";
304
+ if (
305
+ // TODO: add the rest of orchid ops (or allow all of them?)
306
+ [
307
+ "exact",
308
+ "lt",
309
+ "lte",
310
+ "gt",
311
+ "gte",
312
+ "like",
313
+ "ilike",
314
+ "contains"
315
+ ].includes(op)
316
+ ) {
317
+ if (!is_scalar(value)) {
318
+ throw new Error(
319
+ `Unsupported filter value for ${query.table}.${field}: must be scalar.`
320
+ );
321
+ }
322
+ if (op === "exact") {
323
+ query = query.where({ [dbfield]: value });
324
+ } else {
325
+ const query_op = { like: "contains" }[op] || op;
326
+ query = query.where({ [dbfield]: { [query_op]: value } });
327
+ }
328
+ } else if (op === "in") {
329
+ if (!(Array.isArray(value) && value.every(is_scalar))) {
330
+ throw new Error(
331
+ `Invalid filter value for ${query.table}.${field}: must be an array of scalars.`
332
+ );
333
+ }
334
+ query = query.whereIn(dbfield, value);
335
+ } else {
336
+ throw new Error(
337
+ `Invalid filter ${query.table}.${field}: unsupported operator ${op}.`
338
+ );
339
+ }
340
+ }
341
+ }
342
+ return query;
343
+ }
344
+
345
+ // src/resolvers/table.ts
346
+ function defineTableResolver(table, options = {}) {
347
+ const get_default_field_resolver = (field, tableField) => {
348
+ const table_field_lookup = tableField || field;
349
+ if (options.modifiers?.[table_field_lookup]) {
350
+ return (query) => query;
351
+ } else if (table.relations?.[table_field_lookup]) {
352
+ return defineRelationResolver({ tableField });
353
+ } else {
354
+ return defineFieldResolver({ tableField });
355
+ }
356
+ };
357
+ const { fields } = options;
358
+ const table_field_resolvers = fields ? Object.keys(fields).reduce(
359
+ (resolvers, field) => {
360
+ const r0 = fields[field];
361
+ const r = typeof r0 === "function" ? r0 : r0 === true ? get_default_field_resolver(field) : typeof r0 === "string" ? get_default_field_resolver(field, r0) : void 0;
362
+ if (r === void 0) {
363
+ throw new Error(
364
+ `Field resolver must be a function, string, or true; found ${r0}`
365
+ );
366
+ }
367
+ resolvers[field] = r;
368
+ return resolvers;
369
+ },
370
+ {}
371
+ ) : void 0;
372
+ const { modify, transform } = options;
373
+ return function resolve({ tree, type, query, filters, graph }) {
374
+ if (query.table !== table.table) {
375
+ throw new Error(
376
+ `Mismatching query type (expected ${table.table}, found ${query.table}).`
377
+ );
378
+ }
379
+ const allow_all_fields = options.allowAllFields ?? graph.options.allowAllFields ?? table_field_resolvers === void 0;
380
+ if (!allow_all_fields && !table_field_resolvers) {
381
+ throw new Error(
382
+ `Table resolver for ${type} must either allow all fields or specify options.fields`
383
+ );
384
+ }
385
+ if (modify) {
386
+ query = modify(query, tree);
387
+ }
388
+ for (const subtree of Object.values(tree.fieldsByTypeName[type])) {
389
+ const field = subtree.name;
390
+ const r = table_field_resolvers?.[field] || (allow_all_fields ? get_default_field_resolver(field) : void 0);
391
+ if (!r) {
392
+ throw new Error(`No field resolver defined for field ${type}.${field}`);
393
+ }
394
+ if (r) {
395
+ query = r(query, { field, tree: subtree, graph });
396
+ }
397
+ }
398
+ const allow_all_filters = options.allowAllFilters ?? graph.options.allowAllFilters;
399
+ const effective_filters = allow_all_filters ? true : filters;
400
+ if (effective_filters) {
401
+ query = apply_filters({
402
+ query,
403
+ filters: effective_filters,
404
+ args: tree.args,
405
+ modifiers: options.modifiers
406
+ });
407
+ }
408
+ if (transform) {
409
+ const context = get_query_context(query);
410
+ query = run_after_query(query, (instance) => {
411
+ return transform(instance, context);
412
+ });
413
+ }
414
+ return query;
415
+ };
416
+ }
417
+ // Annotate the CommonJS export names for ESM import in node:
418
+ 0 && (module.exports = {
419
+ createGraphResolver,
420
+ cursor,
421
+ defineCursorPaginator,
422
+ defineFieldResolver,
423
+ definePageResolver,
424
+ defineRelationResolver,
425
+ defineTableResolver,
426
+ field,
427
+ graph,
428
+ page,
429
+ relation,
430
+ table
431
+ });
432
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/paginators/base.ts","../src/paginators/cursor.ts","../src/utils/query-context.ts","../src/utils/run-after.ts","../src/resolvers/field.ts","../src/resolvers/graph.ts","../src/resolvers/page.ts","../src/resolvers/relation.ts","../src/utils/is-plain-object.ts","../src/filters/filters.ts","../src/resolvers/table.ts"],"sourcesContent":["export {\n\tdefineCursorPaginator as cursor,\n\tdefineCursorPaginator,\n} from \"./paginators/cursor\"\nexport {\n\tdefineFieldResolver,\n\tdefineFieldResolver as field,\n} from \"./resolvers/field\"\nexport {\n\tcreateGraphResolver,\n\tcreateGraphResolver as graph,\n} from \"./resolvers/graph\"\nexport {\n\tdefinePageResolver,\n\tdefinePageResolver as page,\n} from \"./resolvers/page\"\nexport {\n\tdefineRelationResolver,\n\tdefineRelationResolver as relation,\n} from \"./resolvers/relation\"\nexport {\n\tdefineTableResolver,\n\tdefineTableResolver as table,\n} from \"./resolvers/table\"\n","import { Query } from \"pqb\"\n\nexport interface Paginator {\n\t/** GraphQL path, for example: `[\"nodes\"]` */\n\treadonly path: string[]\n\tpaginate(query: Query, ...args: any[]): Query\n}\n\ntype GetPageFn<P> = (nodes: any[]) => P\n\nconst s = Symbol()\n\n// FIXME use proper orchid methods, set result type\nexport function set_query_page_result<P>(query: Query, get_page: GetPageFn<P>) {\n\tfunction _get_page(data: any) {\n\t\tif (!Array.isArray(data)) {\n\t\t\tthrow new Error(`Paginator called for single result query.`)\n\t\t}\n\t\treturn get_page(data)\n\t}\n\n\t// For root query\n\tconst { handleResult } = query.query as any\n\t;(query.query as any).handleResult = (...args: any[]) => {\n\t\tconst data = handleResult(...args)\n\t\treturn _get_page(data)\n\t}\n\n\t// For nested query\n\t;(query.query as any)[s] = _get_page\n\n\treturn query\n}\n\nexport function get_query_pagination_handler(query: Query) {\n\treturn (query.query as any)[s]\n}\n","import { Query } from \"pqb\"\n\nimport { Paginator, set_query_page_result } from \"./base\"\n\nexport function defineCursorPaginator(\n\toptions: Partial<CursorPaginatorOptions> = {}\n) {\n\treturn new CursorPaginator(options)\n}\n\nexport interface CursorPaginatorOptions {\n\tfields: string[]\n\ttake: number\n}\n\nexport interface CursorPaginatorArgs {\n\tcursor?: string\n\ttake?: number\n}\n\nexport interface CursorPaginatorPage<M> {\n\tnodes: M[]\n\tcursor?: string\n}\n\nclass CursorPaginator implements Paginator {\n\treadonly path = [\"nodes\"]\n\treadonly options: CursorPaginatorOptions\n\n\treadonly fields: Array<{\n\t\tname: string\n\t\tdesc: boolean\n\t}>\n\n\tconstructor(options: Partial<CursorPaginatorOptions> = {}) {\n\t\tthis.options = {\n\t\t\tfields: [\"id\"],\n\t\t\ttake: 10,\n\t\t\t...options,\n\t\t}\n\t\tthis.fields = this.options.fields.map((field) => {\n\t\t\tif (field.startsWith(\"-\")) {\n\t\t\t\treturn { name: field.slice(1), desc: true }\n\t\t\t} else {\n\t\t\t\treturn { name: field, desc: false }\n\t\t\t}\n\t\t})\n\t}\n\n\tpaginate(query: Query, args: CursorPaginatorArgs = {}) {\n\t\tconst take = args.take ?? this.options.take\n\t\tconst { cursor } = args\n\t\tconsole.log(\"paginating query\", query)\n\n\t\t// Set query order\n\t\tquery = query.clear(\"order\")\n\t\tfor (const field of this.fields) {\n\t\t\t// TODO: prevent potential name clash with aliases like .as(`_${table_ref}_order_key_0`)\n\t\t\tquery = query\n\t\t\t\t.select(field.name)\n\t\t\t\t.order({ [field.name]: field.desc ? \"DESC\" : \"ASC\" })\n\t\t}\n\n\t\tif (cursor) {\n\t\t\tquery = this._set_query_cursor(query, cursor)\n\t\t}\n\t\tquery = query.limit(take + 1)\n\n\t\tquery = set_query_page_result(query, (nodes) => {\n\t\t\tlet cursor: string | undefined\n\t\t\tif (nodes.length > take) {\n\t\t\t\tcursor = this._create_cursor(nodes[take - 1])\n\t\t\t\tnodes = nodes.slice(0, take)\n\t\t\t}\n\t\t\treturn { nodes, cursor }\n\t\t})\n\n\t\treturn query\n\t}\n\n\t_create_cursor(instance: any) {\n\t\treturn JSON.stringify(\n\t\t\tthis.fields.map((field) => {\n\t\t\t\tconst value = instance[field.name]\n\t\t\t\tif (value === undefined) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Unable to create cursor: undefined field ${field.name}`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\treturn String(value)\n\t\t\t})\n\t\t)\n\t}\n\n\t_set_query_cursor(query: Query, cursor: string) {\n\t\tconst values = JSON.parse(cursor)\n\t\tconst left: string[] = []\n\t\tconst right: string[] = []\n\t\tconst expr_values: Record<string, any> = {}\n\t\t// TODO: refactor\n\t\tfor (let i = 0; i < this.fields.length; ++i) {\n\t\t\tconst field = this.fields[i]\n\t\t\tconst expressions = field.desc ? right : left\n\t\t\tconst placeholders = field.desc ? left : right\n\t\t\texpressions.push(`\"${field.name}\"`)\n\t\t\tconst placeholder = `value${i}`\n\t\t\tplaceholders.push(\"$\" + placeholder)\n\t\t\texpr_values[placeholder] = values[i]\n\t\t}\n\t\treturn query.where(\n\t\t\tquery.raw(`(${left.join(\",\")}) > (${right.join(\",\")})`, expr_values)\n\t\t)\n\t}\n}\n","import { Query } from \"pqb\"\n\nconst graphql = Symbol(\"graphql\")\n\nexport function set_query_context(query: Query, context: any) {\n\t;(query.query as any)[graphql] = context\n}\n\nexport function get_query_context(query: Query) {\n\treturn (query.query as any)[graphql]\n}\n","import { Query } from \"pqb\"\n\nexport function run_after_query(\n\tquery: Query,\n\ttransform: (instance: any) => any\n) {\n\treturn query.afterQuery(async (_, result) => {\n\t\t// FIXME: returning is ignored in orchid (unlike objection). Add some hacks instead.\n\t\tif (Array.isArray(result)) {\n\t\t\tconst result1 = await Promise.all(result.map(transform))\n\t\t\treturn result1.filter(Boolean) // Skip empty objects\n\t\t} else if (result) {\n\t\t\treturn transform(result)\n\t\t} else {\n\t\t\t// Supposedly, single query builder returning NULL\n\t\t\treturn result\n\t\t}\n\t})\n}\n","import { ResolveTree } from \"graphql-parse-resolve-info\"\nimport { Query } from \"pqb\"\n\nimport { get_query_context } from \"../utils/query-context\"\nimport { run_after_query } from \"../utils/run-after\"\nimport type { GraphResolver } from \"./graph\"\n\n/* A function that modifies the query to select a field. */\nexport type FieldResolverFn = (\n\tquery: Query,\n\toptions: {\n\t\t/** GraphQL field */\n\t\tfield: string\n\t\t/** GraphQL resolve tree */\n\t\ttree: ResolveTree\n\t\t/** Current graph resolver */\n\t\tgraph: GraphResolver\n\t}\n) => Query\n\nexport interface FieldResolverOptions {\n\t/** Table field (if different from GraphQL field) */\n\ttableField?: string\n\t/** Custom query modifier (if different than simply selecting a field). */\n\tmodify?: FieldResolverFn\n\t/** Post-process selected value. Return a new value or a promise. */\n\ttransform?(value: any, instance: any, context: any): any\n}\n\nexport function defineFieldResolver(\n\toptions: FieldResolverOptions = {}\n): FieldResolverFn {\n\tconst { tableField, modify, transform } = options\n\n\treturn function resolve(query, options) {\n\t\tconst { field } = options\n\t\tif (modify) {\n\t\t\treturn modify(query, options)\n\t\t} else {\n\t\t\tquery = query.select({ [field]: tableField || field })\n\t\t}\n\t\tif (transform) {\n\t\t\tconst context = get_query_context(query)\n\t\t\tquery = run_after_query(query, async (instance) => {\n\t\t\t\tinstance[field] = await transform(instance[field], instance, context)\n\t\t\t\treturn instance\n\t\t\t})\n\t\t}\n\t\treturn query\n\t}\n}\n","import { GraphQLResolveInfo } from \"graphql\"\nimport { parseResolveInfo, ResolveTree } from \"graphql-parse-resolve-info\"\nimport { Query } from \"pqb\"\n\nimport { FiltersDef } from \"../filters/filters\"\nimport { Paginator } from \"../paginators/base\"\nimport { set_query_context } from \"../utils/query-context\"\nimport type { TableResolverFn, TableResolverOptions } from \"./table\"\n\nexport type GraphResolverOptions = Pick<\n\tTableResolverOptions,\n\t\"allowAllFields\" | \"allowAllFilters\"\n>\n\nexport function createGraphResolver(\n\ttypes: Record<string, TableResolverFn>,\n\toptions?: GraphResolverOptions\n) {\n\treturn new GraphResolver(types, options)\n}\n\nexport interface GraphResolveOptions {\n\tinfo: GraphQLResolveInfo\n\tcontext: any\n\tfilters?: FiltersDef\n}\n\nexport class GraphResolver {\n\tconstructor(\n\t\tpublic readonly tables: Record<string, TableResolverFn>,\n\t\tpublic readonly options: GraphResolverOptions = {}\n\t) {}\n\n\tresolve(query: Query, { info, context, filters }: GraphResolveOptions) {\n\t\tset_query_context(query, context)\n\t\tconst tree = this._get_resolve_tree(info)\n\t\treturn this._resolve_type({ query, tree, filters })\n\t}\n\n\tresolvePage(\n\t\tquery: Query,\n\t\tpaginator: Paginator,\n\t\t{ info, context, filters }: GraphResolveOptions\n\t) {\n\t\tset_query_context(query, context)\n\t\tconst tree = this._get_resolve_tree(info)\n\t\treturn this._resolve_page({ query, tree, paginator, filters })\n\t}\n\n\t_get_resolve_tree(info: GraphQLResolveInfo) {\n\t\treturn parseResolveInfo(info) as ResolveTree\n\t}\n\n\t_resolve_type({\n\t\ttree,\n\t\tquery,\n\t\tfilters,\n\t}: {\n\t\tquery: Query\n\t\ttree: ResolveTree\n\t\tfilters?: FiltersDef\n\t}) {\n\t\tconst type = Object.keys(tree.fieldsByTypeName)[0]\n\t\tconst table_resolver = this.tables[type]\n\t\tif (!table_resolver) {\n\t\t\tthrow new Error(`Table resolver not found for type ${type}.`)\n\t\t}\n\t\treturn table_resolver({ tree, type, query, filters, graph: this })\n\t}\n\n\t_resolve_page({\n\t\ttree,\n\t\tquery,\n\t\tpaginator,\n\t\tfilters,\n\t}: {\n\t\tquery: Query\n\t\ttree: ResolveTree\n\t\tpaginator: Paginator\n\t\tfilters?: FiltersDef\n\t}) {\n\t\tconst { args } = tree\n\t\t// Skip page subtree(s)\n\t\tfor (const field of paginator.path) {\n\t\t\tconst type = Object.keys(tree.fieldsByTypeName)[0]\n\t\t\ttree = tree.fieldsByTypeName[type][field]\n\t\t\t// TODO: raise exception if not found\n\t\t}\n\t\tquery = this._resolve_type({ query, tree, filters })\n\t\treturn paginator.paginate(query, args)\n\t}\n}\n","import { addParserToQuery } from \"pqb\"\n\nimport { get_query_pagination_handler, Paginator } from \"../paginators/base\"\nimport { defineFieldResolver } from \"./field\"\nimport { RelationResolverOptions } from \"./relation\"\n\nexport function definePageResolver(\n\tpaginator: Paginator,\n\toptions: RelationResolverOptions = {}\n) {\n\tconst { tableField, filters, modify } = options\n\n\treturn defineFieldResolver({\n\t\tmodify: (query, { field, tree, graph }) =>\n\t\t\tquery.select({\n\t\t\t\t[field]: (q) => {\n\t\t\t\t\tconst page_query = graph._resolve_page({\n\t\t\t\t\t\ttree,\n\t\t\t\t\t\tquery: (q as any)[tableField || field],\n\t\t\t\t\t\tpaginator,\n\t\t\t\t\t\tfilters,\n\t\t\t\t\t})\n\t\t\t\t\tconst get_page = get_query_pagination_handler(page_query)\n\t\t\t\t\taddParserToQuery(page_query.query, field, get_page as any)\n\t\t\t\t\treturn modify ? modify(page_query, tree) : page_query\n\t\t\t\t},\n\t\t\t}),\n\t})\n}\n","import { FiltersDef } from \"../filters/filters\"\nimport { defineFieldResolver, FieldResolverOptions } from \"./field\"\nimport { QueryTreeModifier } from \"./table\"\n\nexport interface RelationResolverOptions\n\textends Omit<FieldResolverOptions, \"modify\"> {\n\tfilters?: FiltersDef\n\tmodify?: QueryTreeModifier\n}\n\nexport function defineRelationResolver(options: RelationResolverOptions = {}) {\n\tconst { tableField, filters, modify } = options\n\n\treturn defineFieldResolver({\n\t\tmodify: (query, { field, tree, graph }) =>\n\t\t\tquery.select({\n\t\t\t\t[field]: (q) => {\n\t\t\t\t\tconst relation_query = graph._resolve_type({\n\t\t\t\t\t\ttree,\n\t\t\t\t\t\tquery: (q as any)[tableField || field],\n\t\t\t\t\t\tfilters,\n\t\t\t\t\t})\n\t\t\t\t\treturn modify ? modify(relation_query, tree) : relation_query\n\t\t\t\t},\n\t\t\t}),\n\t})\n}\n","export function is_plain_object(obj: any): obj is Record<string, any> {\n\treturn typeof obj === \"object\" && !Array.isArray(obj)\n}\n","import { Query } from \"pqb\"\n\nimport { is_plain_object } from \"../utils/is-plain-object\"\nimport { Modifier } from \"../utils/modifier\"\n\n// TODO: per-field definitions\nexport type FiltersDef = boolean\n\nexport type FilterScalarValue = null | string | number | boolean\nexport type FilterValue = FilterScalarValue | Exclude<FilterScalarValue, null>[]\nexport type Filter = { [property: string]: FilterValue }\n\nfunction is_scalar(value: any) {\n\treturn (\n\t\tvalue === null ||\n\t\ttypeof value === \"string\" ||\n\t\ttypeof value === \"number\" ||\n\t\ttypeof value === \"boolean\"\n\t)\n}\n\nexport function apply_filters({\n\tquery,\n\tfilters,\n\targs,\n\tmodifiers,\n}: {\n\tquery: Query\n\tfilters: FiltersDef\n\targs?: Record<string, any>\n\tmodifiers?: Record<string, Modifier>\n}) {\n\tif (!filters) {\n\t\treturn query\n\t}\n\tconst filter_obj = args?.filter\n\tif (!filter_obj) {\n\t\treturn query\n\t}\n\tif (!is_plain_object(filter_obj)) {\n\t\tthrow new Error(`Invalid filter: ${filter_obj}, must be object.`)\n\t}\n\tfor (const [field, value] of Object.entries(filter_obj)) {\n\t\tif (value === undefined) {\n\t\t\t// Support optional GraphQL arguments in filter\n\t\t\tcontinue\n\t\t}\n\t\tif (modifiers?.[field]) {\n\t\t\tquery = modifiers[field](query, value)\n\t\t} else {\n\t\t\t// Normal filter\n\t\t\tconst [dbfield, op0] = field.split(\"__\")\n\t\t\tconst op = op0?.toLowerCase() || \"exact\"\n\t\t\tif (\n\t\t\t\t// TODO: add the rest of orchid ops (or allow all of them?)\n\t\t\t\t[\n\t\t\t\t\t\"exact\",\n\t\t\t\t\t\"lt\",\n\t\t\t\t\t\"lte\",\n\t\t\t\t\t\"gt\",\n\t\t\t\t\t\"gte\",\n\t\t\t\t\t\"like\",\n\t\t\t\t\t\"ilike\",\n\t\t\t\t\t\"contains\",\n\t\t\t\t].includes(op)\n\t\t\t) {\n\t\t\t\tif (!is_scalar(value)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Unsupported filter value for ${query.table}.${field}: must be scalar.`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tif (op === \"exact\") {\n\t\t\t\t\tquery = query.where({ [dbfield]: value })\n\t\t\t\t} else {\n\t\t\t\t\tconst query_op = { like: \"contains\" }[op] || op\n\t\t\t\t\tquery = query.where({ [dbfield]: { [query_op]: value } })\n\t\t\t\t}\n\t\t\t} else if (op === \"in\") {\n\t\t\t\tif (!(Array.isArray(value) && value.every(is_scalar))) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Invalid filter value for ${query.table}.${field}: must be an array of scalars.`\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t\tquery = query.whereIn(dbfield, value)\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid filter ${query.table}.${field}: unsupported operator ${op}.`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\treturn query\n}\n","import { ResolveTree } from \"graphql-parse-resolve-info\"\nimport { DbTable, TableClass } from \"orchid-orm\"\nimport { Query } from \"pqb\"\n\nimport { apply_filters, FiltersDef } from \"../filters/filters\"\nimport { Modifier } from \"../utils/modifier\"\nimport { get_query_context } from \"../utils/query-context\"\nimport { run_after_query } from \"../utils/run-after\"\nimport { defineFieldResolver, FieldResolverFn } from \"./field\"\nimport type { GraphResolver } from \"./graph\"\nimport { defineRelationResolver } from \"./relation\"\n\n/** A function that modifies the query to select fields/relations and filter the result set. */\nexport type TableResolverFn = (args: {\n\ttree: ResolveTree\n\t/** GraphQL type */\n\ttype: string\n\tquery: Query\n\tfilters?: FiltersDef\n\tgraph: GraphResolver\n}) => Query\n\nexport interface TableResolverOptions {\n\t/** allow to resolve all table fields without explicitly listing them */\n\tallowAllFields?: boolean\n\t/** allow to filter all table fields without explicitly listing them */\n\tallowAllFilters?: boolean\n\tfields?: Record<string, SimpleFieldResolver>\n\tmodifiers?: Record<string, Modifier>\n\tmodify?: QueryTreeModifier\n\ttransform?(instance: any, context: any): void | PromiseLike<void>\n}\n\nexport type SimpleFieldResolver = true | string | FieldResolverFn\n\nexport type QueryTreeModifier = (query: Query, tree: ResolveTree) => Query\n\nexport function defineTableResolver<T extends TableClass>(\n\ttable: DbTable<T>,\n\toptions: TableResolverOptions = {}\n): TableResolverFn {\n\t/**\n\t * Create a field resolver which will modify the query to resolve a GraphQL field.\n\t */\n\tconst get_default_field_resolver = (\n\t\tfield: string,\n\t\ttableField?: string\n\t): FieldResolverFn | undefined => {\n\t\tconst table_field_lookup = tableField || field\n\t\tif (options.modifiers?.[table_field_lookup]) {\n\t\t\t// Keep query as is.\n\t\t\treturn (query) => query\n\t\t} else if ((table.relations as any)?.[table_field_lookup]) {\n\t\t\treturn defineRelationResolver({ tableField })\n\t\t} else {\n\t\t\treturn defineFieldResolver({ tableField })\n\t\t}\n\t}\n\n\t// Pre-create field resolvers\n\tconst { fields } = options\n\tconst table_field_resolvers = fields\n\t\t? Object.keys(fields).reduce<Record<string, FieldResolverFn>>(\n\t\t\t\t(resolvers, field) => {\n\t\t\t\t\tconst r0 = fields[field]\n\t\t\t\t\tconst r: FieldResolverFn | undefined =\n\t\t\t\t\t\ttypeof r0 === \"function\"\n\t\t\t\t\t\t\t? r0\n\t\t\t\t\t\t\t: r0 === true\n\t\t\t\t\t\t\t? get_default_field_resolver(field)\n\t\t\t\t\t\t\t: typeof r0 === \"string\"\n\t\t\t\t\t\t\t? get_default_field_resolver(field, r0)\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\tif (r === undefined) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Field resolver must be a function, string, or true; found ${r0}`\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\tresolvers[field] = r\n\t\t\t\t\treturn resolvers\n\t\t\t\t},\n\t\t\t\t{}\n\t\t )\n\t\t: undefined\n\n\tconst { modify, transform } = options\n\n\treturn function resolve({ tree, type, query, filters, graph }) {\n\t\tif (query.table !== table.table) {\n\t\t\tthrow new Error(\n\t\t\t\t`Mismatching query type (expected ${table.table}, found ${query.table}).`\n\t\t\t)\n\t\t}\n\n\t\tconst allow_all_fields =\n\t\t\toptions.allowAllFields ??\n\t\t\tgraph.options.allowAllFields ??\n\t\t\ttable_field_resolvers === undefined\n\n\t\tif (!allow_all_fields && !table_field_resolvers) {\n\t\t\tthrow new Error(\n\t\t\t\t`Table resolver for ${type} must either allow all fields or specify options.fields`\n\t\t\t)\n\t\t}\n\n\t\tif (modify) {\n\t\t\tquery = modify(query, tree)\n\t\t}\n\n\t\tfor (const subtree of Object.values(tree.fieldsByTypeName[type])) {\n\t\t\tconst field = subtree.name\n\t\t\tconst r =\n\t\t\t\ttable_field_resolvers?.[field] ||\n\t\t\t\t(allow_all_fields ? get_default_field_resolver(field) : undefined)\n\t\t\tif (!r) {\n\t\t\t\tthrow new Error(`No field resolver defined for field ${type}.${field}`)\n\t\t\t}\n\t\t\tif (r) {\n\t\t\t\tquery = r(query, { field, tree: subtree, graph })\n\t\t\t}\n\t\t}\n\n\t\tconst allow_all_filters =\n\t\t\toptions.allowAllFilters ?? graph.options.allowAllFilters\n\n\t\tconst effective_filters = allow_all_filters ? true : filters\n\n\t\tif (effective_filters) {\n\t\t\tquery = apply_filters({\n\t\t\t\tquery,\n\t\t\t\tfilters: effective_filters,\n\t\t\t\targs: tree.args,\n\t\t\t\tmodifiers: options.modifiers,\n\t\t\t})\n\t\t}\n\n\t\tif (transform) {\n\t\t\tconst context = get_query_context(query)\n\t\t\tquery = run_after_query(query, (instance) => {\n\t\t\t\treturn transform(instance, context)\n\t\t\t})\n\t\t}\n\n\t\treturn query\n\t}\n}\n"],"mappings":"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","names":["cursor","options"]}
@@ -0,0 +1,115 @@
1
+ import * as pqb from 'pqb';
2
+ import { Query } from 'pqb';
3
+ import { ResolveTree } from 'graphql-parse-resolve-info';
4
+ import { GraphQLResolveInfo } from 'graphql';
5
+ import { TableClass, DbTable } from 'orchid-orm';
6
+
7
+ interface Paginator {
8
+ /** GraphQL path, for example: `["nodes"]` */
9
+ readonly path: string[];
10
+ paginate(query: Query, ...args: any[]): Query;
11
+ }
12
+
13
+ declare function defineCursorPaginator(options?: Partial<CursorPaginatorOptions>): CursorPaginator;
14
+ interface CursorPaginatorOptions {
15
+ fields: string[];
16
+ take: number;
17
+ }
18
+ interface CursorPaginatorArgs {
19
+ cursor?: string;
20
+ take?: number;
21
+ }
22
+ declare class CursorPaginator implements Paginator {
23
+ readonly path: string[];
24
+ readonly options: CursorPaginatorOptions;
25
+ readonly fields: Array<{
26
+ name: string;
27
+ desc: boolean;
28
+ }>;
29
+ constructor(options?: Partial<CursorPaginatorOptions>);
30
+ paginate(query: Query, args?: CursorPaginatorArgs): Query;
31
+ _create_cursor(instance: any): string;
32
+ _set_query_cursor(query: Query, cursor: string): pqb.WhereResult<Query>;
33
+ }
34
+
35
+ type Modifier = (query: Query, param?: any) => Query;
36
+
37
+ type FiltersDef = boolean;
38
+
39
+ /** A function that modifies the query to select fields/relations and filter the result set. */
40
+ type TableResolverFn = (args: {
41
+ tree: ResolveTree;
42
+ /** GraphQL type */
43
+ type: string;
44
+ query: Query;
45
+ filters?: FiltersDef;
46
+ graph: GraphResolver;
47
+ }) => Query;
48
+ interface TableResolverOptions {
49
+ /** allow to resolve all table fields without explicitly listing them */
50
+ allowAllFields?: boolean;
51
+ /** allow to filter all table fields without explicitly listing them */
52
+ allowAllFilters?: boolean;
53
+ fields?: Record<string, SimpleFieldResolver>;
54
+ modifiers?: Record<string, Modifier>;
55
+ modify?: QueryTreeModifier;
56
+ transform?(instance: any, context: any): void | PromiseLike<void>;
57
+ }
58
+ type SimpleFieldResolver = true | string | FieldResolverFn;
59
+ type QueryTreeModifier = (query: Query, tree: ResolveTree) => Query;
60
+ declare function defineTableResolver<T extends TableClass>(table: DbTable<T>, options?: TableResolverOptions): TableResolverFn;
61
+
62
+ type GraphResolverOptions = Pick<TableResolverOptions, "allowAllFields" | "allowAllFilters">;
63
+ declare function createGraphResolver(types: Record<string, TableResolverFn>, options?: GraphResolverOptions): GraphResolver;
64
+ interface GraphResolveOptions {
65
+ info: GraphQLResolveInfo;
66
+ context: any;
67
+ filters?: FiltersDef;
68
+ }
69
+ declare class GraphResolver {
70
+ readonly tables: Record<string, TableResolverFn>;
71
+ readonly options: GraphResolverOptions;
72
+ constructor(tables: Record<string, TableResolverFn>, options?: GraphResolverOptions);
73
+ resolve(query: Query, { info, context, filters }: GraphResolveOptions): Query;
74
+ resolvePage(query: Query, paginator: Paginator, { info, context, filters }: GraphResolveOptions): Query;
75
+ _get_resolve_tree(info: GraphQLResolveInfo): ResolveTree;
76
+ _resolve_type({ tree, query, filters, }: {
77
+ query: Query;
78
+ tree: ResolveTree;
79
+ filters?: FiltersDef;
80
+ }): Query;
81
+ _resolve_page({ tree, query, paginator, filters, }: {
82
+ query: Query;
83
+ tree: ResolveTree;
84
+ paginator: Paginator;
85
+ filters?: FiltersDef;
86
+ }): Query;
87
+ }
88
+
89
+ type FieldResolverFn = (query: Query, options: {
90
+ /** GraphQL field */
91
+ field: string;
92
+ /** GraphQL resolve tree */
93
+ tree: ResolveTree;
94
+ /** Current graph resolver */
95
+ graph: GraphResolver;
96
+ }) => Query;
97
+ interface FieldResolverOptions {
98
+ /** Table field (if different from GraphQL field) */
99
+ tableField?: string;
100
+ /** Custom query modifier (if different than simply selecting a field). */
101
+ modify?: FieldResolverFn;
102
+ /** Post-process selected value. Return a new value or a promise. */
103
+ transform?(value: any, instance: any, context: any): any;
104
+ }
105
+ declare function defineFieldResolver(options?: FieldResolverOptions): FieldResolverFn;
106
+
107
+ interface RelationResolverOptions extends Omit<FieldResolverOptions, "modify"> {
108
+ filters?: FiltersDef;
109
+ modify?: QueryTreeModifier;
110
+ }
111
+ declare function defineRelationResolver(options?: RelationResolverOptions): FieldResolverFn;
112
+
113
+ declare function definePageResolver(paginator: Paginator, options?: RelationResolverOptions): FieldResolverFn;
114
+
115
+ export { createGraphResolver, defineCursorPaginator as cursor, defineCursorPaginator, defineFieldResolver, definePageResolver, defineRelationResolver, defineTableResolver, defineFieldResolver as field, createGraphResolver as graph, definePageResolver as page, defineRelationResolver as relation, defineTableResolver as table };