@smartive/graphql-magic 23.4.0-next.8 → 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 -2
  2. package/dist/bin/gqm.cjs +125 -656
  3. package/dist/cjs/index.cjs +2132 -2702
  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 -73
  12. package/dist/esm/resolvers/filters.js.map +1 -1
  13. package/dist/esm/resolvers/selects.js +2 -33
  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 -22
  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 -81
  29. package/src/resolvers/selects.ts +5 -38
  30. package/src/resolvers/utils.ts +0 -32
  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,65 +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) => subQuery.whereRaw(`${column} IN (?)`, [value.filter((v) => v !== null) as string[]]),
229
- (subQuery) => subQuery.whereRaw(`${column} IS NULL`),
230
- ]),
231
- );
232
- } else {
233
- ops.push((query) =>
234
- ors(query, [
235
- (subQuery) => subQuery.whereIn(column, value.filter((v) => v !== null) as string[]),
236
- (subQuery) => subQuery.whereNull(column),
237
- ]),
238
- );
239
- }
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
+ );
240
209
  continue;
241
210
  }
242
211
 
243
- if (isExpressionField) {
244
- ops.push((query) => query.whereRaw(`${column} IS NULL`));
245
- } else {
246
- ops.push((query) => query.whereNull(column));
247
- }
212
+ ops.push((query) => query.whereNull(column));
248
213
  continue;
249
214
  }
250
215
 
251
- if (isExpressionField) {
252
- ops.push((query) => query.whereRaw(`${column} IN (?)`, [value as string[]]));
253
- } else {
254
- ops.push((query) => query.whereIn(column, value as string[]));
255
- }
216
+ ops.push((query) => query.whereIn(column, value as string[]));
256
217
  continue;
257
218
  }
258
219
 
259
- if (isExpressionField) {
260
- ops.push((query) => query.whereRaw(`${column} = ?`, [value]));
261
- } else {
262
- ops.push((query) => query.where({ [column]: value }));
263
- }
220
+ ops.push((query) => query.where({ [column]: value }));
264
221
  }
265
222
  };
266
223
 
@@ -269,18 +226,11 @@ const applySearch = (node: FieldResolverNode, search: string, query: Knex.QueryB
269
226
  query,
270
227
  node.model.fields
271
228
  .filter(({ searchable }) => searchable)
272
- .map((field) => {
273
- const isExpressionField = field.generateAs?.type === 'expression';
274
- const column = isExpressionField ? getColumnExpression(node, field.name) : getColumn(node, field.name);
275
-
276
- return (query: Knex.QueryBuilder) => {
277
- if (isExpressionField) {
278
- return query.whereRaw(`${column}::text ILIKE ?`, [`%${search}%`]);
279
- }
280
-
281
- return query.whereRaw('??::text ILIKE ?', [column, `%${search}%`]);
282
- };
283
- }),
229
+ .map(
230
+ ({ name }) =>
231
+ (query) =>
232
+ query.whereRaw('??::text ILIKE ?', [getColumn(node, name), `%${search}%`]),
233
+ ),
284
234
  );
285
235
 
286
236
  const applyOrderBy = (node: FilterNode, orderBy: OrderBy | OrderBy[], query: Knex.QueryBuilder, joins: Joins) => {
@@ -311,12 +261,6 @@ const applyOrderBy = (node: FilterNode, orderBy: OrderBy | OrderBy[], query: Kne
311
261
  }
312
262
 
313
263
  // Simple field
314
- const isExpressionField = field.generateAs?.type === 'expression';
315
- const column = isExpressionField ? getColumnExpression(node, key) : getColumn(node, key);
316
- if (isExpressionField) {
317
- void query.orderByRaw(`${column} ${value}`);
318
- } else {
319
- void query.orderBy(column, value as 'ASC' | 'DESC');
320
- }
264
+ void query.orderBy(getColumn(node, key), value as 'ASC' | 'DESC');
321
265
  }
322
266
  };
@@ -13,7 +13,6 @@ import {
13
13
  isFieldNode,
14
14
  } from '.';
15
15
  import { PermissionError, UserInputError, getRole } from '..';
16
- import { getColumnName } 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,36 +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 tableShortAlias = node.ctx.aliases.getShort(tableAlias);
87
- const resultShortAlias = node.ctx.aliases.getShort(resultAlias);
88
- const expression = generateAs.expression.replace(/\b(\w+)\b/g, (match, columnName) => {
89
- const field = node.model.fields.find((f) => {
90
- if (f.name === columnName) {
91
- return true;
92
- }
93
- const actualColumnName = getColumnName(f);
94
-
95
- return actualColumnName === columnName;
96
- });
97
- if (field) {
98
- const actualColumnName = getColumnName(field);
99
-
100
- return `${tableShortAlias}.${actualColumnName}`;
101
- }
102
-
103
- return match;
104
- });
105
-
106
- return node.ctx.knex.raw(`(${expression}) as ??`, [`${resultShortAlias}__${fieldAlias}`]);
107
- }
108
-
109
- return `${node.ctx.aliases.getShort(tableAlias)}.${field} as ${node.ctx.aliases.getShort(resultAlias)}__${fieldAlias}`;
110
- }),
74
+ ].map(
75
+ ({ tableAlias, resultAlias, field, fieldAlias }) =>
76
+ `${node.ctx.aliases.getShort(tableAlias)}.${field} as ${node.ctx.aliases.getShort(resultAlias)}__${fieldAlias}`,
77
+ ),
111
78
  );
112
79
 
113
80
  for (const subNode of getInlineFragments(node)) {
@@ -218,38 +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
- export const getColumnExpression = (
222
- node: Pick<ResolverNode, 'model' | 'ctx' | 'rootTableAlias' | 'tableAlias'>,
223
- fieldName: string,
224
- ) => {
225
- const field = node.model.fields.find((field) => field.name === fieldName)!;
226
-
227
- if (field.generateAs?.type === 'expression') {
228
- const expression = field.generateAs.expression.replace(/\b(\w+)\b/g, (match, columnName) => {
229
- const referencedField = node.model.fields.find((f) => {
230
- if (f.name === columnName) {
231
- return true;
232
- }
233
- const actualColumnName = getColumnName(f);
234
-
235
- return actualColumnName === columnName;
236
- });
237
- if (referencedField) {
238
- const actualColumnName = getColumnName(referencedField);
239
- const referencedTableAlias = referencedField.inherited ? node.rootTableAlias : node.tableAlias;
240
-
241
- return `${node.ctx.aliases.getShort(referencedTableAlias)}.${actualColumnName}`;
242
- }
243
-
244
- return match;
245
- });
246
-
247
- return `(${expression})`;
248
- }
249
-
250
- return getColumn(node, fieldName);
251
- };
252
-
253
221
  export const getTechnicalDisplay = (model: EntityModel, entity: Entity) =>
254
222
  model.displayField && entity[model.displayField]
255
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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"}