@smartive/graphql-magic 23.5.0-next.1 → 23.5.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.
@@ -20,17 +20,15 @@ import {
20
20
  import { getColumnName } from '../resolvers';
21
21
  import { Value } from '../values';
22
22
  import { ParsedFunction } from './types';
23
+ import {
24
+ DatabaseFunction,
25
+ getDatabaseFunctions,
26
+ normalizeAggregateDefinition,
27
+ normalizeFunctionBody,
28
+ } from './update-functions';
23
29
 
24
30
  type Callbacks = (() => void)[];
25
31
 
26
- type DatabaseFunction = {
27
- name: string;
28
- signature: string;
29
- body: string;
30
- isAggregate: boolean;
31
- definition?: string;
32
- };
33
-
34
32
  export class MigrationGenerator {
35
33
  // eslint-disable-next-line @typescript-eslint/dot-notation
36
34
  private writer: CodeBlockWriter = new CodeBlockWriter['default']({
@@ -762,7 +760,7 @@ export class MigrationGenerator {
762
760
  this.writer.write(`, ALTER COLUMN "${name}" SET EXPRESSION AS (${field.generateAs.expression})`);
763
761
  } else {
764
762
  this.writer.write(
765
- `${alter ? 'ALTER' : 'ADD'} COLUMN "${name}" ${type}${nonNull() ? ' not null' : ''} GENERATED ALWAYS AS (${field.generateAs.expression}) STORED`,
763
+ `ADD COLUMN "${name}" ${type}${nonNull() ? ' not null' : ''} GENERATED ALWAYS AS (${field.generateAs.expression}) STORED`,
766
764
  );
767
765
  }
768
766
 
@@ -981,144 +979,6 @@ export class MigrationGenerator {
981
979
  return false;
982
980
  }
983
981
 
984
- private normalizeFunctionBody(body: string): string {
985
- return body
986
- .replace(/\s+/g, ' ')
987
- .replace(/\s*\(\s*/g, '(')
988
- .replace(/\s*\)\s*/g, ')')
989
- .replace(/\s*,\s*/g, ',')
990
- .trim();
991
- }
992
-
993
- private normalizeAggregateDefinition(definition: string): string {
994
- let normalized = definition
995
- .replace(/\s+/g, ' ')
996
- .replace(/\s*\(\s*/g, '(')
997
- .replace(/\s*\)\s*/g, ')')
998
- .replace(/\s*,\s*/g, ',')
999
- .trim();
1000
-
1001
- const initCondMatch = normalized.match(/INITCOND\s*=\s*([^,)]+)/i);
1002
- if (initCondMatch) {
1003
- const initCondValue = initCondMatch[1].trim();
1004
- const unquoted = initCondValue.replace(/^['"]|['"]$/g, '');
1005
- if (/^\d+$/.test(unquoted)) {
1006
- normalized = normalized.replace(/INITCOND\s*=\s*[^,)]+/i, `INITCOND = '${unquoted}'`);
1007
- }
1008
- }
1009
-
1010
- return normalized;
1011
- }
1012
-
1013
- private extractFunctionBody(definition: string): string {
1014
- const dollarQuoteMatch = definition.match(/AS\s+\$([^$]*)\$([\s\S]*?)\$\1\$/i);
1015
- if (dollarQuoteMatch) {
1016
- return dollarQuoteMatch[2].trim();
1017
- }
1018
-
1019
- const bodyMatch = definition.match(/AS\s+\$\$([\s\S]*?)\$\$/i) || definition.match(/AS\s+['"]([\s\S]*?)['"]/i);
1020
- if (bodyMatch) {
1021
- return bodyMatch[1].trim();
1022
- }
1023
-
1024
- return definition;
1025
- }
1026
-
1027
- private async getDatabaseFunctions(): Promise<DatabaseFunction[]> {
1028
- const regularFunctions = await this.knex.raw(`
1029
- SELECT
1030
- p.proname as name,
1031
- pg_get_function_identity_arguments(p.oid) as arguments,
1032
- pg_get_functiondef(p.oid) as definition,
1033
- false as is_aggregate
1034
- FROM pg_proc p
1035
- JOIN pg_namespace n ON p.pronamespace = n.oid
1036
- WHERE n.nspname = 'public'
1037
- AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
1038
- ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
1039
- `);
1040
-
1041
- const aggregateFunctions = await this.knex.raw(`
1042
- SELECT
1043
- p.proname as name,
1044
- pg_get_function_identity_arguments(p.oid) as arguments,
1045
- a.aggtransfn::regproc::text as trans_func,
1046
- a.aggfinalfn::regproc::text as final_func,
1047
- a.agginitval as init_val,
1048
- pg_catalog.format_type(a.aggtranstype, NULL) as state_type,
1049
- true as is_aggregate
1050
- FROM pg_proc p
1051
- JOIN pg_aggregate a ON p.oid = a.aggfnoid
1052
- JOIN pg_namespace n ON p.pronamespace = n.oid
1053
- WHERE n.nspname = 'public'
1054
- ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
1055
- `);
1056
-
1057
- const result: DatabaseFunction[] = [];
1058
-
1059
- for (const row of regularFunctions.rows || []) {
1060
- const definition = row.definition || '';
1061
- const name = row.name || '';
1062
- const argumentsStr = row.arguments || '';
1063
-
1064
- if (!definition) {
1065
- continue;
1066
- }
1067
-
1068
- const signature = `${name}(${argumentsStr})`;
1069
- const body = this.normalizeFunctionBody(this.extractFunctionBody(definition));
1070
-
1071
- result.push({
1072
- name,
1073
- signature,
1074
- body,
1075
- isAggregate: false,
1076
- definition,
1077
- });
1078
- }
1079
-
1080
- for (const row of aggregateFunctions.rows || []) {
1081
- const name = row.name || '';
1082
- const argumentsStr = row.arguments || '';
1083
- const transFunc = row.trans_func || '';
1084
- const finalFunc = row.final_func || '';
1085
- const initVal = row.init_val;
1086
- const stateType = row.state_type || '';
1087
-
1088
- const signature = `${name}(${argumentsStr})`;
1089
-
1090
- let aggregateDef = `CREATE AGGREGATE ${name}(${argumentsStr}) (`;
1091
- aggregateDef += `SFUNC = ${transFunc}, STYPE = ${stateType}`;
1092
-
1093
- if (finalFunc) {
1094
- aggregateDef += `, FINALFUNC = ${finalFunc}`;
1095
- }
1096
-
1097
- if (initVal !== null && initVal !== undefined) {
1098
- let initValStr: string;
1099
- if (typeof initVal === 'string') {
1100
- initValStr = `'${initVal}'`;
1101
- } else {
1102
- const numStr = String(initVal);
1103
- initValStr = /^\d+$/.test(numStr) ? `'${numStr}'` : numStr;
1104
- }
1105
- aggregateDef += `, INITCOND = ${initValStr}`;
1106
- }
1107
-
1108
- aggregateDef += ');';
1109
-
1110
- result.push({
1111
- name,
1112
- signature,
1113
- body: this.normalizeAggregateDefinition(aggregateDef),
1114
- isAggregate: true,
1115
- definition: aggregateDef,
1116
- });
1117
- }
1118
-
1119
- return result;
1120
- }
1121
-
1122
982
  private async handleFunctions(up: Callbacks, down: Callbacks) {
1123
983
  if (!this.parsedFunctions || this.parsedFunctions.length === 0) {
1124
984
  return;
@@ -1126,7 +986,7 @@ export class MigrationGenerator {
1126
986
 
1127
987
  const definedFunctions = this.parsedFunctions;
1128
988
 
1129
- const dbFunctions = await this.getDatabaseFunctions();
989
+ const dbFunctions = await getDatabaseFunctions(this.knex);
1130
990
  const dbFunctionsBySignature = new Map<string, DatabaseFunction>();
1131
991
  for (const func of dbFunctions) {
1132
992
  dbFunctionsBySignature.set(func.signature, func);
@@ -1163,12 +1023,10 @@ export class MigrationGenerator {
1163
1023
  }
1164
1024
  });
1165
1025
  } else {
1166
- const dbBody = dbFunc.isAggregate
1167
- ? this.normalizeAggregateDefinition(dbFunc.body)
1168
- : this.normalizeFunctionBody(dbFunc.body);
1026
+ const dbBody = dbFunc.isAggregate ? normalizeAggregateDefinition(dbFunc.body) : normalizeFunctionBody(dbFunc.body);
1169
1027
  const definedBody = definedFunc.isAggregate
1170
- ? this.normalizeAggregateDefinition(definedFunc.body)
1171
- : this.normalizeFunctionBody(definedFunc.body);
1028
+ ? normalizeAggregateDefinition(definedFunc.body)
1029
+ : normalizeFunctionBody(definedFunc.body);
1172
1030
 
1173
1031
  if (dbBody !== definedBody) {
1174
1032
  const oldDefinition = dbFunc.definition || dbFunc.body;
@@ -1,7 +1,7 @@
1
1
  import { Knex } from 'knex';
2
2
  import { ParsedFunction } from './types';
3
3
 
4
- type DatabaseFunction = {
4
+ export type DatabaseFunction = {
5
5
  name: string;
6
6
  signature: string;
7
7
  body: string;
@@ -19,11 +19,31 @@ const normalizeWhitespace = (str: string): string => {
19
19
  .trim();
20
20
  };
21
21
 
22
- const normalizeFunctionBody = (body: string): string => {
22
+ export const normalizeFunctionBody = (body: string): string => {
23
23
  return normalizeWhitespace(body);
24
24
  };
25
25
 
26
- const extractFunctionBody = (definition: string): string => {
26
+ export const normalizeAggregateDefinition = (definition: string): string => {
27
+ let normalized = definition
28
+ .replace(/\s+/g, ' ')
29
+ .replace(/\s*\(\s*/g, '(')
30
+ .replace(/\s*\)\s*/g, ')')
31
+ .replace(/\s*,\s*/g, ',')
32
+ .trim();
33
+
34
+ const initCondMatch = normalized.match(/INITCOND\s*=\s*([^,)]+)/i);
35
+ if (initCondMatch) {
36
+ const initCondValue = initCondMatch[1].trim();
37
+ const unquoted = initCondValue.replace(/^['"]|['"]$/g, '');
38
+ if (/^\d+$/.test(unquoted)) {
39
+ normalized = normalized.replace(/INITCOND\s*=\s*[^,)]+/i, `INITCOND = '${unquoted}'`);
40
+ }
41
+ }
42
+
43
+ return normalized;
44
+ };
45
+
46
+ export const extractFunctionBody = (definition: string): string => {
27
47
  const dollarQuoteMatch = definition.match(/AS\s+\$([^$]*)\$([\s\S]*?)\$\1\$/i);
28
48
  if (dollarQuoteMatch) {
29
49
  return dollarQuoteMatch[2].trim();
@@ -37,7 +57,7 @@ const extractFunctionBody = (definition: string): string => {
37
57
  return definition;
38
58
  };
39
59
 
40
- const getDatabaseFunctions = async (knex: Knex): Promise<DatabaseFunction[]> => {
60
+ export const getDatabaseFunctions = async (knex: Knex): Promise<DatabaseFunction[]> => {
41
61
  const regularFunctions = await knex.raw(`
42
62
  SELECT
43
63
  p.proname as name,
@@ -108,7 +128,13 @@ const getDatabaseFunctions = async (knex: Knex): Promise<DatabaseFunction[]> =>
108
128
  }
109
129
 
110
130
  if (initVal !== null && initVal !== undefined) {
111
- const initValStr = typeof initVal === 'string' ? `'${initVal}'` : String(initVal);
131
+ let initValStr: string;
132
+ if (typeof initVal === 'string') {
133
+ initValStr = `'${initVal}'`;
134
+ } else {
135
+ const numStr = String(initVal);
136
+ initValStr = /^\d+$/.test(numStr) ? `'${numStr}'` : numStr;
137
+ }
112
138
  aggregateDef += `, INITCOND = ${initValStr}`;
113
139
  }
114
140
 
@@ -117,7 +143,7 @@ const getDatabaseFunctions = async (knex: Knex): Promise<DatabaseFunction[]> =>
117
143
  result.push({
118
144
  name,
119
145
  signature,
120
- body: normalizeFunctionBody(aggregateDef),
146
+ body: normalizeAggregateDefinition(aggregateDef),
121
147
  isAggregate: true,
122
148
  definition: aggregateDef,
123
149
  });