@smartive/graphql-magic 23.2.0 → 23.4.0-next.4

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 (42) hide show
  1. package/.github/workflows/release.yml +8 -2
  2. package/CHANGELOG.md +4 -2
  3. package/dist/bin/gqm.cjs +678 -64
  4. package/dist/cjs/index.cjs +2767 -2107
  5. package/dist/esm/migrations/generate-functions.d.ts +2 -0
  6. package/dist/esm/migrations/generate-functions.js +59 -0
  7. package/dist/esm/migrations/generate-functions.js.map +1 -0
  8. package/dist/esm/migrations/generate.d.ts +8 -1
  9. package/dist/esm/migrations/generate.js +273 -33
  10. package/dist/esm/migrations/generate.js.map +1 -1
  11. package/dist/esm/migrations/index.d.ts +2 -0
  12. package/dist/esm/migrations/index.js +2 -0
  13. package/dist/esm/migrations/index.js.map +1 -1
  14. package/dist/esm/migrations/parse-functions.d.ts +8 -0
  15. package/dist/esm/migrations/parse-functions.js +105 -0
  16. package/dist/esm/migrations/parse-functions.js.map +1 -0
  17. package/dist/esm/migrations/update-functions.d.ts +2 -0
  18. package/dist/esm/migrations/update-functions.js +174 -0
  19. package/dist/esm/migrations/update-functions.js.map +1 -0
  20. package/dist/esm/models/model-definitions.d.ts +4 -1
  21. package/dist/esm/resolvers/filters.js +73 -14
  22. package/dist/esm/resolvers/filters.js.map +1 -1
  23. package/dist/esm/resolvers/selects.js +33 -2
  24. package/dist/esm/resolvers/selects.js.map +1 -1
  25. package/dist/esm/resolvers/utils.d.ts +1 -0
  26. package/dist/esm/resolvers/utils.js +22 -0
  27. package/dist/esm/resolvers/utils.js.map +1 -1
  28. package/docs/docs/3-fields.md +149 -0
  29. package/docs/docs/5-migrations.md +9 -1
  30. package/package.json +5 -1
  31. package/src/bin/gqm/gqm.ts +40 -5
  32. package/src/bin/gqm/settings.ts +7 -0
  33. package/src/bin/gqm/static-eval.ts +48 -1
  34. package/src/migrations/generate-functions.ts +72 -0
  35. package/src/migrations/generate.ts +338 -41
  36. package/src/migrations/index.ts +2 -0
  37. package/src/migrations/parse-functions.ts +140 -0
  38. package/src/migrations/update-functions.ts +216 -0
  39. package/src/models/model-definitions.ts +4 -1
  40. package/src/resolvers/filters.ts +81 -25
  41. package/src/resolvers/selects.ts +38 -5
  42. package/src/resolvers/utils.ts +32 -0
@@ -1,5 +1,6 @@
1
1
  import { camelCase, Dictionary, kebabCase, lowerFirst, snakeCase, startCase, upperFirst } from 'lodash';
2
2
  import {
3
+ BindingElement,
3
4
  CaseClause,
4
5
  ElementAccessExpression,
5
6
  Identifier,
@@ -47,6 +48,7 @@ export const staticEval = (node: Node | undefined, context: Dictionary<unknown>)
47
48
 
48
49
  const VISITOR: Visitor<unknown, Dictionary<unknown>> = {
49
50
  undefined: () => undefined,
51
+ [SyntaxKind.BindingElement]: (node: BindingElement, context) => context[node.getName()],
50
52
  [SyntaxKind.VariableDeclaration]: (node, context) => staticEval(node.getInitializer(), context),
51
53
  [SyntaxKind.ArrayLiteralExpression]: (node, context) => {
52
54
  const values: unknown[] = [];
@@ -146,7 +148,52 @@ const VISITOR: Visitor<unknown, Dictionary<unknown>> = {
146
148
  const parameters: Dictionary<unknown> = {};
147
149
  let i = 0;
148
150
  for (const parameter of node.getParameters()) {
149
- parameters[parameter.getName()] = args[i];
151
+ const argument = args[i];
152
+
153
+ if (parameter.isRestParameter()) {
154
+ parameters[parameter.getName()] = args.slice(i);
155
+ } else {
156
+ const nameNode = parameter.getNameNode();
157
+ if (Node.isObjectBindingPattern(nameNode)) {
158
+ const value = (argument ?? {}) as Dictionary<unknown>;
159
+ const usedKeys = new Set<string>();
160
+
161
+ for (const element of nameNode.getElements()) {
162
+ if (element.getDotDotDotToken()) {
163
+ // Handle rest element (...args)
164
+ const restName = element.getName();
165
+ const restValue: Dictionary<unknown> = {};
166
+ for (const key in value) {
167
+ if (!usedKeys.has(key)) {
168
+ restValue[key] = value[key];
169
+ }
170
+ }
171
+ parameters[restName] = restValue;
172
+ } else {
173
+ // Handle property destructuring (prop: alias = defaultValue)
174
+ const propertyNameNode = element.getPropertyNameNode();
175
+ const elementDetails = element.getNameNode();
176
+
177
+ // If "prop: alias", key is "prop". If just "alias", key is "alias".
178
+ const key = propertyNameNode ? propertyNameNode.getText() : elementDetails.getText();
179
+ const variableName = elementDetails.getText();
180
+
181
+ usedKeys.add(key);
182
+
183
+ let propertyValue = value[key];
184
+
185
+ // Handle default values (= defaultValue)
186
+ if (propertyValue === undefined && element.hasInitializer()) {
187
+ propertyValue = staticEval(element.getInitializer(), { ...context, ...parameters });
188
+ }
189
+
190
+ parameters[variableName] = propertyValue;
191
+ }
192
+ }
193
+ } else {
194
+ parameters[parameter.getName()] = argument;
195
+ }
196
+ }
150
197
  i++;
151
198
  }
152
199
  return staticEval(node.getBody(), { ...context, ...parameters });
@@ -0,0 +1,72 @@
1
+ import { Knex } from 'knex';
2
+
3
+ export const generateFunctionsFromDatabase = async (knex: Knex): Promise<string> => {
4
+ const regularFunctions = await knex.raw(`
5
+ SELECT
6
+ pg_get_functiondef(p.oid) as definition
7
+ FROM pg_proc p
8
+ JOIN pg_namespace n ON p.pronamespace = n.oid
9
+ WHERE n.nspname = 'public'
10
+ AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
11
+ ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
12
+ `);
13
+
14
+ const aggregateFunctions = await knex.raw(`
15
+ SELECT
16
+ p.proname as name,
17
+ pg_get_function_identity_arguments(p.oid) as arguments,
18
+ a.aggtransfn::regproc::text as trans_func,
19
+ a.aggfinalfn::regproc::text as final_func,
20
+ a.agginitval as init_val,
21
+ pg_catalog.format_type(a.aggtranstype, NULL) as state_type
22
+ FROM pg_proc p
23
+ JOIN pg_aggregate a ON p.oid = a.aggfnoid
24
+ JOIN pg_namespace n ON p.pronamespace = n.oid
25
+ WHERE n.nspname = 'public'
26
+ ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
27
+ `);
28
+
29
+ const functions: string[] = [];
30
+
31
+ for (const row of regularFunctions.rows || []) {
32
+ if (row.definition) {
33
+ functions.push(row.definition.trim());
34
+ }
35
+ }
36
+
37
+ for (const row of aggregateFunctions.rows || []) {
38
+ const name = row.name || '';
39
+ const argumentsStr = row.arguments || '';
40
+ const transFunc = row.trans_func || '';
41
+ const finalFunc = row.final_func || '';
42
+ const initVal = row.init_val;
43
+ const stateType = row.state_type || '';
44
+
45
+ if (!name || !transFunc || !stateType) {
46
+ continue;
47
+ }
48
+
49
+ let aggregateDef = `CREATE AGGREGATE ${name}(${argumentsStr}) (\n`;
50
+ aggregateDef += ` SFUNC = ${transFunc},\n`;
51
+ aggregateDef += ` STYPE = ${stateType}`;
52
+
53
+ if (finalFunc) {
54
+ aggregateDef += `,\n FINALFUNC = ${finalFunc}`;
55
+ }
56
+
57
+ if (initVal !== null && initVal !== undefined) {
58
+ const initValStr = typeof initVal === 'string' ? `'${initVal}'` : String(initVal);
59
+ aggregateDef += `,\n INITCOND = ${initValStr}`;
60
+ }
61
+
62
+ aggregateDef += '\n);';
63
+
64
+ functions.push(aggregateDef);
65
+ }
66
+
67
+ if (functions.length === 0) {
68
+ return '-- PostgreSQL functions\n-- No functions found in database\n';
69
+ }
70
+
71
+ return functions.join('\n\n') + '\n';
72
+ };