@constructive-io/graphql-codegen 2.18.0 → 2.20.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 (301) hide show
  1. package/README.md +1818 -113
  2. package/__tests__/codegen/input-types-generator.test.d.ts +1 -0
  3. package/__tests__/codegen/input-types-generator.test.js +635 -0
  4. package/cli/codegen/barrel.d.ts +27 -0
  5. package/cli/codegen/barrel.js +163 -0
  6. package/cli/codegen/client.d.ts +4 -0
  7. package/cli/codegen/client.js +170 -0
  8. package/cli/codegen/custom-mutations.d.ts +38 -0
  9. package/cli/codegen/custom-mutations.js +149 -0
  10. package/cli/codegen/custom-queries.d.ts +38 -0
  11. package/cli/codegen/custom-queries.js +358 -0
  12. package/cli/codegen/filters.d.ts +27 -0
  13. package/cli/codegen/filters.js +357 -0
  14. package/cli/codegen/gql-ast.d.ts +41 -0
  15. package/cli/codegen/gql-ast.js +329 -0
  16. package/cli/codegen/index.d.ts +71 -0
  17. package/cli/codegen/index.js +147 -0
  18. package/cli/codegen/mutations.d.ts +30 -0
  19. package/cli/codegen/mutations.js +410 -0
  20. package/cli/codegen/orm/barrel.d.ts +18 -0
  21. package/cli/codegen/orm/barrel.js +48 -0
  22. package/cli/codegen/orm/client-generator.d.ts +45 -0
  23. package/cli/codegen/orm/client-generator.js +646 -0
  24. package/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
  25. package/cli/codegen/orm/custom-ops-generator.js +350 -0
  26. package/cli/codegen/orm/index.d.ts +38 -0
  27. package/cli/codegen/orm/index.js +88 -0
  28. package/cli/codegen/orm/input-types-generator.d.ts +21 -0
  29. package/cli/codegen/orm/input-types-generator.js +705 -0
  30. package/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
  31. package/cli/codegen/orm/input-types-generator.test.js +75 -0
  32. package/cli/codegen/orm/model-generator.d.ts +32 -0
  33. package/cli/codegen/orm/model-generator.js +264 -0
  34. package/cli/codegen/orm/query-builder.d.ts +161 -0
  35. package/cli/codegen/orm/query-builder.js +366 -0
  36. package/cli/codegen/orm/select-types.d.ts +169 -0
  37. package/cli/codegen/orm/select-types.js +16 -0
  38. package/cli/codegen/orm/select-types.test.d.ts +11 -0
  39. package/cli/codegen/orm/select-types.test.js +22 -0
  40. package/cli/codegen/queries.d.ts +25 -0
  41. package/cli/codegen/queries.js +438 -0
  42. package/cli/codegen/scalars.d.ts +12 -0
  43. package/cli/codegen/scalars.js +71 -0
  44. package/cli/codegen/schema-gql-ast.d.ts +51 -0
  45. package/cli/codegen/schema-gql-ast.js +385 -0
  46. package/cli/codegen/ts-ast.d.ts +122 -0
  47. package/cli/codegen/ts-ast.js +280 -0
  48. package/cli/codegen/type-resolver.d.ts +96 -0
  49. package/cli/codegen/type-resolver.js +246 -0
  50. package/cli/codegen/types.d.ts +12 -0
  51. package/cli/codegen/types.js +69 -0
  52. package/cli/codegen/utils.d.ts +163 -0
  53. package/cli/codegen/utils.js +326 -0
  54. package/cli/commands/generate-orm.d.ts +37 -0
  55. package/cli/commands/generate-orm.js +195 -0
  56. package/cli/commands/generate.d.ts +39 -0
  57. package/cli/commands/generate.js +299 -0
  58. package/cli/commands/index.d.ts +7 -0
  59. package/cli/commands/index.js +12 -0
  60. package/cli/commands/init.d.ts +35 -0
  61. package/cli/commands/init.js +176 -0
  62. package/cli/index.d.ts +4 -0
  63. package/cli/index.js +291 -0
  64. package/cli/introspect/fetch-meta.d.ts +31 -0
  65. package/cli/introspect/fetch-meta.js +108 -0
  66. package/cli/introspect/fetch-schema.d.ts +21 -0
  67. package/cli/introspect/fetch-schema.js +86 -0
  68. package/cli/introspect/index.d.ts +8 -0
  69. package/cli/introspect/index.js +16 -0
  70. package/cli/introspect/meta-query.d.ts +111 -0
  71. package/cli/introspect/meta-query.js +191 -0
  72. package/cli/introspect/schema-query.d.ts +20 -0
  73. package/cli/introspect/schema-query.js +123 -0
  74. package/cli/introspect/transform-schema.d.ts +74 -0
  75. package/cli/introspect/transform-schema.js +269 -0
  76. package/cli/introspect/transform-schema.test.d.ts +1 -0
  77. package/cli/introspect/transform-schema.test.js +67 -0
  78. package/cli/introspect/transform.d.ts +21 -0
  79. package/cli/introspect/transform.js +216 -0
  80. package/cli/watch/cache.d.ts +45 -0
  81. package/cli/watch/cache.js +111 -0
  82. package/cli/watch/debounce.d.ts +19 -0
  83. package/cli/watch/debounce.js +89 -0
  84. package/cli/watch/hash.d.ts +17 -0
  85. package/cli/watch/hash.js +48 -0
  86. package/cli/watch/index.d.ts +10 -0
  87. package/cli/watch/index.js +22 -0
  88. package/cli/watch/orchestrator.d.ts +63 -0
  89. package/cli/watch/orchestrator.js +228 -0
  90. package/cli/watch/poller.d.ts +65 -0
  91. package/cli/watch/poller.js +203 -0
  92. package/cli/watch/types.d.ts +67 -0
  93. package/cli/watch/types.js +5 -0
  94. package/client/error.d.ts +95 -0
  95. package/client/error.js +255 -0
  96. package/client/execute.d.ts +57 -0
  97. package/client/execute.js +124 -0
  98. package/client/index.d.ts +6 -0
  99. package/client/index.js +18 -0
  100. package/client/typed-document.d.ts +31 -0
  101. package/client/typed-document.js +44 -0
  102. package/core/ast.d.ts +10 -0
  103. package/core/ast.js +593 -0
  104. package/core/custom-ast.d.ts +35 -0
  105. package/core/custom-ast.js +204 -0
  106. package/core/index.d.ts +8 -0
  107. package/core/index.js +33 -0
  108. package/core/meta-object/convert.d.ts +65 -0
  109. package/core/meta-object/convert.js +63 -0
  110. package/core/meta-object/format.json +93 -0
  111. package/core/meta-object/index.d.ts +2 -0
  112. package/core/meta-object/index.js +18 -0
  113. package/core/meta-object/validate.d.ts +9 -0
  114. package/core/meta-object/validate.js +34 -0
  115. package/core/query-builder.d.ts +46 -0
  116. package/core/query-builder.js +412 -0
  117. package/core/types.d.ts +139 -0
  118. package/core/types.js +28 -0
  119. package/esm/__tests__/codegen/input-types-generator.test.d.ts +1 -0
  120. package/esm/__tests__/codegen/input-types-generator.test.js +633 -0
  121. package/esm/cli/codegen/barrel.d.ts +27 -0
  122. package/esm/cli/codegen/barrel.js +156 -0
  123. package/esm/cli/codegen/client.d.ts +4 -0
  124. package/esm/cli/codegen/client.js +167 -0
  125. package/esm/cli/codegen/custom-mutations.d.ts +38 -0
  126. package/esm/cli/codegen/custom-mutations.js +145 -0
  127. package/esm/cli/codegen/custom-queries.d.ts +38 -0
  128. package/esm/cli/codegen/custom-queries.js +354 -0
  129. package/esm/cli/codegen/filters.d.ts +27 -0
  130. package/esm/cli/codegen/filters.js +351 -0
  131. package/esm/cli/codegen/gql-ast.d.ts +41 -0
  132. package/esm/cli/codegen/gql-ast.js +288 -0
  133. package/esm/cli/codegen/index.d.ts +71 -0
  134. package/esm/cli/codegen/index.js +124 -0
  135. package/esm/cli/codegen/mutations.d.ts +30 -0
  136. package/esm/cli/codegen/mutations.js +404 -0
  137. package/esm/cli/codegen/orm/barrel.d.ts +18 -0
  138. package/esm/cli/codegen/orm/barrel.js +44 -0
  139. package/esm/cli/codegen/orm/client-generator.d.ts +45 -0
  140. package/esm/cli/codegen/orm/client-generator.js +640 -0
  141. package/esm/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
  142. package/esm/cli/codegen/orm/custom-ops-generator.js +346 -0
  143. package/esm/cli/codegen/orm/index.d.ts +38 -0
  144. package/esm/cli/codegen/orm/index.js +75 -0
  145. package/esm/cli/codegen/orm/input-types-generator.d.ts +21 -0
  146. package/esm/cli/codegen/orm/input-types-generator.js +700 -0
  147. package/esm/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
  148. package/esm/cli/codegen/orm/input-types-generator.test.js +73 -0
  149. package/esm/cli/codegen/orm/model-generator.d.ts +32 -0
  150. package/esm/cli/codegen/orm/model-generator.js +260 -0
  151. package/esm/cli/codegen/orm/query-builder.d.ts +161 -0
  152. package/esm/cli/codegen/orm/query-builder.js +353 -0
  153. package/esm/cli/codegen/orm/select-types.d.ts +169 -0
  154. package/esm/cli/codegen/orm/select-types.js +15 -0
  155. package/esm/cli/codegen/orm/select-types.test.d.ts +11 -0
  156. package/esm/cli/codegen/orm/select-types.test.js +21 -0
  157. package/esm/cli/codegen/queries.d.ts +25 -0
  158. package/esm/cli/codegen/queries.js +433 -0
  159. package/esm/cli/codegen/scalars.d.ts +12 -0
  160. package/esm/cli/codegen/scalars.js +66 -0
  161. package/esm/cli/codegen/schema-gql-ast.d.ts +51 -0
  162. package/esm/cli/codegen/schema-gql-ast.js +343 -0
  163. package/esm/cli/codegen/ts-ast.d.ts +122 -0
  164. package/esm/cli/codegen/ts-ast.js +260 -0
  165. package/esm/cli/codegen/type-resolver.d.ts +96 -0
  166. package/esm/cli/codegen/type-resolver.js +224 -0
  167. package/esm/cli/codegen/types.d.ts +12 -0
  168. package/esm/cli/codegen/types.js +65 -0
  169. package/esm/cli/codegen/utils.d.ts +163 -0
  170. package/esm/cli/codegen/utils.js +288 -0
  171. package/esm/cli/commands/generate-orm.d.ts +37 -0
  172. package/esm/cli/commands/generate-orm.js +192 -0
  173. package/esm/cli/commands/generate.d.ts +39 -0
  174. package/esm/cli/commands/generate.js +262 -0
  175. package/esm/cli/commands/index.d.ts +7 -0
  176. package/esm/cli/commands/index.js +5 -0
  177. package/esm/cli/commands/init.d.ts +35 -0
  178. package/esm/cli/commands/init.js +138 -0
  179. package/esm/cli/index.d.ts +4 -0
  180. package/esm/cli/index.js +256 -0
  181. package/esm/cli/introspect/fetch-meta.d.ts +31 -0
  182. package/esm/cli/introspect/fetch-meta.js +104 -0
  183. package/esm/cli/introspect/fetch-schema.d.ts +21 -0
  184. package/esm/cli/introspect/fetch-schema.js +83 -0
  185. package/esm/cli/introspect/index.d.ts +8 -0
  186. package/esm/cli/introspect/index.js +6 -0
  187. package/esm/cli/introspect/meta-query.d.ts +111 -0
  188. package/esm/cli/introspect/meta-query.js +188 -0
  189. package/esm/cli/introspect/schema-query.d.ts +20 -0
  190. package/esm/cli/introspect/schema-query.js +120 -0
  191. package/esm/cli/introspect/transform-schema.d.ts +74 -0
  192. package/esm/cli/introspect/transform-schema.js +259 -0
  193. package/esm/cli/introspect/transform-schema.test.d.ts +1 -0
  194. package/esm/cli/introspect/transform-schema.test.js +65 -0
  195. package/esm/cli/introspect/transform.d.ts +21 -0
  196. package/esm/cli/introspect/transform.js +210 -0
  197. package/esm/cli/watch/cache.d.ts +45 -0
  198. package/esm/cli/watch/cache.js +73 -0
  199. package/esm/cli/watch/debounce.d.ts +19 -0
  200. package/esm/cli/watch/debounce.js +85 -0
  201. package/esm/cli/watch/hash.d.ts +17 -0
  202. package/esm/cli/watch/hash.js +43 -0
  203. package/esm/cli/watch/index.d.ts +10 -0
  204. package/esm/cli/watch/index.js +8 -0
  205. package/esm/cli/watch/orchestrator.d.ts +63 -0
  206. package/esm/cli/watch/orchestrator.js +223 -0
  207. package/esm/cli/watch/poller.d.ts +65 -0
  208. package/esm/cli/watch/poller.js +198 -0
  209. package/esm/cli/watch/types.d.ts +67 -0
  210. package/esm/cli/watch/types.js +4 -0
  211. package/esm/client/error.d.ts +95 -0
  212. package/esm/client/error.js +249 -0
  213. package/esm/client/execute.d.ts +57 -0
  214. package/esm/client/execute.js +120 -0
  215. package/esm/client/index.d.ts +6 -0
  216. package/esm/client/index.js +6 -0
  217. package/esm/client/typed-document.d.ts +31 -0
  218. package/esm/client/typed-document.js +40 -0
  219. package/esm/core/ast.d.ts +10 -0
  220. package/esm/core/ast.js +549 -0
  221. package/esm/core/custom-ast.d.ts +35 -0
  222. package/esm/core/custom-ast.js +161 -0
  223. package/esm/core/index.d.ts +8 -0
  224. package/esm/core/index.js +12 -0
  225. package/esm/core/meta-object/convert.d.ts +65 -0
  226. package/esm/core/meta-object/convert.js +60 -0
  227. package/esm/core/meta-object/format.json +93 -0
  228. package/esm/core/meta-object/index.d.ts +2 -0
  229. package/esm/core/meta-object/index.js +2 -0
  230. package/esm/core/meta-object/validate.d.ts +9 -0
  231. package/esm/core/meta-object/validate.js +28 -0
  232. package/esm/core/query-builder.d.ts +46 -0
  233. package/esm/core/query-builder.js +375 -0
  234. package/esm/core/types.d.ts +139 -0
  235. package/esm/core/types.js +24 -0
  236. package/esm/generators/field-selector.d.ts +30 -0
  237. package/esm/generators/field-selector.js +355 -0
  238. package/esm/generators/index.d.ts +6 -0
  239. package/esm/generators/index.js +9 -0
  240. package/esm/generators/mutations.d.ts +31 -0
  241. package/esm/generators/mutations.js +197 -0
  242. package/esm/generators/select.d.ts +50 -0
  243. package/esm/generators/select.js +636 -0
  244. package/esm/index.d.ts +12 -0
  245. package/esm/index.js +17 -3
  246. package/esm/react/index.d.ts +5 -0
  247. package/esm/react/index.js +6 -0
  248. package/esm/types/config.d.ts +199 -0
  249. package/esm/types/config.js +106 -0
  250. package/esm/types/index.d.ts +9 -0
  251. package/esm/types/index.js +4 -0
  252. package/esm/types/introspection.d.ts +121 -0
  253. package/esm/types/introspection.js +54 -0
  254. package/esm/types/mutation.d.ts +45 -0
  255. package/esm/types/mutation.js +4 -0
  256. package/esm/types/query.d.ts +82 -0
  257. package/esm/types/query.js +4 -0
  258. package/esm/types/schema.d.ts +253 -0
  259. package/esm/types/schema.js +5 -0
  260. package/esm/types/selection.d.ts +43 -0
  261. package/esm/types/selection.js +4 -0
  262. package/esm/utils/index.d.ts +4 -0
  263. package/esm/utils/index.js +4 -0
  264. package/generators/field-selector.d.ts +30 -0
  265. package/generators/field-selector.js +361 -0
  266. package/generators/index.d.ts +6 -0
  267. package/generators/index.js +27 -0
  268. package/generators/mutations.d.ts +31 -0
  269. package/generators/mutations.js +235 -0
  270. package/generators/select.d.ts +50 -0
  271. package/generators/select.js +679 -0
  272. package/index.d.ts +12 -3
  273. package/index.js +19 -3
  274. package/package.json +59 -38
  275. package/react/index.d.ts +5 -0
  276. package/react/index.js +9 -0
  277. package/types/config.d.ts +199 -0
  278. package/types/config.js +111 -0
  279. package/types/index.d.ts +9 -0
  280. package/types/index.js +10 -0
  281. package/types/introspection.d.ts +121 -0
  282. package/types/introspection.js +62 -0
  283. package/types/mutation.d.ts +45 -0
  284. package/types/mutation.js +5 -0
  285. package/types/query.d.ts +82 -0
  286. package/types/query.js +5 -0
  287. package/types/schema.d.ts +253 -0
  288. package/types/schema.js +6 -0
  289. package/types/selection.d.ts +43 -0
  290. package/types/selection.js +5 -0
  291. package/utils/index.d.ts +4 -0
  292. package/utils/index.js +7 -0
  293. package/codegen.d.ts +0 -13
  294. package/codegen.js +0 -293
  295. package/esm/codegen.js +0 -253
  296. package/esm/gql.js +0 -939
  297. package/esm/options.js +0 -27
  298. package/gql.d.ts +0 -188
  299. package/gql.js +0 -992
  300. package/options.d.ts +0 -45
  301. package/options.js +0 -31
@@ -0,0 +1,375 @@
1
+ import { print as gqlPrint } from 'graphql';
2
+ import * as inflection from 'inflection';
3
+ import { createOne, deleteOne, getAll, getCount, getMany, getOne, patchOne, } from './ast';
4
+ import { validateMetaObject } from './meta-object';
5
+ export * as MetaObject from './meta-object';
6
+ const isObject = (val) => val !== null && typeof val === 'object';
7
+ export class QueryBuilder {
8
+ _introspection;
9
+ _meta;
10
+ _models;
11
+ _model;
12
+ _key;
13
+ _queryName;
14
+ _ast;
15
+ _edges;
16
+ _op;
17
+ _mutation;
18
+ _select;
19
+ constructor({ meta = {}, introspection, }) {
20
+ this._introspection = introspection;
21
+ this._meta = meta;
22
+ this.clear();
23
+ this.initModelMap();
24
+ this.pickScalarFields = pickScalarFields.bind(this);
25
+ this.pickAllFields = pickAllFields.bind(this);
26
+ const result = validateMetaObject(this._meta);
27
+ if (typeof result === 'object' && result.errors) {
28
+ throw new Error(`QueryBuilder: meta object is invalid:\n${result.message}`);
29
+ }
30
+ }
31
+ /*
32
+ * Save all gql queries and mutations by model name for quicker lookup
33
+ */
34
+ initModelMap() {
35
+ this._models = {};
36
+ for (const [key, defn] of Object.entries(this._introspection)) {
37
+ if (!this._models[defn.model]) {
38
+ this._models[defn.model] = {};
39
+ }
40
+ this._models[defn.model][key] = defn;
41
+ }
42
+ }
43
+ clear() {
44
+ this._model = '';
45
+ this._key = null;
46
+ this._queryName = '';
47
+ this._ast = null;
48
+ this._edges = false;
49
+ this._op = '';
50
+ this._mutation = '';
51
+ this._select = [];
52
+ }
53
+ query(model) {
54
+ this.clear();
55
+ this._model = model;
56
+ return this;
57
+ }
58
+ _findQuery() {
59
+ // based on the op, finds the relevant GQL query
60
+ const queries = this._models[this._model];
61
+ if (!queries) {
62
+ throw new Error('No queries found for ' + this._model);
63
+ }
64
+ const matchQuery = Object.entries(queries).find(([_, defn]) => defn.qtype === this._op);
65
+ if (!matchQuery) {
66
+ throw new Error('No query found for ' + this._model + ':' + this._op);
67
+ }
68
+ const queryKey = matchQuery[0];
69
+ return queryKey;
70
+ }
71
+ _findMutation() {
72
+ // For mutation, there can be many defns that match the operation being requested
73
+ // .ie: deleteAction, deleteActionBySlug, deleteActionByName
74
+ const matchingDefns = Object.keys(this._introspection).reduce((arr, mutationKey) => {
75
+ const defn = this._introspection[mutationKey];
76
+ if (defn.model === this._model &&
77
+ defn.qtype === this._op &&
78
+ defn.qtype === 'mutation' &&
79
+ defn.mutationType === this._mutation) {
80
+ arr = [...arr, { defn, mutationKey }];
81
+ }
82
+ return arr;
83
+ }, []);
84
+ if (matchingDefns.length === 0) {
85
+ throw new Error('no mutation found for ' + this._model + ':' + this._mutation);
86
+ }
87
+ // We only need deleteAction from all of [deleteAction, deleteActionBySlug, deleteActionByName]
88
+ const getInputName = (mutationType) => {
89
+ switch (mutationType) {
90
+ case 'delete': {
91
+ return `Delete${inflection.camelize(this._model)}Input`;
92
+ }
93
+ case 'create': {
94
+ return `Create${inflection.camelize(this._model)}Input`;
95
+ }
96
+ case 'patch': {
97
+ return `Update${inflection.camelize(this._model)}Input`;
98
+ }
99
+ default:
100
+ throw new Error('Unhandled mutation type' + mutationType);
101
+ }
102
+ };
103
+ const matchDefn = matchingDefns.find(({ defn }) => defn.properties.input.type === getInputName(this._mutation));
104
+ if (!matchDefn) {
105
+ throw new Error('no mutation found for ' + this._model + ':' + this._mutation);
106
+ }
107
+ return matchDefn.mutationKey;
108
+ }
109
+ select(selection) {
110
+ const defn = this._introspection[this._key];
111
+ // If selection not given, pick only scalar fields
112
+ if (selection == null) {
113
+ this._select = this.pickScalarFields(null, defn);
114
+ return this;
115
+ }
116
+ this._select = this.pickAllFields(selection, defn);
117
+ return this;
118
+ }
119
+ edges(useEdges) {
120
+ this._edges = useEdges;
121
+ return this;
122
+ }
123
+ getMany({ select } = {}) {
124
+ this._op = 'getMany';
125
+ this._key = this._findQuery();
126
+ this.queryName(inflection.camelize(['get', inflection.underscore(this._key), 'query'].join('_'), true));
127
+ const defn = this._introspection[this._key];
128
+ this.select(select);
129
+ this._ast = getMany({
130
+ builder: this,
131
+ queryName: this._queryName,
132
+ operationName: this._key,
133
+ query: defn,
134
+ selection: this._select,
135
+ });
136
+ return this;
137
+ }
138
+ all({ select } = {}) {
139
+ this._op = 'getMany';
140
+ this._key = this._findQuery();
141
+ this.queryName(inflection.camelize(['get', inflection.underscore(this._key), 'query', 'all'].join('_'), true));
142
+ const defn = this._introspection[this._key];
143
+ this.select(select);
144
+ this._ast = getAll({
145
+ queryName: this._queryName,
146
+ operationName: this._key,
147
+ query: defn,
148
+ selection: this._select,
149
+ });
150
+ return this;
151
+ }
152
+ count() {
153
+ this._op = 'getMany';
154
+ this._key = this._findQuery();
155
+ this.queryName(inflection.camelize(['get', inflection.underscore(this._key), 'count', 'query'].join('_'), true));
156
+ const defn = this._introspection[this._key];
157
+ this._ast = getCount({
158
+ queryName: this._queryName,
159
+ operationName: this._key,
160
+ query: defn,
161
+ });
162
+ return this;
163
+ }
164
+ getOne({ select } = {}) {
165
+ this._op = 'getOne';
166
+ this._key = this._findQuery();
167
+ this.queryName(inflection.camelize(['get', inflection.underscore(this._key), 'query'].join('_'), true));
168
+ const defn = this._introspection[this._key];
169
+ this.select(select);
170
+ this._ast = getOne({
171
+ builder: this,
172
+ queryName: this._queryName,
173
+ operationName: this._key,
174
+ query: defn,
175
+ selection: this._select,
176
+ });
177
+ return this;
178
+ }
179
+ create({ select } = {}) {
180
+ this._op = 'mutation';
181
+ this._mutation = 'create';
182
+ this._key = this._findMutation();
183
+ this.queryName(inflection.camelize([inflection.underscore(this._key), 'mutation'].join('_'), true));
184
+ const defn = this._introspection[this._key];
185
+ this.select(select);
186
+ this._ast = createOne({
187
+ operationName: this._key,
188
+ mutationName: this._queryName,
189
+ mutation: defn,
190
+ selection: this._select,
191
+ });
192
+ return this;
193
+ }
194
+ delete({ select } = {}) {
195
+ this._op = 'mutation';
196
+ this._mutation = 'delete';
197
+ this._key = this._findMutation();
198
+ this.queryName(inflection.camelize([inflection.underscore(this._key), 'mutation'].join('_'), true));
199
+ const defn = this._introspection[this._key];
200
+ this.select(select);
201
+ this._ast = deleteOne({
202
+ operationName: this._key,
203
+ mutationName: this._queryName,
204
+ mutation: defn,
205
+ });
206
+ return this;
207
+ }
208
+ update({ select } = {}) {
209
+ this._op = 'mutation';
210
+ this._mutation = 'patch';
211
+ this._key = this._findMutation();
212
+ this.queryName(inflection.camelize([inflection.underscore(this._key), 'mutation'].join('_'), true));
213
+ const defn = this._introspection[this._key];
214
+ this.select(select);
215
+ this._ast = patchOne({
216
+ operationName: this._key,
217
+ mutationName: this._queryName,
218
+ mutation: defn,
219
+ selection: this._select,
220
+ });
221
+ return this;
222
+ }
223
+ queryName(name) {
224
+ this._queryName = name;
225
+ return this;
226
+ }
227
+ print() {
228
+ if (!this._ast) {
229
+ throw new Error('No AST generated. Please call a query method first.');
230
+ }
231
+ const _hash = gqlPrint(this._ast);
232
+ return {
233
+ _hash,
234
+ _queryName: this._queryName,
235
+ _ast: this._ast,
236
+ };
237
+ }
238
+ // Bind methods that will be called with different this context
239
+ pickScalarFields;
240
+ pickAllFields;
241
+ }
242
+ /**
243
+ * Pick scalar fields of a query definition
244
+ * @param {Object} defn Query definition
245
+ * @param {Object} meta Meta object containing info about table relations
246
+ * @returns {Array}
247
+ */
248
+ function pickScalarFields(selection, defn) {
249
+ const model = defn.model;
250
+ const modelMeta = this._meta.tables.find((t) => t.name === model);
251
+ if (!modelMeta) {
252
+ throw new Error(`Model meta not found for ${model}`);
253
+ }
254
+ const isInTableSchema = (fieldName) => !!modelMeta.fields.find((field) => field.name === fieldName);
255
+ const pickFrom = (modelSelection) => modelSelection
256
+ .filter((fieldName) => {
257
+ // If not specified or not a valid selection list, allow all
258
+ if (selection == null || !Array.isArray(selection))
259
+ return true;
260
+ return Object.keys(selection).includes(fieldName);
261
+ })
262
+ .filter((fieldName) => !isRelationalField(fieldName, modelMeta) &&
263
+ isInTableSchema(fieldName))
264
+ .map((fieldName) => ({
265
+ name: fieldName,
266
+ isObject: false,
267
+ fieldDefn: modelMeta.fields.find((f) => f.name === fieldName),
268
+ }));
269
+ // This is for inferring the sub-selection of a mutation query
270
+ // from a definition model .eg UserSetting, find its related queries in the introspection object, and pick its selection fields
271
+ if (defn.qtype === 'mutation') {
272
+ const relatedQuery = this._introspection[`${modelNameToGetMany(defn.model)}`];
273
+ return pickFrom(relatedQuery.selection);
274
+ }
275
+ return pickFrom(defn.selection);
276
+ }
277
+ /**
278
+ * Pick scalar fields and sub-selection fields of a query definition
279
+ * @param {Object} selection Selection clause object
280
+ * @param {Object} defn Query definition
281
+ * @param {Object} meta Meta object containing info about table relations
282
+ * @returns {Array}
283
+ */
284
+ function pickAllFields(selection, defn) {
285
+ const model = defn.model;
286
+ const modelMeta = this._meta.tables.find((t) => t.name === model);
287
+ if (!modelMeta) {
288
+ throw new Error(`Model meta not found for ${model}`);
289
+ }
290
+ const selectionEntries = Object.entries(selection);
291
+ let fields = [];
292
+ const isWhiteListed = (selectValue) => {
293
+ return typeof selectValue === 'boolean' && selectValue;
294
+ };
295
+ for (const entry of selectionEntries) {
296
+ const [fieldName, fieldOptions] = entry;
297
+ // Case
298
+ // {
299
+ // goalResults: // fieldName
300
+ // { select: { id: true }, variables: { first: 100 } } // fieldOptions
301
+ // }
302
+ if (isObject(fieldOptions)) {
303
+ if (!isFieldInDefinition(fieldName, defn, modelMeta)) {
304
+ continue;
305
+ }
306
+ const referencedForeignConstraint = modelMeta.foreignConstraints.find((constraint) => constraint.fromKey.name === fieldName ||
307
+ constraint.fromKey.alias === fieldName);
308
+ const selectOptions = fieldOptions;
309
+ const subFields = Object.keys(selectOptions.select).filter((subField) => {
310
+ return (!isRelationalField(subField, modelMeta) &&
311
+ isWhiteListed(selectOptions.select[subField]));
312
+ });
313
+ const isBelongTo = !!referencedForeignConstraint;
314
+ const fieldSelection = {
315
+ name: fieldName,
316
+ isObject: true,
317
+ isBelongTo,
318
+ selection: subFields.map((name) => ({ name, isObject: false })),
319
+ variables: selectOptions.variables,
320
+ };
321
+ // Need to further expand selection of object fields,
322
+ // but only non-graphql-builtin, non-relation fields
323
+ // .ie action { id location }
324
+ // location is non-scalar and non-relational, thus need to further expand into { x y ... }
325
+ if (isBelongTo) {
326
+ const getManyName = modelNameToGetMany(referencedForeignConstraint.refTable);
327
+ const refDefn = this._introspection[getManyName];
328
+ fieldSelection.selection = pickScalarFields.call(this, { [fieldName]: true }, refDefn);
329
+ }
330
+ fields = [...fields, fieldSelection];
331
+ }
332
+ else {
333
+ // Case
334
+ // {
335
+ // userId: true // [fieldName, fieldOptions]
336
+ // }
337
+ if (isWhiteListed(fieldOptions)) {
338
+ fields = [
339
+ ...fields,
340
+ {
341
+ name: fieldName,
342
+ isObject: false,
343
+ fieldDefn: modelMeta.fields.find((f) => f.name === fieldName),
344
+ },
345
+ ];
346
+ }
347
+ }
348
+ }
349
+ return fields;
350
+ }
351
+ function isFieldInDefinition(fieldName, defn, modelMeta) {
352
+ const isReferenced = !!modelMeta.foreignConstraints.find((constraint) => constraint.fromKey.name === fieldName ||
353
+ constraint.fromKey.alias === fieldName);
354
+ return (isReferenced ||
355
+ defn.selection.some((selectionItem) => {
356
+ if (typeof selectionItem === 'string') {
357
+ return fieldName === selectionItem;
358
+ }
359
+ if (isObject(selectionItem)) {
360
+ return selectionItem.name === fieldName;
361
+ }
362
+ return false;
363
+ }));
364
+ }
365
+ // TODO: see if there is a possibility of supertyping table (a key is both a foreign and primary key)
366
+ // A relational field is a foreign key but not a primary key
367
+ function isRelationalField(fieldName, modelMeta) {
368
+ return (!modelMeta.primaryConstraints.find((field) => field.name === fieldName) &&
369
+ !!modelMeta.foreignConstraints.find((constraint) => constraint.fromKey.name === fieldName));
370
+ }
371
+ // Get getMany op name from model
372
+ // ie. UserSetting => userSettings
373
+ function modelNameToGetMany(model) {
374
+ return inflection.camelize(inflection.pluralize(inflection.underscore(model)), true);
375
+ }
@@ -0,0 +1,139 @@
1
+ import type { DocumentNode, FieldNode, SelectionSetNode, VariableDefinitionNode } from 'graphql';
2
+ import type { CleanField } from '../types/schema';
3
+ export type ASTNode = DocumentNode | FieldNode | SelectionSetNode | VariableDefinitionNode;
4
+ export interface NestedProperties {
5
+ [key: string]: QueryProperty | NestedProperties;
6
+ }
7
+ export interface QueryProperty {
8
+ name: string;
9
+ type: string;
10
+ isNotNull: boolean;
11
+ isArray: boolean;
12
+ isArrayNotNull: boolean;
13
+ properties?: NestedProperties;
14
+ }
15
+ export interface QueryDefinition {
16
+ model: string;
17
+ qtype: 'getMany' | 'getOne' | 'mutation';
18
+ mutationType?: 'create' | 'patch' | 'delete';
19
+ selection: string[];
20
+ properties: Record<string, QueryProperty>;
21
+ }
22
+ export interface MutationDefinition extends QueryDefinition {
23
+ qtype: 'mutation';
24
+ mutationType: 'create' | 'patch' | 'delete';
25
+ }
26
+ export interface IntrospectionSchema {
27
+ [key: string]: QueryDefinition | MutationDefinition;
28
+ }
29
+ export interface MetaFieldType {
30
+ gqlType: string;
31
+ isArray: boolean;
32
+ modifier?: string | number | null;
33
+ pgAlias?: string | null;
34
+ pgType?: string | null;
35
+ subtype?: string | null;
36
+ typmod?: number | null;
37
+ }
38
+ export interface MetaField {
39
+ name: string;
40
+ type: MetaFieldType;
41
+ }
42
+ export interface MetaConstraint {
43
+ name: string;
44
+ type: MetaFieldType;
45
+ alias?: string;
46
+ }
47
+ export interface MetaForeignConstraint {
48
+ fromKey: MetaConstraint;
49
+ refTable: string;
50
+ toKey: MetaConstraint;
51
+ }
52
+ export interface MetaTable {
53
+ name: string;
54
+ fields: MetaField[];
55
+ primaryConstraints: MetaConstraint[];
56
+ uniqueConstraints: MetaConstraint[];
57
+ foreignConstraints: MetaForeignConstraint[];
58
+ }
59
+ export interface MetaObject {
60
+ tables: MetaTable[];
61
+ }
62
+ export type GraphQLVariableValue = string | number | boolean | null;
63
+ export interface GraphQLVariables {
64
+ [key: string]: GraphQLVariableValue | GraphQLVariableValue[] | GraphQLVariables | GraphQLVariables[];
65
+ }
66
+ export interface QueryFieldSelection {
67
+ name: string;
68
+ isObject: boolean;
69
+ fieldDefn?: MetaField | CleanField;
70
+ selection?: QueryFieldSelection[];
71
+ variables?: GraphQLVariables;
72
+ isBelongTo?: boolean;
73
+ }
74
+ export interface QuerySelectionOptions {
75
+ [fieldName: string]: boolean | {
76
+ select: Record<string, boolean>;
77
+ variables?: GraphQLVariables;
78
+ };
79
+ }
80
+ export interface QueryBuilderInstance {
81
+ _introspection: IntrospectionSchema;
82
+ _meta: MetaObject;
83
+ _edges?: boolean;
84
+ }
85
+ export interface ASTFunctionParams {
86
+ queryName: string;
87
+ operationName: string;
88
+ query: QueryDefinition;
89
+ selection: QueryFieldSelection[];
90
+ builder?: QueryBuilderInstance;
91
+ }
92
+ export interface MutationASTParams {
93
+ mutationName: string;
94
+ operationName: string;
95
+ mutation: MutationDefinition;
96
+ selection?: QueryFieldSelection[];
97
+ }
98
+ export interface QueryBuilderOptions {
99
+ meta: MetaObject;
100
+ introspection: IntrospectionSchema;
101
+ }
102
+ export interface QueryBuilderResult {
103
+ _hash: string;
104
+ _queryName: string;
105
+ _ast: DocumentNode;
106
+ }
107
+ export interface IQueryBuilder {
108
+ query(model: string): IQueryBuilder;
109
+ getMany(options?: {
110
+ select?: QuerySelectionOptions;
111
+ }): IQueryBuilder;
112
+ getOne(options?: {
113
+ select?: QuerySelectionOptions;
114
+ }): IQueryBuilder;
115
+ all(options?: {
116
+ select?: QuerySelectionOptions;
117
+ }): IQueryBuilder;
118
+ count(): IQueryBuilder;
119
+ create(options?: {
120
+ select?: QuerySelectionOptions;
121
+ }): IQueryBuilder;
122
+ update(options?: {
123
+ select?: QuerySelectionOptions;
124
+ }): IQueryBuilder;
125
+ delete(options?: {
126
+ select?: QuerySelectionOptions;
127
+ }): IQueryBuilder;
128
+ edges(useEdges: boolean): IQueryBuilder;
129
+ print(): QueryBuilderResult;
130
+ }
131
+ export interface ObjectArrayItem extends QueryProperty {
132
+ name: string;
133
+ key?: string;
134
+ }
135
+ export declare function isGraphQLVariableValue(value: unknown): value is GraphQLVariableValue;
136
+ export declare function isGraphQLVariables(obj: unknown): obj is GraphQLVariables;
137
+ export type StrictRecord<K extends PropertyKey, V> = Record<K, V> & {
138
+ [P in PropertyKey]: P extends K ? V : never;
139
+ };
@@ -0,0 +1,24 @@
1
+ // Type guards for runtime validation
2
+ export function isGraphQLVariableValue(value) {
3
+ return (value === null ||
4
+ typeof value === 'string' ||
5
+ typeof value === 'number' ||
6
+ typeof value === 'boolean');
7
+ }
8
+ export function isGraphQLVariables(obj) {
9
+ if (!obj || typeof obj !== 'object')
10
+ return false;
11
+ for (const [key, value] of Object.entries(obj)) {
12
+ if (typeof key !== 'string')
13
+ return false;
14
+ if (Array.isArray(value)) {
15
+ if (!value.every((item) => isGraphQLVariableValue(item) || isGraphQLVariables(item))) {
16
+ return false;
17
+ }
18
+ }
19
+ else if (!isGraphQLVariableValue(value) && !isGraphQLVariables(value)) {
20
+ return false;
21
+ }
22
+ }
23
+ return true;
24
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Simplified field selection system
3
+ * Converts user-friendly selection options to internal SelectionOptions format
4
+ */
5
+ import type { QuerySelectionOptions } from '../core/types';
6
+ import type { CleanTable } from '../types/schema';
7
+ import type { FieldSelection } from '../types/selection';
8
+ /**
9
+ * Convert simplified field selection to QueryBuilder SelectionOptions
10
+ */
11
+ export declare function convertToSelectionOptions(table: CleanTable, allTables: CleanTable[], selection?: FieldSelection): QuerySelectionOptions | null;
12
+ /**
13
+ * Check if a field is relational using table metadata
14
+ */
15
+ export declare function isRelationalField(fieldName: string, table: CleanTable): boolean;
16
+ /**
17
+ * Get all available relation fields from a table
18
+ */
19
+ export declare function getAvailableRelations(table: CleanTable): Array<{
20
+ fieldName: string;
21
+ type: 'belongsTo' | 'hasOne' | 'hasMany' | 'manyToMany';
22
+ referencedTable?: string;
23
+ }>;
24
+ /**
25
+ * Validate field selection against table schema
26
+ */
27
+ export declare function validateFieldSelection(selection: FieldSelection, table: CleanTable): {
28
+ isValid: boolean;
29
+ errors: string[];
30
+ };