@dav3/gql-of-power 1.2.0 → 1.4.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.
Files changed (48) hide show
  1. package/.fallowrc.json +23 -0
  2. package/.prettierignore +13 -0
  3. package/README.md +164 -14
  4. package/agents/templates/entity-skeleton.ts.txt +136 -0
  5. package/dist/entities/gql-entity.d.ts +28 -2
  6. package/dist/entities/gql-entity.js +575 -171
  7. package/dist/field-operations.d.ts +102 -0
  8. package/dist/field-operations.js +95 -0
  9. package/dist/operations.d.ts +9 -103
  10. package/dist/operations.js +17 -82
  11. package/dist/queries/filter-processor.d.ts +86 -5
  12. package/dist/queries/filter-processor.js +327 -52
  13. package/dist/queries/gql-to-sql-mapper.d.ts +23 -3
  14. package/dist/queries/gql-to-sql-mapper.js +338 -132
  15. package/dist/queries/relationship-handler.d.ts +3 -1
  16. package/dist/queries/relationship-handler.js +13 -9
  17. package/dist/queries/sql-builder.d.ts +4 -53
  18. package/dist/queries/sql-builder.js +8 -74
  19. package/dist/queries/utils.d.ts +1 -2
  20. package/dist/queries/utils.js +1 -8
  21. package/dist/query-manager.d.ts +18 -8
  22. package/dist/query-manager.js +129 -5
  23. package/dist/types/gql-to-sql-types.d.ts +1 -1
  24. package/dist/types/gql-to-sql-types.js +2 -2
  25. package/dist/types/gql-types.d.ts +13 -3
  26. package/dist/types/sql-types.d.ts +150 -3
  27. package/dist/types/sql-types.js +2 -0
  28. package/dist/variables.d.ts +0 -1
  29. package/dist/variables.js +13 -10
  30. package/fallow-baselines/dead-code.json +34 -0
  31. package/fallow-baselines/dupes.json +10 -0
  32. package/fallow-baselines/health.json +103 -0
  33. package/package.json +19 -12
  34. package/src/entities/gql-entity.ts +774 -173
  35. package/src/field-operations.ts +134 -0
  36. package/src/operations.ts +11 -116
  37. package/src/queries/filter-processor.ts +616 -35
  38. package/src/queries/gql-to-sql-mapper.ts +604 -161
  39. package/src/queries/relationship-handler.ts +12 -12
  40. package/src/queries/sql-builder.ts +12 -103
  41. package/src/queries/utils.ts +2 -11
  42. package/src/query-manager.ts +198 -23
  43. package/src/types/access-control.ts +1 -0
  44. package/src/types/gql-to-sql-types.ts +2 -2
  45. package/src/types/gql-types.ts +23 -9
  46. package/src/types/sql-types.ts +155 -6
  47. package/src/types/utils.ts +3 -3
  48. package/src/variables.ts +12 -8
package/.fallowrc.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "./node_modules/fallow/schema.json",
3
+ "entry": [
4
+ "src/index.{ts,tsx,js,jsx}",
5
+ "scripts/update-version.ts",
6
+ "tests/run-sample-tests.ts",
7
+ "tests/regression/generate-sql-snapshots.ts"
8
+ ],
9
+ "ignorePatterns": ["dist/**", "coverage/**", "tests/fixtures/**", "examples/**"],
10
+ "ignoreDependencies": [],
11
+ "ignoreExports": [
12
+ {
13
+ "file": "src/types/gql-types.ts",
14
+ "exports": ["*"],
15
+ "reason": "Generated filter/pagination input type shapes consumed via type-graphql decorators, not direct imports."
16
+ }
17
+ ],
18
+ "audit": {
19
+ "deadCodeBaseline": "fallow-baselines/dead-code.json",
20
+ "healthBaseline": "fallow-baselines/health.json",
21
+ "dupesBaseline": "fallow-baselines/dupes.json"
22
+ }
23
+ }
@@ -0,0 +1,13 @@
1
+ # Build output
2
+ dist/
3
+ coverage/
4
+
5
+ # Lockfiles (binary / auto-generated)
6
+ bun.lockb
7
+ pnpm-lock.yaml
8
+ package-lock.json
9
+ yarn.lock
10
+
11
+ # fallow caches (auto-managed) + machine-generated baselines
12
+ .fallow/
13
+ fallow-baselines/
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ⚔️ GQL of Power
2
2
 
3
- > **"One Query to Rule Them All"** — Master your data with the power of a single GraphQL query
3
+ > **"One Query to Rule Them All"** — Master your data with the power of a single optimized SQL query
4
4
 
5
5
  ---
6
6
 
@@ -8,9 +8,9 @@
8
8
 
9
9
  In the age of microservices and data loaders, a shadow falls upon performance: _the N+1 query problem_. Weary developers traverse the lands of Middleware-earth, orchestrating countless queries to fetch interconnected data.
10
10
 
11
- But what if there was another way? What if, with the power of a single query, you could bind all your data together?
11
+ But what if there was another way? What if, with the power of a single SQL query, you could bind all your data together?
12
12
 
13
- **GQL of Power** is a TypeScript library that harnesses ancient sorcery to generate perfectly optimized SQL queries from your GraphQL operations. It eliminates the need for data loaders entirely — one query to fetch your complete data structure, no matter how deeply nested your relationships run.
13
+ **GQL of Power** is a TypeScript library that harnesses ancient sorcery to generate perfectly optimized SQL queries from your GraphQL operations. It eliminates the need for data loaders entirely — one SQL query to fetch your complete data structure, no matter how deeply nested your relationships run.
14
14
 
15
15
  Like the One Ring wielding dominion over all other Rings, GQL of Power commands your database with singular authority.
16
16
 
@@ -157,6 +157,7 @@ const fields = defineFields(Book, {
157
157
  | `alias` | `string` | Override the GQL field name |
158
158
  | `array` | `true` | Mark as array return type |
159
159
  | `relatedEntityName` | `() => string` | ORM entity name for array relation fields (auto-derived when using `@GQLEntityClass`) |
160
+ | `countFieldName` | `string` | Generate a count field for this relationship (see [Count Fields](#count-fields)) |
160
161
  | `enum` | `EnumData` | Register an enum type |
161
162
 
162
163
  ### `@GQLEntityClass(OrmClass, fields, extra?)`
@@ -317,17 +318,114 @@ filter: {
317
318
 
318
319
  ### Filter operations
319
320
 
320
- | Operation | Meaning |
321
- | -------------- | ------------------------------------ |
322
- | `_eq` | Equal |
323
- | `_ne` | Not equal |
324
- | `_in` | In array |
325
- | `_nin` | Not in array |
326
- | `_like` | ILIKE (case-insensitive contains) |
327
- | `_gt` / `_gte` | Greater than / greater than or equal |
328
- | `_lt` / `_lte` | Less than / less than or equal |
329
- | `_and` | Logical AND |
330
- | `_or` | Logical OR (generates UNION ALL) |
321
+ | Operation | Meaning |
322
+ | -------------- | ------------------------------------------------------ |
323
+ | `_eq` | Equal |
324
+ | `_ne` | Not equal |
325
+ | `_in` | In array |
326
+ | `_nin` | Not in array |
327
+ | `_like` | ILIKE (case-insensitive contains) |
328
+ | `_gt` / `_gte` | Greater than / greater than or equal |
329
+ | `_lt` / `_lte` | Less than / less than or equal |
330
+ | `_and` | Logical AND |
331
+ | `_or` | Logical OR (generates UNION ALL) |
332
+ | `_exists` | Check related entities exist (AND-combined per key) |
333
+ | `_not_exists` | Check no related entities exist (AND-combined per key) |
334
+
335
+ ### Existence Filters (`_exists` / `_not_exists`)
336
+
337
+ Check whether related entities match a set of conditions. Each key is a relationship field name; the value is a filter applied to that related entity. Multiple keys are AND-combined.
338
+
339
+ ```graphql
340
+ # Authors that have at least one book titled "The Hobbit"
341
+ filter: {
342
+ _exists: {
343
+ books: { title: "The Hobbit" }
344
+ }
345
+ }
346
+
347
+ # Authors that have a book titled "The Hobbit" AND no books in the "Horror" genre
348
+ filter: {
349
+ _and: [
350
+ { _exists: { books: { title: "The Hobbit" } } }
351
+ { _not_exists: { books: { genre: "Horror" } } }
352
+ ]
353
+ }
354
+
355
+ # Persons who fought in a victory battle AND wrote a book about it
356
+ filter: {
357
+ _exists: {
358
+ battles: { outcome: "Victory" }
359
+ books: { title: { _like: "%War%" } }
360
+ }
361
+ }
362
+ ```
363
+
364
+ `_exists` generates `EXISTS (SELECT 1 FROM ... WHERE ...)` subqueries. `_not_exists` generates `NOT EXISTS (...)`. Multiple keys within one `_exists`/`_not_exists` each produce a separate `EXISTS`/`NOT EXISTS` clause, AND-combined in the WHERE. OR across exists conditions is achieved via `_or`.
365
+
366
+ ---
367
+
368
+ ## Count Fields
369
+
370
+ Add `countFieldName` to any relationship field with `array: true` to auto-generate an Int count field. The count is computed via a correlated `COUNT(*)` subquery — no JOINs in the outer query.
371
+
372
+ ### Definition
373
+
374
+ ```typescript
375
+ const authorFields = defineFields(Author, {
376
+ id: { type: () => ID, generateFilter: true },
377
+ name: { type: () => String, generateFilter: true },
378
+ books: {
379
+ type: () => BookGQL,
380
+ array: true,
381
+ relatedEntityName: () => 'Book',
382
+ countFieldName: 'bookCount', // generates an `bookCount: Int` field
383
+ },
384
+ });
385
+ ```
386
+
387
+ ### Querying
388
+
389
+ ```graphql
390
+ query {
391
+ authors {
392
+ name
393
+ bookCount # total books
394
+ bookCount(filter: { publishedYear: { _gt: 1950 } }) # filtered count
395
+ }
396
+ }
397
+ ```
398
+
399
+ ### Filtering by Count
400
+
401
+ The count field is also available as a filter key with numeric operators:
402
+
403
+ ```graphql
404
+ # Authors with exactly 4 books
405
+ filter: { bookCount: 4 }
406
+
407
+ # Authors with more than 3 books
408
+ filter: { bookCount_gt: 3 }
409
+
410
+ # Nested object form
411
+ filter: { BookCount: { _gte: 2, _lte: 10 } }
412
+ ```
413
+
414
+ Supported operators: `_eq`, `_ne`, `_gt`, `_gte`, `_lt`, `_lte`.
415
+
416
+ ### Generated SQL
417
+
418
+ ```sql
419
+ -- bookCount (select)
420
+ SELECT ...,
421
+ (SELECT COUNT(*) FROM "books" AS e_w1 WHERE e_w1.author_id = a_1.id) AS "bookCount"
422
+ FROM authors AS a_1 ...
423
+
424
+ -- bookCount_gt (filter)
425
+ WHERE (SELECT COUNT(*) FROM "books" AS e_w1 WHERE e_w1.author_id = a_1.id) > :v_bookCount_gt__1
426
+ ```
427
+
428
+ Works for all relationship types (1:m, m:1, m:n). For m:n, the pivot table is included in the subquery.
331
429
 
332
430
  ---
333
431
 
@@ -409,6 +507,34 @@ const results = await queryManager.getQueryResultsForFields(
409
507
 
410
508
  `BookGQL.relatedEntityName` (`'Book'`) is used automatically to look up ORM metadata — no need to pass the ORM class separately.
411
509
 
510
+ ### Singular Queries
511
+
512
+ For fetching a single record, use the singular variants. These enforce `LIMIT 1` internally and return `K | null` instead of `K[]`:
513
+
514
+ ```typescript
515
+ // From a GraphQL resolver
516
+ const ring = await queryManager.getQueryResultForInfo(
517
+ metadataProvider,
518
+ RingGQL,
519
+ info,
520
+ { forgedBy: 'Sauron' },
521
+ [{ forgedYear: 'desc' }] // optional orderBy — controls *which* record is returned
522
+ );
523
+ // ring: Ring | null
524
+
525
+ // With explicit field selection
526
+ const ring = await queryManager.getQueryResultForFields(
527
+ metadataProvider,
528
+ RingGQL,
529
+ { id: {}, name: {} },
530
+ { forgedBy: 'Sauron' },
531
+ [{ forgedYear: 'desc' }]
532
+ );
533
+ // ring: Ring | null
534
+ ```
535
+
536
+ No `limit` or `offset` parameters are accepted — `LIMIT 1` is always applied.
537
+
412
538
  ---
413
539
 
414
540
  ## Architecture
@@ -442,6 +568,27 @@ const results = await queryManager.getQueryResultsForFields(
442
568
 
443
569
  ---
444
570
 
571
+ ## Agent Integration
572
+
573
+ This library ships an **agent skill** (`agents/`) that teaches AI coding assistants (Claude Code, Cursor, Hermes, or any agent reading `AGENTS.md`) how to scaffold gql-of-power entities, relationships, and advanced features correctly — using copy-paste templates, annotated relationship examples, and a decision tree for picking the right relationship type.
574
+
575
+ To install it in a consumer project (one-time setup):
576
+
577
+ ```bash
578
+ # Claude Code
579
+ mkdir -p .claude/skills && cp -R node_modules/@dav3/gql-of-power/agents/ .claude/skills/gql-of-power/
580
+
581
+ # Cursor
582
+ mkdir -p .cursor/rules && cp node_modules/@dav3/gql-of-power/agents/SKILL.md .cursor/rules/gql-of-power.mdc
583
+
584
+ # Hermes
585
+ ln -s node_modules/@dav3/gql-of-power/agents ~/.hermes/skills/gql-of-power
586
+ ```
587
+
588
+ See [`agents/install.md`](./agents/install.md) for full instructions (including a symlink option that tracks gql-of-power updates, slash-command setup, and a generic `AGENTS.md` snippet). Once installed, ask your agent to "add a gql-of-power entity" and it will follow the library's intended patterns.
589
+
590
+ ---
591
+
445
592
  ## Development
446
593
 
447
594
  ```bash
@@ -449,8 +596,11 @@ bun install # Install dependencies
449
596
  bun run build # Compile TypeScript → dist/
450
597
  bun run test # Run all tests
451
598
  bun run test:watch # Watch mode
599
+ bun run audit # Codebase-intelligence gate (fallow): dead code, duplication, complexity
452
600
  ```
453
601
 
602
+ `bun run audit` runs the changed-file gate against saved baselines in `.fallow/` and fails only on **new** findings it introduces. Use `bun run audit:full` for the complete report, or `bun run audit:dead-code` / `audit:dupes` / `audit:health` for individual analyses. See `AGENTS.md` for the full audit workflow.
603
+
454
604
  ---
455
605
 
456
606
  ## License
@@ -0,0 +1,136 @@
1
+ // gql-of-power entity skeleton — copy, rename, and adapt.
2
+ // Middle-earth themed example: a "Weapon" entity with a m:1 to its Bearer.
3
+ //
4
+ // This file is a template, not importable code. Place your real files in:
5
+ // schema/entities.ts (ORM class + EntityMetadata)
6
+ // schema/fields.ts (FieldsSettings)
7
+ // graphql/entities.ts (createGQLTypes calls)
8
+ // graphql/resolvers.ts (@Resolver + @Query classes)
9
+
10
+ import 'reflect-metadata';
11
+ import { GraphQLResolveInfo } from 'graphql';
12
+ import {
13
+ createGQLTypes,
14
+ GQLEntityFilterInputFieldType,
15
+ FieldsSettings,
16
+ } from '@dav3/gql-of-power';
17
+ import { EntityMetadata, EntityProperty, ReferenceType } from '@dav3/gql-of-power';
18
+ import { Arg, Info, Int, Query, Resolver } from 'type-graphql';
19
+ import { queryManager, provider } from './your-app-setup'; // <-- your wiring
20
+
21
+ // ─────────────────────────────────────────────────────────────────────────────
22
+ // 1. ORM ENTITY CLASS (schema/entities.ts)
23
+ // Plain TS class. Property names = JS names. Relationship fields optional.
24
+ // ─────────────────────────────────────────────────────────────────────────────
25
+
26
+ export class Weapon {
27
+ id!: number;
28
+ name!: string;
29
+ damage!: number;
30
+ // m:1 relationship — Weapon holds bearerId
31
+ bearerId?: number;
32
+ bearer?: Person;
33
+ }
34
+
35
+ export class Person {
36
+ id!: number;
37
+ name!: string;
38
+ }
39
+
40
+ // ─────────────────────────────────────────────────────────────────────────────
41
+ // 2. ENTITY METADATA (schema/entities.ts)
42
+ // SQL reality: table, PKs, column names, relationship join columns.
43
+ // ─────────────────────────────────────────────────────────────────────────────
44
+
45
+ const prop = (
46
+ type: string,
47
+ name: string,
48
+ fieldNames: string[],
49
+ reference?: {
50
+ referenceType: ReferenceType;
51
+ joinColumns?: string[];
52
+ referencedColumnNames?: string[];
53
+ mappedBy?: string;
54
+ }
55
+ ): EntityProperty => ({
56
+ type,
57
+ name,
58
+ fieldNames,
59
+ mappedBy: reference?.mappedBy || '',
60
+ joinColumns: reference?.joinColumns || [],
61
+ referencedColumnNames: reference?.referencedColumnNames || [],
62
+ inverseJoinColumns: [],
63
+ pivotTable: '',
64
+ reference: reference?.referenceType,
65
+ });
66
+
67
+ export const WeaponMetadata: EntityMetadata<Weapon> = {
68
+ name: 'Weapon',
69
+ tableName: 'weapons',
70
+ primaryKeys: ['id'],
71
+ properties: {
72
+ id: prop('number', 'id', ['id']),
73
+ name: prop('string', 'name', ['weapon_name']),
74
+ damage: prop('number', 'damage', ['damage']),
75
+ bearerId: prop('number', 'bearerId', ['bearer_id']),
76
+ bearer: prop('Person', 'bearer', ['bearer_id'], {
77
+ referenceType: ReferenceType.MANY_TO_ONE,
78
+ joinColumns: ['bearer_id'],
79
+ referencedColumnNames: ['id'],
80
+ }),
81
+ },
82
+ };
83
+
84
+ export const PersonMetadata: EntityMetadata<Person> = {
85
+ name: 'Person',
86
+ tableName: 'persons',
87
+ primaryKeys: ['id'],
88
+ properties: {
89
+ id: prop('number', 'id', ['id']),
90
+ name: prop('string', 'name', ['person_name']),
91
+ },
92
+ };
93
+
94
+ // ─────────────────────────────────────────────────────────────────────────────
95
+ // 3. FIELDS SETTINGS (schema/fields.ts)
96
+ // How each field maps to GraphQL. Pass to createGQLTypes.
97
+ // ─────────────────────────────────────────────────────────────────────────────
98
+
99
+ // Create PersonGQL first (Weapon references it)
100
+ export const PersonGQL = createGQLTypes(Person, {
101
+ id: { type: () => Number, generateFilter: true },
102
+ name: { type: () => String, generateFilter: true },
103
+ });
104
+
105
+ export const WeaponFields: Partial<FieldsSettings<Weapon>> = {
106
+ id: { type: () => Number, generateFilter: true },
107
+ name: { type: () => String, generateFilter: true },
108
+ damage: { type: () => Int, generateFilter: true },
109
+ bearer: {
110
+ type: () => PersonGQL.GQLEntity,
111
+ options: { nullable: true },
112
+ generateFilter: true,
113
+ relatedEntityName: () => Person.name,
114
+ getFilterType: () => Int,
115
+ },
116
+ };
117
+
118
+ // ─────────────────────────────────────────────────────────────────────────────
119
+ // 4. WIRE + RESOLVE (graphql/entities.ts, graphql/resolvers.ts)
120
+ // ─────────────────────────────────────────────────────────────────────────────
121
+
122
+ export const WeaponGQL = createGQLTypes(Weapon, WeaponFields);
123
+
124
+ @Resolver(() => WeaponGQL.GQLEntity || Object)
125
+ export class WeaponResolver extends WeaponGQL.FieldsResolver {
126
+ @Query(() => [WeaponGQL.GQLEntity])
127
+ async weapons(
128
+ @Info() info: GraphQLResolveInfo,
129
+ @Arg('filter', () => WeaponGQL.GQLEntityFilterInput || Object, { nullable: true })
130
+ filter?: GQLEntityFilterInputFieldType<Weapon>
131
+ ) {
132
+ // Relationship-field filters need `as any` (the type doesn't surface them):
133
+ // { bearer: { name: 'Aragorn' } } as any
134
+ return await queryManager.getQueryResultsForInfo(provider, Weapon, info, filter);
135
+ }
136
+ }
@@ -1,5 +1,6 @@
1
1
  import { getMetadataStorage } from 'type-graphql';
2
- import { CustomFieldsSettings, FieldSettings, FieldsSettings, GQLEntityFilterInputFieldType, GQLEntityPaginationInputType, RelatedFieldSettings } from '../types';
2
+ import { CountFieldMeta, CustomFieldsSettings, FieldSettings, FieldsSettings, RelatedFieldSettings } from '../types/sql-types';
3
+ import { GQLEntityFilterInputFieldType, GQLEntityPaginationInputType } from '../types/gql-types';
3
4
  import { AccessControlEntry } from '../types/access-control';
4
5
  export declare const setGlobalConfig: (config: {
5
6
  gqlTypesSuffix?: string;
@@ -8,6 +9,26 @@ export declare const setGlobalConfig: (config: {
8
9
  export declare const getFieldsOptionsFor: (name: string) => Record<string, string>;
9
10
  export declare const getFieldByAlias: (entityName: string | undefined, alias: string) => string;
10
11
  export declare const getCustomFieldsFor: (name: string) => CustomFieldsSettings<any>;
12
+ /**
13
+ * Returns the count fields registered for the given GQL entity name.
14
+ * Keyed by the count field name (e.g. 'bookCount'), value is the count field metadata.
15
+ */
16
+ export declare const getCountFieldsFor: (name: string) => Record<string, CountFieldMeta>;
17
+ /**
18
+ * Manually registers a count field for an entity.
19
+ * Useful for testing without the @GQLEntityClass decorator.
20
+ * In production, count fields are auto-registered by the decorator when `countFieldName` is set.
21
+ */
22
+ export declare const registerCountField: (gqlEntityName: string, countFieldName: string, relationshipFieldName: string, relatedEntityName: () => string) => void;
23
+ /**
24
+ * Clears all registered count fields. Intended for test teardown.
25
+ */
26
+ export declare const clearCountFields: () => void;
27
+ export declare const getMapEnumFieldsFor: (name: string) => Record<string, any>;
28
+ export declare const clearMapEnumFields: () => void;
29
+ export declare const getParseJsonFieldsFor: (name: string) => Set<string>;
30
+ export declare const registerParseJsonField: (gqlEntityName: string, fieldName: string) => void;
31
+ export declare const clearParseJsonFields: () => void;
11
32
  export declare const getACLFor: (name: string) => AccessControlEntry<any, any>;
12
33
  export declare const getGQLEntityNameFor: (name: string) => string;
13
34
  export declare const getGQLEntityNameForClass: <T>(classType: new () => T) => string;
@@ -34,6 +55,7 @@ export type GQLEntityStaticMembers = {
34
55
  readonly FilterInput: new () => any;
35
56
  readonly PaginationInput: new () => any;
36
57
  readonly OrderBy: new () => any;
58
+ readonly Input: new () => any;
37
59
  readonly FieldsResolver: new () => any;
38
60
  readonly gqlEntityName: string;
39
61
  readonly relatedEntityName: string;
@@ -54,6 +76,7 @@ export declare abstract class GQLEntityBase {
54
76
  static FilterInput: new () => any;
55
77
  static PaginationInput: new () => any;
56
78
  static OrderBy: new () => any;
79
+ static Input: new () => any;
57
80
  static FieldsResolver: new () => any;
58
81
  static gqlEntityName: string;
59
82
  static relatedEntityName: string;
@@ -140,12 +163,14 @@ export declare function createGQLEntity<T extends Object, K>(classType: new () =
140
163
  GQLEntityOrderBy: {
141
164
  new (): {};
142
165
  };
166
+ GQLEntityInput: new () => any;
143
167
  FieldsResolver: {
144
168
  new (): {};
145
169
  };
146
170
  bindFieldResolvers: (_c: any) => void;
147
171
  };
148
172
  };
173
+ type TypeGQLMetadataStorage = ReturnType<typeof getMetadataStorage>;
149
174
  /**
150
175
  * Convenience wrapper — creates entity, builds resolvers, and returns everything merged.
151
176
  * Equivalent to calling `createGQLEntity(...).buildResolvers()` and merging results.
@@ -160,6 +185,7 @@ export declare function createGQLTypes<T extends Object, K>(classType: new () =>
160
185
  GQLEntityOrderBy: {
161
186
  new (): {};
162
187
  };
188
+ GQLEntityInput: new () => any;
163
189
  FieldsResolver: {
164
190
  new (): {};
165
191
  };
@@ -177,13 +203,13 @@ export declare function createGQLTypes<T extends Object, K>(classType: new () =>
177
203
  GQLEntityOrderBy: {
178
204
  new (): {};
179
205
  };
206
+ GQLEntityInput: new () => any;
180
207
  FieldsResolver: {
181
208
  new (): {};
182
209
  };
183
210
  bindFieldResolvers: (_c: any) => void;
184
211
  };
185
212
  };
186
- type TypeGQLMetadataStorage = ReturnType<typeof getMetadataStorage>;
187
213
  /**
188
214
  * Creates filter and sorting metadata for a field. Called during buildResolvers().
189
215
  */