@smartive/graphql-magic 23.4.0-next.9 → 23.4.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +2 -3
  2. package/dist/bin/gqm.cjs +125 -656
  3. package/dist/cjs/index.cjs +2118 -2685
  4. package/dist/esm/migrations/generate.d.ts +1 -9
  5. package/dist/esm/migrations/generate.js +33 -269
  6. package/dist/esm/migrations/generate.js.map +1 -1
  7. package/dist/esm/migrations/index.d.ts +0 -2
  8. package/dist/esm/migrations/index.js +0 -2
  9. package/dist/esm/migrations/index.js.map +1 -1
  10. package/dist/esm/models/model-definitions.d.ts +1 -4
  11. package/dist/esm/resolvers/filters.js +14 -76
  12. package/dist/esm/resolvers/filters.js.map +1 -1
  13. package/dist/esm/resolvers/selects.js +2 -20
  14. package/dist/esm/resolvers/selects.js.map +1 -1
  15. package/dist/esm/resolvers/utils.d.ts +0 -1
  16. package/dist/esm/resolvers/utils.js +0 -29
  17. package/dist/esm/resolvers/utils.js.map +1 -1
  18. package/docs/docs/3-fields.md +0 -149
  19. package/docs/docs/5-migrations.md +1 -9
  20. package/package.json +2 -2
  21. package/src/bin/gqm/gqm.ts +5 -44
  22. package/src/bin/gqm/settings.ts +0 -7
  23. package/src/bin/gqm/static-eval.ts +102 -0
  24. package/src/bin/gqm/utils.ts +0 -1
  25. package/src/migrations/generate.ts +41 -334
  26. package/src/migrations/index.ts +0 -2
  27. package/src/models/model-definitions.ts +1 -4
  28. package/src/resolvers/filters.ts +25 -88
  29. package/src/resolvers/selects.ts +5 -22
  30. package/src/resolvers/utils.ts +0 -44
  31. package/dist/esm/migrations/generate-functions.d.ts +0 -2
  32. package/dist/esm/migrations/generate-functions.js +0 -60
  33. package/dist/esm/migrations/generate-functions.js.map +0 -1
  34. package/dist/esm/migrations/types.d.ts +0 -7
  35. package/dist/esm/migrations/types.js +0 -2
  36. package/dist/esm/migrations/types.js.map +0 -1
  37. package/dist/esm/migrations/update-functions.d.ts +0 -3
  38. package/dist/esm/migrations/update-functions.js +0 -177
  39. package/dist/esm/migrations/update-functions.js.map +0 -1
  40. package/src/bin/gqm/parse-functions.ts +0 -141
  41. package/src/migrations/generate-functions.ts +0 -74
  42. package/src/migrations/types.ts +0 -7
  43. package/src/migrations/update-functions.ts +0 -221
@@ -3,7 +3,7 @@ import { EntityModel, FullContext, getPermissionStack } from '..';
3
3
  import { ForbiddenError, UserInputError } from '../errors';
4
4
  import { OrderBy, Where, normalizeArguments } from './arguments';
5
5
  import { FieldResolverNode } from './node';
6
- import { Joins, QueryBuilderOps, addJoin, apply, applyJoins, getColumn, getColumnExpression, ors } from './utils';
6
+ import { Joins, QueryBuilderOps, addJoin, apply, applyJoins, getColumn, ors } from './utils';
7
7
 
8
8
  export const SPECIAL_FILTERS: Record<string, string> = {
9
9
  GT: '?? > ?',
@@ -157,32 +157,19 @@ const applyWhere = (node: FilterNode, where: Where | undefined, ops: QueryBuilde
157
157
  // Should not happen
158
158
  throw new Error(`Invalid filter ${key}.`);
159
159
  }
160
- const actualField = node.model.getField(actualKey);
161
- const isExpressionField = actualField.generateAs?.type === 'expression';
162
- const actualColumn = isExpressionField ? getColumnExpression(node, actualKey) : getColumn(node, actualKey);
163
- if (isExpressionField) {
164
- const operator = filter === 'GT' ? '>' : filter === 'GTE' ? '>=' : filter === 'LT' ? '<' : '<=';
165
- ops.push((query) => query.whereRaw(`${actualColumn} ${operator} ?`, [value as string]));
166
- } else {
167
- ops.push((query) => query.whereRaw(SPECIAL_FILTERS[filter], [actualColumn, value as string]));
168
- }
160
+ ops.push((query) => query.whereRaw(SPECIAL_FILTERS[filter], [getColumn(node, actualKey), value as string]));
169
161
  continue;
170
162
  }
171
163
 
172
164
  const field = node.model.getField(key);
173
165
 
174
- const isExpressionField = field.generateAs?.type === 'expression';
175
- const column = isExpressionField ? getColumnExpression(node, key) : getColumn(node, key);
166
+ const column = getColumn(node, key);
176
167
 
177
168
  if (field.kind === 'relation') {
178
169
  const relation = node.model.getRelation(field.name);
179
170
 
180
171
  if (value === null) {
181
- if (isExpressionField) {
182
- ops.push((query) => query.whereRaw(`${column} IS NULL`));
183
- } else {
184
- ops.push((query) => query.whereNull(column));
185
- }
172
+ ops.push((query) => query.whereNull(column));
186
173
  continue;
187
174
  }
188
175
 
@@ -202,72 +189,35 @@ const applyWhere = (node: FilterNode, where: Where | undefined, ops: QueryBuilde
202
189
 
203
190
  if (Array.isArray(value)) {
204
191
  if (field && field.list) {
205
- if (isExpressionField) {
206
- ops.push((query) =>
207
- ors(
208
- query,
209
- value.map((v) => (subQuery) => subQuery.whereRaw(`? = ANY(${column})`, [v])),
210
- ),
211
- );
212
- } else {
213
- ops.push((query) =>
214
- ors(
215
- query,
216
- value.map((v) => (subQuery) => subQuery.whereRaw('? = ANY(??)', [v, column] as string[])),
217
- ),
218
- );
219
- }
192
+ ops.push((query) =>
193
+ ors(
194
+ query,
195
+ value.map((v) => (subQuery) => subQuery.whereRaw('? = ANY(??)', [v, column] as string[])),
196
+ ),
197
+ );
220
198
  continue;
221
199
  }
222
200
 
223
201
  if (value.some((v) => v === null)) {
224
202
  if (value.some((v) => v !== null)) {
225
- if (isExpressionField) {
226
- ops.push((query) =>
227
- ors(query, [
228
- (subQuery) =>
229
- subQuery.whereRaw(
230
- `${column} IN (${value
231
- .filter((v) => v !== null)
232
- .map(() => `?`)
233
- .join(',')})`,
234
- value.filter((v) => v !== null) as string[],
235
- ),
236
- (subQuery) => subQuery.whereRaw(`${column} IS NULL`),
237
- ]),
238
- );
239
- } else {
240
- ops.push((query) =>
241
- ors(query, [
242
- (subQuery) => subQuery.whereIn(column, value.filter((v) => v !== null) as string[]),
243
- (subQuery) => subQuery.whereNull(column),
244
- ]),
245
- );
246
- }
203
+ ops.push((query) =>
204
+ ors(query, [
205
+ (subQuery) => subQuery.whereIn(column, value.filter((v) => v !== null) as string[]),
206
+ (subQuery) => subQuery.whereNull(column),
207
+ ]),
208
+ );
247
209
  continue;
248
210
  }
249
211
 
250
- if (isExpressionField) {
251
- ops.push((query) => query.whereRaw(`${column} IS NULL`));
252
- } else {
253
- ops.push((query) => query.whereNull(column));
254
- }
212
+ ops.push((query) => query.whereNull(column));
255
213
  continue;
256
214
  }
257
215
 
258
- if (isExpressionField) {
259
- ops.push((query) => query.whereRaw(`${column} IN (${value.map(() => `?`).join(',')})`, value as string[]));
260
- } else {
261
- ops.push((query) => query.whereIn(column, value as string[]));
262
- }
216
+ ops.push((query) => query.whereIn(column, value as string[]));
263
217
  continue;
264
218
  }
265
219
 
266
- if (isExpressionField) {
267
- ops.push((query) => query.whereRaw(`${column} = ?`, [value]));
268
- } else {
269
- ops.push((query) => query.where({ [column]: value }));
270
- }
220
+ ops.push((query) => query.where({ [column]: value }));
271
221
  }
272
222
  };
273
223
 
@@ -276,18 +226,11 @@ const applySearch = (node: FieldResolverNode, search: string, query: Knex.QueryB
276
226
  query,
277
227
  node.model.fields
278
228
  .filter(({ searchable }) => searchable)
279
- .map((field) => {
280
- const isExpressionField = field.generateAs?.type === 'expression';
281
- const column = isExpressionField ? getColumnExpression(node, field.name) : getColumn(node, field.name);
282
-
283
- return (query: Knex.QueryBuilder) => {
284
- if (isExpressionField) {
285
- return query.whereRaw(`${column}::text ILIKE ?`, [`%${search}%`]);
286
- }
287
-
288
- return query.whereRaw('??::text ILIKE ?', [column, `%${search}%`]);
289
- };
290
- }),
229
+ .map(
230
+ ({ name }) =>
231
+ (query) =>
232
+ query.whereRaw('??::text ILIKE ?', [getColumn(node, name), `%${search}%`]),
233
+ ),
291
234
  );
292
235
 
293
236
  const applyOrderBy = (node: FilterNode, orderBy: OrderBy | OrderBy[], query: Knex.QueryBuilder, joins: Joins) => {
@@ -318,12 +261,6 @@ const applyOrderBy = (node: FilterNode, orderBy: OrderBy | OrderBy[], query: Kne
318
261
  }
319
262
 
320
263
  // Simple field
321
- const isExpressionField = field.generateAs?.type === 'expression';
322
- const column = isExpressionField ? getColumnExpression(node, key) : getColumn(node, key);
323
- if (isExpressionField) {
324
- void query.orderByRaw(`${column} ${value}`);
325
- } else {
326
- void query.orderBy(column, value as 'ASC' | 'DESC');
327
- }
264
+ void query.orderBy(getColumn(node, key), value as 'ASC' | 'DESC');
328
265
  }
329
266
  };
@@ -13,7 +13,6 @@ import {
13
13
  isFieldNode,
14
14
  } from '.';
15
15
  import { PermissionError, UserInputError, getRole } from '..';
16
- import { getColumnExpression } from './utils';
17
16
 
18
17
  export const applySelects = (node: ResolverNode, query: Knex.QueryBuilder, joins: Joins) => {
19
18
  if (node.isAggregate) {
@@ -33,15 +32,7 @@ export const applySelects = (node: ResolverNode, query: Knex.QueryBuilder, joins
33
32
  ...[
34
33
  { tableAlias: node.rootTableAlias, resultAlias: node.resultAlias, field: 'id', fieldAlias: ID_ALIAS },
35
34
  ...(node.model.root
36
- ? [
37
- {
38
- tableAlias: node.rootTableAlias,
39
- resultAlias: node.resultAlias,
40
- field: 'type',
41
- fieldAlias: TYPE_ALIAS,
42
- generateAs: undefined,
43
- },
44
- ]
35
+ ? [{ tableAlias: node.rootTableAlias, resultAlias: node.resultAlias, field: 'type', fieldAlias: TYPE_ALIAS }]
45
36
  : []),
46
37
  ...getSimpleFields(node)
47
38
  .filter((fieldNode) => {
@@ -78,20 +69,12 @@ export const applySelects = (node: ResolverNode, query: Knex.QueryBuilder, joins
78
69
  tableAlias: field.inherited ? node.rootTableAlias : node.tableAlias,
79
70
  resultAlias: node.resultAlias,
80
71
  fieldAlias,
81
- generateAs: field.generateAs,
82
72
  };
83
73
  }),
84
- ].map(({ tableAlias, resultAlias, field, fieldAlias, generateAs }) => {
85
- if (generateAs?.type === 'expression') {
86
- const resultShortAlias = node.ctx.aliases.getShort(resultAlias);
87
- const columnExpression = getColumnExpression(node, field);
88
- const expression = columnExpression.slice(1, -1);
89
-
90
- return node.ctx.knex.raw(`(${expression}) as ??`, [`${resultShortAlias}__${fieldAlias}`]);
91
- }
92
-
93
- return `${node.ctx.aliases.getShort(tableAlias)}.${field} as ${node.ctx.aliases.getShort(resultAlias)}__${fieldAlias}`;
94
- }),
74
+ ].map(
75
+ ({ tableAlias, resultAlias, field, fieldAlias }) =>
76
+ `${node.ctx.aliases.getShort(tableAlias)}.${field} as ${node.ctx.aliases.getShort(resultAlias)}__${fieldAlias}`,
77
+ ),
95
78
  );
96
79
 
97
80
  for (const subNode of getInlineFragments(node)) {
@@ -218,50 +218,6 @@ export const getColumn = (
218
218
  return `${node.ctx.aliases.getShort(field.inherited ? node.rootTableAlias : node.tableAlias)}.${getColumnName(field)}`;
219
219
  };
220
220
 
221
- const replaceColumnReferences = (
222
- expression: string,
223
- node: Pick<ResolverNode, 'model' | 'ctx' | 'rootTableAlias' | 'tableAlias'>,
224
- ) => {
225
- const replaceField = (columnName: string) => {
226
- const referencedField = node.model.fields.find((f) => getColumnName(f) === columnName);
227
- if (referencedField) {
228
- const actualColumnName = getColumnName(referencedField);
229
- const referencedTableAlias = referencedField.inherited ? node.rootTableAlias : node.tableAlias;
230
-
231
- return {
232
- tableAlias: node.ctx.aliases.getShort(referencedTableAlias),
233
- columnName: actualColumnName,
234
- };
235
- }
236
-
237
- return null;
238
- };
239
-
240
- return expression.replace(/"(\w+)"/g, (match, columnName) => {
241
- const replacement = replaceField(columnName);
242
- if (replacement) {
243
- return `"${replacement.tableAlias}"."${replacement.columnName}"`;
244
- }
245
-
246
- return match;
247
- });
248
- };
249
-
250
- export const getColumnExpression = (
251
- node: Pick<ResolverNode, 'model' | 'ctx' | 'rootTableAlias' | 'tableAlias'>,
252
- fieldName: string,
253
- ) => {
254
- const field = node.model.fields.find((field) => field.name === fieldName)!;
255
-
256
- if (field.generateAs?.type === 'expression') {
257
- const expression = replaceColumnReferences(field.generateAs.expression, node);
258
-
259
- return `(${expression})`;
260
- }
261
-
262
- return getColumn(node, fieldName);
263
- };
264
-
265
221
  export const getTechnicalDisplay = (model: EntityModel, entity: Entity) =>
266
222
  model.displayField && entity[model.displayField]
267
223
  ? `${model.name} "${entity[model.displayField]}" (${entity.id})`
@@ -1,2 +0,0 @@
1
- import { Knex } from 'knex';
2
- export declare const generateFunctionsFromDatabase: (knex: Knex) => Promise<string>;
@@ -1,60 +0,0 @@
1
- export const generateFunctionsFromDatabase = async (knex) => {
2
- const regularFunctions = await knex.raw(`
3
- SELECT
4
- pg_get_functiondef(p.oid) as definition
5
- FROM pg_proc p
6
- JOIN pg_namespace n ON p.pronamespace = n.oid
7
- WHERE n.nspname = 'public'
8
- AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
9
- ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
10
- `);
11
- const aggregateFunctions = await knex.raw(`
12
- SELECT
13
- p.proname as name,
14
- pg_get_function_identity_arguments(p.oid) as arguments,
15
- a.aggtransfn::regproc::text as trans_func,
16
- a.aggfinalfn::regproc::text as final_func,
17
- a.agginitval as init_val,
18
- pg_catalog.format_type(a.aggtranstype, NULL) as state_type
19
- FROM pg_proc p
20
- JOIN pg_aggregate a ON p.oid = a.aggfnoid
21
- JOIN pg_namespace n ON p.pronamespace = n.oid
22
- WHERE n.nspname = 'public'
23
- ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
24
- `);
25
- const functions = [];
26
- for (const row of regularFunctions.rows || []) {
27
- if (row.definition) {
28
- functions.push(row.definition.trim());
29
- }
30
- }
31
- for (const row of aggregateFunctions.rows || []) {
32
- const name = row.name || '';
33
- const argumentsStr = row.arguments || '';
34
- const transFunc = row.trans_func || '';
35
- const finalFunc = row.final_func || '';
36
- const initVal = row.init_val;
37
- const stateType = row.state_type || '';
38
- if (!name || !transFunc || !stateType) {
39
- continue;
40
- }
41
- let aggregateDef = `CREATE AGGREGATE ${name}(${argumentsStr}) (\n`;
42
- aggregateDef += ` SFUNC = ${transFunc},\n`;
43
- aggregateDef += ` STYPE = ${stateType}`;
44
- if (finalFunc) {
45
- aggregateDef += `,\n FINALFUNC = ${finalFunc}`;
46
- }
47
- if (initVal !== null && initVal !== undefined) {
48
- const initValStr = typeof initVal === 'string' ? `'${initVal}'` : String(initVal);
49
- aggregateDef += `,\n INITCOND = ${initValStr}`;
50
- }
51
- aggregateDef += '\n);';
52
- functions.push(aggregateDef);
53
- }
54
- if (functions.length === 0) {
55
- return `export const functions: string[] = [];\n`;
56
- }
57
- const functionsArrayString = functions.map((func) => ` ${JSON.stringify(func)}`).join(',\n');
58
- return `export const functions: string[] = [\n${functionsArrayString},\n];\n`;
59
- };
60
- //# sourceMappingURL=generate-functions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"generate-functions.js","sourceRoot":"","sources":["../../../src/migrations/generate-functions.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,EAAE,IAAU,EAAmB,EAAE;IACjF,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC;;;;;;;;GAQvC,CAAC,CAAC;IAEH,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC;;;;;;;;;;;;;GAazC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QAC9C,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YACnB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,kBAAkB,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC7B,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;QAEvC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,SAAS;QACX,CAAC;QAED,IAAI,YAAY,GAAG,oBAAoB,IAAI,IAAI,YAAY,OAAO,CAAC;QACnE,YAAY,IAAI,aAAa,SAAS,KAAK,CAAC;QAC5C,YAAY,IAAI,aAAa,SAAS,EAAE,CAAC;QAEzC,IAAI,SAAS,EAAE,CAAC;YACd,YAAY,IAAI,oBAAoB,SAAS,EAAE,CAAC;QAClD,CAAC;QAED,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC9C,MAAM,UAAU,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAClF,YAAY,IAAI,mBAAmB,UAAU,EAAE,CAAC;QAClD,CAAC;QAED,YAAY,IAAI,MAAM,CAAC;QAEvB,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,0CAA0C,CAAC;IACpD,CAAC;IAED,MAAM,oBAAoB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAE9F,OAAO,yCAAyC,oBAAoB,SAAS,CAAC;AAChF,CAAC,CAAC"}
@@ -1,7 +0,0 @@
1
- export type ParsedFunction = {
2
- name: string;
3
- signature: string;
4
- body: string;
5
- fullDefinition: string;
6
- isAggregate: boolean;
7
- };
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/migrations/types.ts"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- import { Knex } from 'knex';
2
- import { ParsedFunction } from './types';
3
- export declare const updateFunctions: (knex: Knex, parsedFunctions: ParsedFunction[]) => Promise<void>;
@@ -1,177 +0,0 @@
1
- const normalizeWhitespace = (str) => {
2
- return str
3
- .replace(/\s+/g, ' ')
4
- .replace(/\s*\(\s*/g, '(')
5
- .replace(/\s*\)\s*/g, ')')
6
- .replace(/\s*,\s*/g, ',')
7
- .replace(/\s*;\s*/g, ';')
8
- .trim();
9
- };
10
- const normalizeFunctionBody = (body) => {
11
- return normalizeWhitespace(body);
12
- };
13
- const extractFunctionBody = (definition) => {
14
- const dollarQuoteMatch = definition.match(/AS\s+\$([^$]*)\$([\s\S]*?)\$\1\$/i);
15
- if (dollarQuoteMatch) {
16
- return dollarQuoteMatch[2].trim();
17
- }
18
- const bodyMatch = definition.match(/AS\s+\$\$([\s\S]*?)\$\$/i) || definition.match(/AS\s+['"]([\s\S]*?)['"]/i);
19
- if (bodyMatch) {
20
- return bodyMatch[1].trim();
21
- }
22
- return definition;
23
- };
24
- const getDatabaseFunctions = async (knex) => {
25
- const regularFunctions = await knex.raw(`
26
- SELECT
27
- p.proname as name,
28
- pg_get_function_identity_arguments(p.oid) as arguments,
29
- pg_get_functiondef(p.oid) as definition,
30
- false as is_aggregate
31
- FROM pg_proc p
32
- JOIN pg_namespace n ON p.pronamespace = n.oid
33
- WHERE n.nspname = 'public'
34
- AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
35
- ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
36
- `);
37
- const aggregateFunctions = await knex.raw(`
38
- SELECT
39
- p.proname as name,
40
- pg_get_function_identity_arguments(p.oid) as arguments,
41
- a.aggtransfn::regproc::text as trans_func,
42
- a.aggfinalfn::regproc::text as final_func,
43
- a.agginitval as init_val,
44
- pg_catalog.format_type(a.aggtranstype, NULL) as state_type,
45
- true as is_aggregate
46
- FROM pg_proc p
47
- JOIN pg_aggregate a ON p.oid = a.aggfnoid
48
- JOIN pg_namespace n ON p.pronamespace = n.oid
49
- WHERE n.nspname = 'public'
50
- ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
51
- `);
52
- const result = [];
53
- for (const row of regularFunctions.rows || []) {
54
- const definition = row.definition || '';
55
- const name = row.name || '';
56
- const argumentsStr = row.arguments || '';
57
- if (!definition) {
58
- continue;
59
- }
60
- const signature = `${name}(${argumentsStr})`;
61
- const body = normalizeFunctionBody(extractFunctionBody(definition));
62
- result.push({
63
- name,
64
- signature,
65
- body,
66
- isAggregate: false,
67
- definition,
68
- });
69
- }
70
- for (const row of aggregateFunctions.rows || []) {
71
- const name = row.name || '';
72
- const argumentsStr = row.arguments || '';
73
- const transFunc = row.trans_func || '';
74
- const finalFunc = row.final_func || '';
75
- const initVal = row.init_val;
76
- const stateType = row.state_type || '';
77
- const signature = `${name}(${argumentsStr})`;
78
- let aggregateDef = `CREATE AGGREGATE ${name}(${argumentsStr}) (`;
79
- aggregateDef += `SFUNC = ${transFunc}, STYPE = ${stateType}`;
80
- if (finalFunc) {
81
- aggregateDef += `, FINALFUNC = ${finalFunc}`;
82
- }
83
- if (initVal !== null && initVal !== undefined) {
84
- const initValStr = typeof initVal === 'string' ? `'${initVal}'` : String(initVal);
85
- aggregateDef += `, INITCOND = ${initValStr}`;
86
- }
87
- aggregateDef += ');';
88
- result.push({
89
- name,
90
- signature,
91
- body: normalizeFunctionBody(aggregateDef),
92
- isAggregate: true,
93
- definition: aggregateDef,
94
- });
95
- }
96
- return result;
97
- };
98
- const compareFunctions = (defined, db) => {
99
- const definedBody = normalizeFunctionBody(defined.body);
100
- const dbBody = normalizeFunctionBody(db.body);
101
- if (definedBody !== dbBody) {
102
- const definedPreview = definedBody.length > 200 ? `${definedBody.substring(0, 200)}...` : definedBody;
103
- const dbPreview = dbBody.length > 200 ? `${dbBody.substring(0, 200)}...` : dbBody;
104
- return {
105
- changed: true,
106
- diff: `Definition changed:\n File: ${definedPreview}\n DB: ${dbPreview}`,
107
- };
108
- }
109
- return { changed: false };
110
- };
111
- export const updateFunctions = async (knex, parsedFunctions) => {
112
- if (parsedFunctions.length === 0) {
113
- return;
114
- }
115
- const definedFunctions = parsedFunctions;
116
- const dbFunctions = await getDatabaseFunctions(knex);
117
- const dbFunctionsBySignature = new Map();
118
- for (const func of dbFunctions) {
119
- dbFunctionsBySignature.set(func.signature, func);
120
- }
121
- console.info(`Found ${definedFunctions.length} function(s) in file, ${dbFunctions.length} function(s) in database.`);
122
- let updatedCount = 0;
123
- let skippedCount = 0;
124
- for (const definedFunc of definedFunctions) {
125
- const dbFunc = dbFunctionsBySignature.get(definedFunc.signature);
126
- if (!dbFunc) {
127
- try {
128
- await knex.raw(definedFunc.fullDefinition);
129
- console.info(`✓ Created ${definedFunc.isAggregate ? 'aggregate' : 'function'}: ${definedFunc.signature}`);
130
- updatedCount++;
131
- }
132
- catch (error) {
133
- console.error(`✗ Failed to create ${definedFunc.isAggregate ? 'aggregate' : 'function'} ${definedFunc.signature}:`, error.message);
134
- throw error;
135
- }
136
- }
137
- else {
138
- const comparison = compareFunctions(definedFunc, dbFunc);
139
- if (comparison.changed) {
140
- console.info(`\n⚠ ${definedFunc.isAggregate ? 'Aggregate' : 'Function'} ${definedFunc.signature} has changes:`);
141
- if (comparison.diff) {
142
- console.info(comparison.diff);
143
- }
144
- try {
145
- if (definedFunc.isAggregate) {
146
- const dropMatch = definedFunc.fullDefinition.match(/CREATE\s+(OR\s+REPLACE\s+)?AGGREGATE\s+([^(]+)\(/i);
147
- if (dropMatch) {
148
- const functionName = dropMatch[2].trim();
149
- const argsMatch = definedFunc.fullDefinition.match(/CREATE\s+(OR\s+REPLACE\s+)?AGGREGATE\s+[^(]+\(([^)]*)\)/i);
150
- const args = argsMatch ? argsMatch[2].trim() : '';
151
- await knex.raw(`DROP AGGREGATE IF EXISTS ${functionName}${args ? `(${args})` : ''}`);
152
- }
153
- }
154
- await knex.raw(definedFunc.fullDefinition);
155
- console.info(`✓ Updated ${definedFunc.isAggregate ? 'aggregate' : 'function'}: ${definedFunc.signature}\n`);
156
- updatedCount++;
157
- }
158
- catch (error) {
159
- console.error(`✗ Failed to update ${definedFunc.isAggregate ? 'aggregate' : 'function'} ${definedFunc.signature}:`, error.message);
160
- throw error;
161
- }
162
- }
163
- else {
164
- console.info(`○ Skipped ${definedFunc.isAggregate ? 'aggregate' : 'function'} (unchanged): ${definedFunc.signature}`);
165
- skippedCount++;
166
- }
167
- }
168
- }
169
- console.info(`\nSummary: ${updatedCount} updated, ${skippedCount} skipped`);
170
- if (updatedCount > 0) {
171
- console.info('Functions updated successfully.');
172
- }
173
- else {
174
- console.info('All functions are up to date.');
175
- }
176
- };
177
- //# sourceMappingURL=update-functions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"update-functions.js","sourceRoot":"","sources":["../../../src/migrations/update-functions.ts"],"names":[],"mappings":"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"}