orchid-graphql 0.0.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,10 +2,6 @@
2
2
 
3
3
  A helper library to resolve GraphQL queries directly with [Orchid ORM](https://orchid-orm.netlify.app) tables and relations.
4
4
 
5
- This is a fork of [objection-graphql-resolver](https://github.com/IlyaSemenov/objection-graphql-resolver) which does the same for [Objection.js ORM](https://vincit.github.io/objection.js/).
6
-
7
- ## Features
8
-
9
5
  - Highly effective: selects only requested fields and relations.
10
6
  - Unlimited nested resolvers.
11
7
  - Pagination.
@@ -13,11 +9,13 @@ This is a fork of [objection-graphql-resolver](https://github.com/IlyaSemenov/ob
13
9
  - Hook into (sub)queries with query modifiers.
14
10
  - Hook into field results to restrict access to sensitive information.
15
11
 
12
+ _Note that there is a sister project: `objection-graphql-resolver` which does the same for [Objection.js ORM](https://vincit.github.io/objection.js/)._
13
+
16
14
  ## Status and limitations
17
15
 
18
- This is pre-release and not battle tested. `orchid-graphql` is a quick fork of `objection-graphql-resolver`.
16
+ This is pre-release and not battle tested. `orchid-graphql` is a quick adaptation of `objection-graphql-resolver`.
19
17
 
20
- In particular (unlike its sister project) `orchid-graphql` currently doesn't handle types well and returns `any` most of the time.
18
+ In particular the typings are not ready. The resolver returns a generic `Query` most of the time.
21
19
 
22
20
  ## Install
23
21
 
@@ -299,15 +297,14 @@ const graph = r.graph(
299
297
  }),
300
298
  preview2: r.field({
301
299
  // Modify query
302
- modify: (query) =>
303
- query.select(raw("substr(text,1,100) as preview2")),
300
+ modify: (q) => q.select({ preview2: q.raw("substr(text,1,100)") }),
304
301
  // Post-process selected value
305
302
  transform(
306
303
  // Selected value
307
304
  preview,
308
305
  // Current instance
309
306
  post,
310
- // Query context
307
+ // Field resolve context: graph, tree, type, field, filters, context
311
308
  context
312
309
  ) {
313
310
  if (preview.length < 100) {
@@ -351,7 +348,12 @@ const graph = r.graph(
351
348
  ),
352
349
  },
353
350
  // Modify all queries to this table
354
- modify: (q, { args }) => q.where(args).order({ id: "DESC" }),
351
+ modify: (
352
+ // ORM (sub)query
353
+ query,
354
+ // Table resolve context: graph, tree, type, filters, context
355
+ context
356
+ ) => query.where(context.tree.args).order({ id: "DESC" }),
355
357
  // Allow all fields (`fields` will be used for overrides)
356
358
  allowAllFields: true,
357
359
  // Allow filters in all relations
@@ -385,7 +387,7 @@ const resolvers = {
385
387
  }
386
388
  )
387
389
  },
388
- posts_page: (parent, args, context, info) => {
390
+ posts_page: async (parent, args, context, info) => {
389
391
  return await graph.resolvePage(
390
392
  // Root query (required)
391
393
  db.post,
package/dist/index.cjs CHANGED
@@ -35,29 +35,7 @@ __export(src_exports, {
35
35
  });
36
36
  module.exports = __toCommonJS(src_exports);
37
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 _query = query.query;
48
- const { handleResult } = _query;
49
- _query.handleResult = (q, result, s2) => {
50
- const data = handleResult(q, result, s2);
51
- return s2 ? data : _get_page(data);
52
- };
53
- _query[s] = _get_page;
54
- return query;
55
- }
56
- function get_query_pagination_handler(query) {
57
- return query.query[s];
58
- }
59
-
60
- // src/paginators/cursor.ts
38
+ // ../graphql-orm-resolver/src/paginators/cursor.ts
61
39
  function defineCursorPaginator(options = {}) {
62
40
  return new CursorPaginator(options);
63
41
  }
@@ -79,18 +57,22 @@ var CursorPaginator = class {
79
57
  }
80
58
  });
81
59
  }
82
- paginate(query, args = {}) {
60
+ paginate(query, context) {
61
+ const { orm: orm2 } = context.graph;
62
+ const { args } = context.tree;
83
63
  const take = args.take ?? this.options.take;
84
- const { cursor } = args;
85
- query = query.clear("order");
64
+ const cursor = args.cursor;
65
+ query = orm2.reset_query_order(query);
86
66
  for (const field of this.fields) {
87
- query = query.select(field.name).order({ [field.name]: field.desc ? "DESC" : "ASC" });
67
+ query = orm2.select_field(query, { field: field.name, as: field.name });
68
+ query = orm2.add_query_order(query, field.name, field.desc);
88
69
  }
89
70
  if (cursor) {
90
- query = this._set_query_cursor(query, cursor);
71
+ const { expression, bindings } = this._parse_cursor(cursor);
72
+ query = orm2.where_raw(query, expression, bindings);
91
73
  }
92
- query = query.limit(take + 1);
93
- query = set_query_page_result(query, (nodes) => {
74
+ query = orm2.set_query_limit(query, take + 1);
75
+ query = orm2.set_query_page_result(query, (nodes) => {
94
76
  let cursor2;
95
77
  if (nodes.length > take) {
96
78
  cursor2 = this._create_cursor(nodes[take - 1]);
@@ -113,39 +95,29 @@ var CursorPaginator = class {
113
95
  })
114
96
  );
115
97
  }
116
- _set_query_cursor(query, cursor) {
98
+ _parse_cursor(cursor) {
117
99
  const values = JSON.parse(cursor);
118
100
  const left = [];
119
101
  const right = [];
120
- const expr_values = {};
102
+ const bindings = {};
121
103
  for (let i = 0; i < this.fields.length; ++i) {
122
104
  const field = this.fields[i];
123
105
  const expressions = field.desc ? right : left;
124
106
  const placeholders = field.desc ? left : right;
125
107
  expressions.push(`"${field.name}"`);
126
- const placeholder = `value${i}`;
127
- placeholders.push("$" + placeholder);
128
- expr_values[placeholder] = values[i];
108
+ placeholders.push("$" + field.name);
109
+ bindings[field.name] = values[i];
129
110
  }
130
- return query.where(
131
- query.raw(`(${left.join(",")}) > (${right.join(",")})`, expr_values)
132
- );
111
+ return {
112
+ expression: `(${left.join(",")}) > (${right.join(",")})`,
113
+ bindings
114
+ };
133
115
  }
134
116
  };
135
117
 
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) => {
118
+ // ../graphql-orm-resolver/src/utils/run-after.ts
119
+ function run_after_query(orm2, query, transform) {
120
+ return orm2.run_after_query(query, async (result) => {
149
121
  if (Array.isArray(result)) {
150
122
  const result1 = await Promise.all(result.map(transform));
151
123
  return result1.filter(Boolean);
@@ -157,19 +129,21 @@ function run_after_query(query, transform) {
157
129
  });
158
130
  }
159
131
 
160
- // src/resolvers/field.ts
132
+ // ../graphql-orm-resolver/src/resolvers/field.ts
161
133
  function defineFieldResolver(options = {}) {
162
134
  const { tableField, modify, transform } = options;
163
- return function resolve(query, options2) {
164
- const { field } = options2;
135
+ return function resolve(query, context) {
136
+ const { field } = context;
165
137
  if (modify) {
166
- return modify(query, options2);
138
+ query = modify(query, context);
167
139
  } else {
168
- query = query.select({ [field]: tableField || field });
140
+ query = context.graph.orm.select_field(query, {
141
+ field: tableField || field,
142
+ as: field
143
+ });
169
144
  }
170
145
  if (transform) {
171
- const context = get_query_context(query);
172
- query = run_after_query(query, async (instance) => {
146
+ query = run_after_query(context.graph.orm, query, async (instance) => {
173
147
  instance[field] = await transform(instance[field], instance, context);
174
148
  return instance;
175
149
  });
@@ -178,118 +152,103 @@ function defineFieldResolver(options = {}) {
178
152
  };
179
153
  }
180
154
 
181
- // src/resolvers/graph.ts
155
+ // ../graphql-orm-resolver/src/resolvers/graph.ts
182
156
  var import_graphql_parse_resolve_info = require("graphql-parse-resolve-info");
183
- function createGraphResolver(types, options) {
184
- return new GraphResolver(types, options);
185
- }
186
157
  var GraphResolver = class {
187
- constructor(tables, options = {}) {
188
- this.tables = tables;
158
+ constructor(orm2, type_resolvers, options = {}) {
159
+ this.orm = orm2;
160
+ this.type_resolvers = type_resolvers;
189
161
  this.options = options;
190
162
  }
191
163
  resolve(query, { info, context, filters }) {
192
- set_query_context(query, context);
193
164
  const tree = this._get_resolve_tree(info);
194
- return this._resolve_type({ query, tree, filters });
165
+ return this._resolve_type(query, { tree, filters, context });
195
166
  }
196
167
  resolvePage(query, paginator, { info, context, filters }) {
197
- set_query_context(query, context);
198
168
  const tree = this._get_resolve_tree(info);
199
- return this._resolve_page({ query, tree, paginator, filters });
169
+ return this._resolve_page(query, paginator, { tree, filters, context });
200
170
  }
201
171
  _get_resolve_tree(info) {
202
172
  return (0, import_graphql_parse_resolve_info.parseResolveInfo)(info);
203
173
  }
204
- _resolve_type({
205
- tree,
206
- query,
207
- filters
208
- }) {
174
+ _resolve_type(query, context) {
175
+ const { tree } = context;
209
176
  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}.`);
177
+ const type_resolver = this.type_resolvers[type];
178
+ if (!type_resolver) {
179
+ throw new Error(`Resolver not found for type ${type}.`);
213
180
  }
214
- return table_resolver({ tree, type, query, filters, graph: this });
181
+ return type_resolver.resolve(query, {
182
+ ...context,
183
+ graph: this,
184
+ tree,
185
+ type
186
+ });
215
187
  }
216
- _resolve_page({
217
- tree,
218
- query,
219
- paginator,
220
- filters
221
- }) {
222
- const { args } = tree;
188
+ _resolve_page(query, paginator, context) {
189
+ let { tree } = context;
223
190
  for (const field of paginator.path) {
224
191
  const type = Object.keys(tree.fieldsByTypeName)[0];
225
192
  tree = tree.fieldsByTypeName[type][field];
226
193
  }
227
- query = this._resolve_type({ query, tree, filters });
228
- return paginator.paginate(query, args);
194
+ query = this._resolve_type(query, { ...context, tree });
195
+ return paginator.paginate(query, {
196
+ ...context,
197
+ graph: this
198
+ });
229
199
  }
230
200
  };
231
201
 
232
- // src/resolvers/page.ts
233
- var import_orchid_core = require("orchid-core");
202
+ // ../graphql-orm-resolver/src/resolvers/page.ts
234
203
  function definePageResolver(paginator, options = {}) {
235
- const { tableField, filters, modify } = options;
236
- return defineFieldResolver({
237
- modify: (query, { field, tree, graph }) => {
238
- let get_page;
239
- query = query.select({
240
- [field]: (q) => {
241
- q = graph._resolve_page({
242
- tree,
243
- query: q[tableField || field],
244
- paginator,
245
- filters
246
- });
247
- get_page = get_query_pagination_handler(q);
248
- return modify ? modify(q, tree) : q;
249
- }
250
- });
251
- (0, import_orchid_core.overrideParserInQuery)(query.query, field, get_page);
252
- return query;
253
- }
254
- });
204
+ const { tableField, modify } = options;
205
+ return function resolve(query, context) {
206
+ const { graph, field } = context;
207
+ const pagination_context = {};
208
+ query = graph.orm.select_relation(query, {
209
+ relation: tableField || field,
210
+ as: field,
211
+ modify(subquery) {
212
+ subquery = graph._resolve_page(subquery, paginator, context);
213
+ subquery = graph.orm.modify_subquery_pagination(
214
+ subquery,
215
+ pagination_context
216
+ );
217
+ return modify ? modify(subquery, context) : subquery;
218
+ }
219
+ });
220
+ query = graph.orm.finish_query_pagination(query, field, pagination_context);
221
+ return query;
222
+ };
255
223
  }
256
224
 
257
- // src/resolvers/relation.ts
225
+ // ../graphql-orm-resolver/src/resolvers/relation.ts
258
226
  function defineRelationResolver(options = {}) {
259
227
  const { tableField, filters, modify } = options;
260
- return defineFieldResolver({
261
- modify: (query, { field, tree, graph }) => query.select({
262
- [field]: (q) => {
263
- const relation_query = graph._resolve_type({
264
- tree,
265
- query: q[tableField || field],
266
- filters
267
- });
268
- return modify ? modify(relation_query, tree) : relation_query;
228
+ return function resolve(query, context) {
229
+ const { graph, field } = context;
230
+ return graph.orm.select_relation(query, {
231
+ relation: tableField || field,
232
+ as: field,
233
+ modify(subquery) {
234
+ subquery = graph._resolve_type(subquery, { ...context, filters });
235
+ return modify ? modify(subquery, context) : subquery;
269
236
  }
270
- })
271
- });
237
+ });
238
+ };
272
239
  }
273
240
 
274
- // src/utils/is-plain-object.ts
241
+ // ../graphql-orm-resolver/src/utils/is-plain-object.ts
275
242
  function is_plain_object(obj) {
276
243
  return typeof obj === "object" && !Array.isArray(obj);
277
244
  }
278
245
 
279
- // src/filters/filters.ts
280
- function is_scalar(value) {
281
- return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
282
- }
283
- function apply_filters({
284
- query,
285
- filters,
286
- args,
287
- modifiers
288
- }) {
246
+ // ../graphql-orm-resolver/src/filters/filters.ts
247
+ function apply_filters(query, { filters, modifiers, context }) {
289
248
  if (!filters) {
290
249
  return query;
291
250
  }
292
- const filter_obj = args?.filter;
251
+ const filter_obj = context.tree.args?.filter;
293
252
  if (!filter_obj) {
294
253
  return query;
295
254
  }
@@ -301,122 +260,196 @@ function apply_filters({
301
260
  continue;
302
261
  }
303
262
  if (modifiers?.[field]) {
304
- query = modifiers[field](query, value);
263
+ query = modifiers[field](query, value, context);
305
264
  } else {
306
- const [dbfield, op0] = field.split("__");
307
- const op = op0?.toLowerCase() || "exact";
308
- if (
309
- // TODO: add the rest of orchid ops (or allow all of them?)
310
- [
311
- "exact",
312
- "lt",
313
- "lte",
314
- "gt",
315
- "gte",
316
- "like",
317
- "ilike",
318
- "contains"
319
- ].includes(op)
320
- ) {
321
- if (!is_scalar(value)) {
322
- throw new Error(
323
- `Unsupported filter value for ${query.table}.${field}: must be scalar.`
324
- );
325
- }
326
- if (op === "exact") {
327
- query = query.where({ [dbfield]: value });
328
- } else {
329
- const query_op = { like: "contains" }[op] || op;
330
- query = query.where({ [dbfield]: { [query_op]: value } });
331
- }
332
- } else if (op === "in") {
333
- if (!(Array.isArray(value) && value.every(is_scalar))) {
334
- throw new Error(
335
- `Invalid filter value for ${query.table}.${field}: must be an array of scalars.`
336
- );
337
- }
338
- query = query.whereIn(dbfield, value);
339
- } else {
340
- throw new Error(
341
- `Invalid filter ${query.table}.${field}: unsupported operator ${op}.`
342
- );
343
- }
265
+ const [table_field, op0] = field.split("__");
266
+ const op = op0?.toLowerCase();
267
+ query = context.graph.orm.where(query, table_field, op, value);
344
268
  }
345
269
  }
346
270
  return query;
347
271
  }
348
272
 
349
- // src/resolvers/table.ts
350
- function defineTableResolver(table, options = {}) {
351
- const get_default_field_resolver = (field, tableField) => {
352
- const table_field_lookup = tableField || field;
353
- if (options.modifiers?.[table_field_lookup]) {
354
- return (query) => query;
355
- } else if (table.relations?.[table_field_lookup]) {
356
- return defineRelationResolver({ tableField });
357
- } else {
358
- return defineFieldResolver({ tableField });
273
+ // ../graphql-orm-resolver/src/resolvers/table.ts
274
+ var TableResolver = class {
275
+ constructor(orm2, table, options = {}) {
276
+ this.orm = orm2;
277
+ this.table = table;
278
+ this.options = options;
279
+ this.relations = new Set(orm2.get_table_relations(table));
280
+ this.virtual_fields = new Set(orm2.get_table_virtual_fields(table));
281
+ this.modifiers = { ...orm2.get_table_modifiers(table), ...options.modifiers };
282
+ const { fields } = options;
283
+ if (fields) {
284
+ this.table_field_resolvers = Object.keys(fields).reduce((resolvers, field) => {
285
+ const r0 = fields[field];
286
+ const r = typeof r0 === "function" ? r0 : r0 === true ? this._get_default_field_resolver(field) : typeof r0 === "string" ? this._get_default_field_resolver(field, r0) : void 0;
287
+ if (r === void 0) {
288
+ throw new Error(
289
+ `Field resolver must be a function, string, or true; found ${typeof r0}.`
290
+ );
291
+ }
292
+ resolvers[field] = r;
293
+ return resolvers;
294
+ }, {});
359
295
  }
360
- };
361
- const { fields } = options;
362
- const table_field_resolvers = fields ? Object.keys(fields).reduce(
363
- (resolvers, field) => {
364
- const r0 = fields[field];
365
- const r = typeof r0 === "function" ? r0 : r0 === true ? get_default_field_resolver(field) : typeof r0 === "string" ? get_default_field_resolver(field, r0) : void 0;
366
- if (r === void 0) {
367
- throw new Error(
368
- `Field resolver must be a function, string, or true; found ${r0}`
369
- );
370
- }
371
- resolvers[field] = r;
372
- return resolvers;
373
- },
374
- {}
375
- ) : void 0;
376
- const { modify, transform } = options;
377
- return function resolve({ tree, type, query, filters, graph }) {
378
- if (query.table !== table.table) {
296
+ }
297
+ // Introspection results
298
+ relations;
299
+ virtual_fields;
300
+ modifiers;
301
+ table_field_resolvers;
302
+ /** Modify query to select fields/relations and filter the result set. */
303
+ resolve(query, context) {
304
+ const { modify, transform } = this.options;
305
+ const { graph, tree, type, filters } = context;
306
+ const query_table = this.orm.get_query_table(query);
307
+ const table_table = this.orm.get_table_table(this.table);
308
+ if (query_table !== table_table) {
379
309
  throw new Error(
380
- `Mismatching query type (expected ${table.table}, found ${query.table}).`
310
+ `Mismatching query table for type ${type}: expected ${table_table}, received ${query_table}.`
381
311
  );
382
312
  }
383
- const allow_all_fields = options.allowAllFields ?? graph.options.allowAllFields ?? table_field_resolvers === void 0;
384
- if (!allow_all_fields && !table_field_resolvers) {
313
+ const allow_all_fields = this.options.allowAllFields ?? graph.options.allowAllFields ?? !this.options.fields;
314
+ if (!allow_all_fields && !this.table_field_resolvers) {
385
315
  throw new Error(
386
- `Table resolver for ${type} must either allow all fields or specify options.fields`
316
+ `Resolver for type ${type} must either allow all fields or specify options.fields.`
387
317
  );
388
318
  }
389
319
  if (modify) {
390
- query = modify(query, tree);
320
+ query = modify(query, context);
391
321
  }
392
322
  for (const subtree of Object.values(tree.fieldsByTypeName[type])) {
393
323
  const field = subtree.name;
394
- const r = table_field_resolvers?.[field] || (allow_all_fields ? get_default_field_resolver(field) : void 0);
324
+ const r = this.table_field_resolvers?.[field] || (allow_all_fields ? this._get_default_field_resolver(field) : void 0);
395
325
  if (!r) {
396
- throw new Error(`No field resolver defined for field ${type}.${field}`);
326
+ throw new Error(`No field resolver defined for field ${type}.${field}.`);
397
327
  }
398
328
  if (r) {
399
- query = r(query, { field, tree: subtree, graph });
329
+ query = r(query, { ...context, tree: subtree, field });
400
330
  }
401
331
  }
402
- const allow_all_filters = options.allowAllFilters ?? graph.options.allowAllFilters;
332
+ const allow_all_filters = this.options.allowAllFilters ?? graph.options.allowAllFilters;
403
333
  const effective_filters = allow_all_filters ? true : filters;
404
334
  if (effective_filters) {
405
- query = apply_filters({
406
- query,
335
+ query = apply_filters(query, {
407
336
  filters: effective_filters,
408
- args: tree.args,
409
- modifiers: options.modifiers
337
+ modifiers: this.modifiers,
338
+ context
410
339
  });
411
340
  }
412
341
  if (transform) {
413
- const context = get_query_context(query);
414
- query = run_after_query(query, (instance) => {
342
+ query = run_after_query(this.orm, query, (instance) => {
415
343
  return transform(instance, context);
416
344
  });
417
345
  }
346
+ query = this.orm.prevent_select_all(query);
418
347
  return query;
419
- };
348
+ }
349
+ /**
350
+ * Create field resolver which will modify query to resolve GraphQL field.
351
+ */
352
+ _get_default_field_resolver(field, tableField) {
353
+ const table_field_lookup = tableField || field;
354
+ if (this.options.modifiers?.[table_field_lookup] || this.virtual_fields.has(table_field_lookup)) {
355
+ return (query) => query;
356
+ } else if (this.relations.has(table_field_lookup)) {
357
+ return defineRelationResolver({ tableField });
358
+ } else {
359
+ return defineFieldResolver({ tableField });
360
+ }
361
+ }
362
+ };
363
+
364
+ // src/orm/orm.ts
365
+ var import_orchid_core = require("orchid-core");
366
+ var orm = {
367
+ // Reflection
368
+ get_table_table(table) {
369
+ return table.table;
370
+ },
371
+ get_table_relations(table) {
372
+ return Object.keys(table.relations);
373
+ },
374
+ get_table_virtual_fields() {
375
+ return [];
376
+ },
377
+ get_table_modifiers() {
378
+ return void 0;
379
+ },
380
+ get_query_table(query) {
381
+ if (!query.table) {
382
+ throw new Error("Query must have table.");
383
+ }
384
+ return query.table;
385
+ },
386
+ // Select
387
+ select_field(query, { field, as }) {
388
+ return query.select({ [as]: field });
389
+ },
390
+ select_relation(query, { relation, as, modify }) {
391
+ return query.select({
392
+ [as]: (q) => modify(q[relation])
393
+ });
394
+ },
395
+ // Find
396
+ where(query, field, op, value) {
397
+ return query.where({ [field]: op ? { [op]: value } : value });
398
+ },
399
+ where_raw(query, expression, bindings) {
400
+ return query.where(query.raw(expression, bindings));
401
+ },
402
+ // Order & Limit
403
+ reset_query_order(query) {
404
+ return query.clear("order");
405
+ },
406
+ add_query_order(query, field, desc) {
407
+ return query.order({ [field]: desc ? "DESC" : "ASC" });
408
+ },
409
+ set_query_limit(query, limit) {
410
+ return query.limit(limit);
411
+ },
412
+ // Pagination helpers
413
+ set_query_page_result(query, get_page) {
414
+ const _query = query.query;
415
+ const { handleResult } = _query;
416
+ _query.handleResult = (q, result, s2) => {
417
+ const data = handleResult(q, result, s2);
418
+ return s2 ? data : get_page(data);
419
+ };
420
+ _query[s] = get_page;
421
+ return query;
422
+ },
423
+ modify_subquery_pagination(subquery, context) {
424
+ context.get_page = subquery.query[s];
425
+ return subquery;
426
+ },
427
+ finish_query_pagination(query, field, context) {
428
+ const { get_page } = context;
429
+ if (!get_page) {
430
+ throw new Error(`Internal error: paginator didn't provide page callback.`);
431
+ }
432
+ (0, import_orchid_core.overrideParserInQuery)(query.query, field, get_page);
433
+ return query;
434
+ },
435
+ // Misc
436
+ run_after_query(query, fn) {
437
+ return query.afterQuery(async (_, result) => fn(result));
438
+ },
439
+ prevent_select_all(query) {
440
+ return query;
441
+ }
442
+ };
443
+ var s = Symbol("subquery_pagination_handler");
444
+
445
+ // src/resolvers/graph.ts
446
+ function createGraphResolver(types, options) {
447
+ return new GraphResolver(orm, types, options);
448
+ }
449
+
450
+ // src/resolvers/table.ts
451
+ function defineTableResolver(table, options = {}) {
452
+ return new TableResolver(orm, table, options);
420
453
  }
421
454
  // Annotate the CommonJS export names for ESM import in node:
422
455
  0 && (module.exports = {