@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.
- package/CHANGELOG.md +2 -2
- package/dist/bin/gqm.cjs +125 -656
- package/dist/cjs/index.cjs +2132 -2702
- package/dist/esm/migrations/generate.d.ts +1 -9
- package/dist/esm/migrations/generate.js +33 -269
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/migrations/index.d.ts +0 -2
- package/dist/esm/migrations/index.js +0 -2
- package/dist/esm/migrations/index.js.map +1 -1
- package/dist/esm/models/model-definitions.d.ts +1 -4
- package/dist/esm/resolvers/filters.js +14 -73
- package/dist/esm/resolvers/filters.js.map +1 -1
- package/dist/esm/resolvers/selects.js +2 -33
- package/dist/esm/resolvers/selects.js.map +1 -1
- package/dist/esm/resolvers/utils.d.ts +0 -1
- package/dist/esm/resolvers/utils.js +0 -22
- package/dist/esm/resolvers/utils.js.map +1 -1
- package/docs/docs/3-fields.md +0 -149
- package/docs/docs/5-migrations.md +1 -9
- package/package.json +2 -2
- package/src/bin/gqm/gqm.ts +5 -44
- package/src/bin/gqm/settings.ts +0 -7
- package/src/bin/gqm/static-eval.ts +102 -0
- package/src/bin/gqm/utils.ts +0 -1
- package/src/migrations/generate.ts +41 -334
- package/src/migrations/index.ts +0 -2
- package/src/models/model-definitions.ts +1 -4
- package/src/resolvers/filters.ts +25 -81
- package/src/resolvers/selects.ts +5 -38
- package/src/resolvers/utils.ts +0 -32
- package/dist/esm/migrations/generate-functions.d.ts +0 -2
- package/dist/esm/migrations/generate-functions.js +0 -60
- package/dist/esm/migrations/generate-functions.js.map +0 -1
- package/dist/esm/migrations/types.d.ts +0 -7
- package/dist/esm/migrations/types.js +0 -2
- package/dist/esm/migrations/types.js.map +0 -1
- package/dist/esm/migrations/update-functions.d.ts +0 -3
- package/dist/esm/migrations/update-functions.js +0 -177
- package/dist/esm/migrations/update-functions.js.map +0 -1
- package/src/bin/gqm/parse-functions.ts +0 -141
- package/src/migrations/generate-functions.ts +0 -74
- package/src/migrations/types.ts +0 -7
- package/src/migrations/update-functions.ts +0 -221
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'fs';
|
|
2
|
-
import { IndentationText, Project } from 'ts-morph';
|
|
3
|
-
import { ParsedFunction } from '../../migrations/types';
|
|
4
|
-
import { staticEval } from './static-eval';
|
|
5
|
-
import { findDeclarationInFile } from './utils';
|
|
6
|
-
|
|
7
|
-
const normalizeWhitespace = (str: string): string => {
|
|
8
|
-
return str
|
|
9
|
-
.replace(/\s+/g, ' ')
|
|
10
|
-
.replace(/\s*\(\s*/g, '(')
|
|
11
|
-
.replace(/\s*\)\s*/g, ')')
|
|
12
|
-
.replace(/\s*,\s*/g, ',')
|
|
13
|
-
.replace(/\s*;\s*/g, ';')
|
|
14
|
-
.trim();
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const normalizeFunctionBody = (body: string): string => {
|
|
18
|
-
return normalizeWhitespace(body);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const normalizeAggregateDefinition = (definition: string): string => {
|
|
22
|
-
let normalized = normalizeWhitespace(definition);
|
|
23
|
-
|
|
24
|
-
const initCondMatch = normalized.match(/INITCOND\s*=\s*([^,)]+)/i);
|
|
25
|
-
if (initCondMatch) {
|
|
26
|
-
const initCondValue = initCondMatch[1].trim();
|
|
27
|
-
const unquoted = initCondValue.replace(/^['"]|['"]$/g, '');
|
|
28
|
-
if (/^\d+$/.test(unquoted)) {
|
|
29
|
-
normalized = normalized.replace(/INITCOND\s*=\s*[^,)]+/i, `INITCOND = '${unquoted}'`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return normalized;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const extractFunctionSignature = (definition: string, isAggregate: boolean): string | null => {
|
|
37
|
-
if (isAggregate) {
|
|
38
|
-
const createMatch = definition.match(/CREATE\s+(OR\s+REPLACE\s+)?AGGREGATE\s+([^(]+)\(/i);
|
|
39
|
-
if (!createMatch) {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const functionNamePart = createMatch[2].trim().replace(/^[^.]+\./, '');
|
|
44
|
-
const argsMatch = definition.match(/CREATE\s+(OR\s+REPLACE\s+)?AGGREGATE\s+[^(]+\(([^)]*)\)/i);
|
|
45
|
-
const args = argsMatch ? argsMatch[2].trim() : '';
|
|
46
|
-
|
|
47
|
-
return `${functionNamePart}(${args})`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const createMatch = definition.match(/CREATE\s+(OR\s+REPLACE\s+)?FUNCTION\s+([^(]+)\(/i);
|
|
51
|
-
if (!createMatch) {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const functionNamePart = createMatch[2].trim().replace(/^[^.]+\./, '');
|
|
56
|
-
const fullArgsMatch = definition.match(
|
|
57
|
-
/CREATE\s+(OR\s+REPLACE\s+)?FUNCTION\s+[^(]+\(([\s\S]*?)\)\s*(RETURNS|LANGUAGE|AS|STRICT|IMMUTABLE|STABLE|VOLATILE|SECURITY)/i,
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
if (!fullArgsMatch) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const argsSection = fullArgsMatch[2].trim();
|
|
65
|
-
const args = argsSection
|
|
66
|
-
.split(/\s*,\s*/)
|
|
67
|
-
.map((arg) => {
|
|
68
|
-
return arg.trim().replace(/\s+/g, ' ');
|
|
69
|
-
})
|
|
70
|
-
.join(', ');
|
|
71
|
-
|
|
72
|
-
return `${functionNamePart}(${args})`;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const extractFunctionBody = (definition: string): string => {
|
|
76
|
-
const dollarQuoteMatch = definition.match(/AS\s+\$([^$]*)\$([\s\S]*?)\$\1\$/i);
|
|
77
|
-
if (dollarQuoteMatch) {
|
|
78
|
-
return dollarQuoteMatch[2].trim();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const bodyMatch = definition.match(/AS\s+\$\$([\s\S]*?)\$\$/i) || definition.match(/AS\s+['"]([\s\S]*?)['"]/i);
|
|
82
|
-
if (bodyMatch) {
|
|
83
|
-
return bodyMatch[1].trim();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return definition;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const parseFunctionsFile = (filePath: string): ParsedFunction[] => {
|
|
90
|
-
if (!existsSync(filePath)) {
|
|
91
|
-
return [];
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const project = new Project({
|
|
95
|
-
manipulationSettings: {
|
|
96
|
-
indentationText: IndentationText.TwoSpaces,
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
const sourceFile = project.addSourceFileAtPath(filePath);
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
const functionsDeclaration = findDeclarationInFile(sourceFile, 'functions');
|
|
103
|
-
const functionsArray = staticEval(functionsDeclaration, {}) as string[];
|
|
104
|
-
|
|
105
|
-
if (!Array.isArray(functionsArray)) {
|
|
106
|
-
return [];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const parsedFunctions: ParsedFunction[] = [];
|
|
110
|
-
|
|
111
|
-
for (const definition of functionsArray) {
|
|
112
|
-
if (!definition || typeof definition !== 'string') {
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const trimmedDefinition = definition.trim();
|
|
117
|
-
const isAggregate = /CREATE\s+(OR\s+REPLACE\s+)?AGGREGATE/i.test(trimmedDefinition);
|
|
118
|
-
const signature = extractFunctionSignature(trimmedDefinition, isAggregate);
|
|
119
|
-
|
|
120
|
-
if (!signature) {
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const nameMatch = signature.match(/^([^(]+)\(/);
|
|
125
|
-
const name = nameMatch ? nameMatch[1].trim().split('.').pop() || '' : '';
|
|
126
|
-
const body = isAggregate ? trimmedDefinition : extractFunctionBody(trimmedDefinition);
|
|
127
|
-
|
|
128
|
-
parsedFunctions.push({
|
|
129
|
-
name,
|
|
130
|
-
signature,
|
|
131
|
-
body: isAggregate ? normalizeAggregateDefinition(body) : normalizeFunctionBody(body),
|
|
132
|
-
fullDefinition: trimmedDefinition,
|
|
133
|
-
isAggregate,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return parsedFunctions;
|
|
138
|
-
} catch (error) {
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
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 `export const functions: string[] = [];\n`;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const functionsArrayString = functions.map((func) => ` ${JSON.stringify(func)}`).join(',\n');
|
|
72
|
-
|
|
73
|
-
return `export const functions: string[] = [\n${functionsArrayString},\n];\n`;
|
|
74
|
-
};
|
package/src/migrations/types.ts
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { Knex } from 'knex';
|
|
2
|
-
import { ParsedFunction } from './types';
|
|
3
|
-
|
|
4
|
-
type DatabaseFunction = {
|
|
5
|
-
name: string;
|
|
6
|
-
signature: string;
|
|
7
|
-
body: string;
|
|
8
|
-
isAggregate: boolean;
|
|
9
|
-
definition?: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const normalizeWhitespace = (str: string): string => {
|
|
13
|
-
return str
|
|
14
|
-
.replace(/\s+/g, ' ')
|
|
15
|
-
.replace(/\s*\(\s*/g, '(')
|
|
16
|
-
.replace(/\s*\)\s*/g, ')')
|
|
17
|
-
.replace(/\s*,\s*/g, ',')
|
|
18
|
-
.replace(/\s*;\s*/g, ';')
|
|
19
|
-
.trim();
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const normalizeFunctionBody = (body: string): string => {
|
|
23
|
-
return normalizeWhitespace(body);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const extractFunctionBody = (definition: string): string => {
|
|
27
|
-
const dollarQuoteMatch = definition.match(/AS\s+\$([^$]*)\$([\s\S]*?)\$\1\$/i);
|
|
28
|
-
if (dollarQuoteMatch) {
|
|
29
|
-
return dollarQuoteMatch[2].trim();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const bodyMatch = definition.match(/AS\s+\$\$([\s\S]*?)\$\$/i) || definition.match(/AS\s+['"]([\s\S]*?)['"]/i);
|
|
33
|
-
if (bodyMatch) {
|
|
34
|
-
return bodyMatch[1].trim();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return definition;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const getDatabaseFunctions = async (knex: Knex): Promise<DatabaseFunction[]> => {
|
|
41
|
-
const regularFunctions = await knex.raw(`
|
|
42
|
-
SELECT
|
|
43
|
-
p.proname as name,
|
|
44
|
-
pg_get_function_identity_arguments(p.oid) as arguments,
|
|
45
|
-
pg_get_functiondef(p.oid) as definition,
|
|
46
|
-
false as is_aggregate
|
|
47
|
-
FROM pg_proc p
|
|
48
|
-
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
49
|
-
WHERE n.nspname = 'public'
|
|
50
|
-
AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
|
|
51
|
-
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
52
|
-
`);
|
|
53
|
-
|
|
54
|
-
const aggregateFunctions = await knex.raw(`
|
|
55
|
-
SELECT
|
|
56
|
-
p.proname as name,
|
|
57
|
-
pg_get_function_identity_arguments(p.oid) as arguments,
|
|
58
|
-
a.aggtransfn::regproc::text as trans_func,
|
|
59
|
-
a.aggfinalfn::regproc::text as final_func,
|
|
60
|
-
a.agginitval as init_val,
|
|
61
|
-
pg_catalog.format_type(a.aggtranstype, NULL) as state_type,
|
|
62
|
-
true as is_aggregate
|
|
63
|
-
FROM pg_proc p
|
|
64
|
-
JOIN pg_aggregate a ON p.oid = a.aggfnoid
|
|
65
|
-
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
66
|
-
WHERE n.nspname = 'public'
|
|
67
|
-
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
68
|
-
`);
|
|
69
|
-
|
|
70
|
-
const result: DatabaseFunction[] = [];
|
|
71
|
-
|
|
72
|
-
for (const row of regularFunctions.rows || []) {
|
|
73
|
-
const definition = row.definition || '';
|
|
74
|
-
const name = row.name || '';
|
|
75
|
-
const argumentsStr = row.arguments || '';
|
|
76
|
-
|
|
77
|
-
if (!definition) {
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const signature = `${name}(${argumentsStr})`;
|
|
82
|
-
const body = normalizeFunctionBody(extractFunctionBody(definition));
|
|
83
|
-
|
|
84
|
-
result.push({
|
|
85
|
-
name,
|
|
86
|
-
signature,
|
|
87
|
-
body,
|
|
88
|
-
isAggregate: false,
|
|
89
|
-
definition,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
for (const row of aggregateFunctions.rows || []) {
|
|
94
|
-
const name = row.name || '';
|
|
95
|
-
const argumentsStr = row.arguments || '';
|
|
96
|
-
const transFunc = row.trans_func || '';
|
|
97
|
-
const finalFunc = row.final_func || '';
|
|
98
|
-
const initVal = row.init_val;
|
|
99
|
-
const stateType = row.state_type || '';
|
|
100
|
-
|
|
101
|
-
const signature = `${name}(${argumentsStr})`;
|
|
102
|
-
|
|
103
|
-
let aggregateDef = `CREATE AGGREGATE ${name}(${argumentsStr}) (`;
|
|
104
|
-
aggregateDef += `SFUNC = ${transFunc}, STYPE = ${stateType}`;
|
|
105
|
-
|
|
106
|
-
if (finalFunc) {
|
|
107
|
-
aggregateDef += `, FINALFUNC = ${finalFunc}`;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (initVal !== null && initVal !== undefined) {
|
|
111
|
-
const initValStr = typeof initVal === 'string' ? `'${initVal}'` : String(initVal);
|
|
112
|
-
aggregateDef += `, INITCOND = ${initValStr}`;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
aggregateDef += ');';
|
|
116
|
-
|
|
117
|
-
result.push({
|
|
118
|
-
name,
|
|
119
|
-
signature,
|
|
120
|
-
body: normalizeFunctionBody(aggregateDef),
|
|
121
|
-
isAggregate: true,
|
|
122
|
-
definition: aggregateDef,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return result;
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const compareFunctions = (defined: ParsedFunction, db: DatabaseFunction): { changed: boolean; diff?: string } => {
|
|
130
|
-
const definedBody = normalizeFunctionBody(defined.body);
|
|
131
|
-
const dbBody = normalizeFunctionBody(db.body);
|
|
132
|
-
|
|
133
|
-
if (definedBody !== dbBody) {
|
|
134
|
-
const definedPreview = definedBody.length > 200 ? `${definedBody.substring(0, 200)}...` : definedBody;
|
|
135
|
-
const dbPreview = dbBody.length > 200 ? `${dbBody.substring(0, 200)}...` : dbBody;
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
changed: true,
|
|
139
|
-
diff: `Definition changed:\n File: ${definedPreview}\n DB: ${dbPreview}`,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return { changed: false };
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
export const updateFunctions = async (knex: Knex, parsedFunctions: ParsedFunction[]): Promise<void> => {
|
|
147
|
-
if (parsedFunctions.length === 0) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const definedFunctions = parsedFunctions;
|
|
152
|
-
|
|
153
|
-
const dbFunctions = await getDatabaseFunctions(knex);
|
|
154
|
-
const dbFunctionsBySignature = new Map<string, DatabaseFunction>();
|
|
155
|
-
for (const func of dbFunctions) {
|
|
156
|
-
dbFunctionsBySignature.set(func.signature, func);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
console.info(`Found ${definedFunctions.length} function(s) in file, ${dbFunctions.length} function(s) in database.`);
|
|
160
|
-
|
|
161
|
-
let updatedCount = 0;
|
|
162
|
-
let skippedCount = 0;
|
|
163
|
-
|
|
164
|
-
for (const definedFunc of definedFunctions) {
|
|
165
|
-
const dbFunc = dbFunctionsBySignature.get(definedFunc.signature);
|
|
166
|
-
|
|
167
|
-
if (!dbFunc) {
|
|
168
|
-
try {
|
|
169
|
-
await knex.raw(definedFunc.fullDefinition);
|
|
170
|
-
console.info(`✓ Created ${definedFunc.isAggregate ? 'aggregate' : 'function'}: ${definedFunc.signature}`);
|
|
171
|
-
updatedCount++;
|
|
172
|
-
} catch (error: any) {
|
|
173
|
-
console.error(
|
|
174
|
-
`✗ Failed to create ${definedFunc.isAggregate ? 'aggregate' : 'function'} ${definedFunc.signature}:`,
|
|
175
|
-
error.message,
|
|
176
|
-
);
|
|
177
|
-
throw error;
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
const comparison = compareFunctions(definedFunc, dbFunc);
|
|
181
|
-
if (comparison.changed) {
|
|
182
|
-
console.info(`\n⚠ ${definedFunc.isAggregate ? 'Aggregate' : 'Function'} ${definedFunc.signature} has changes:`);
|
|
183
|
-
if (comparison.diff) {
|
|
184
|
-
console.info(comparison.diff);
|
|
185
|
-
}
|
|
186
|
-
try {
|
|
187
|
-
if (definedFunc.isAggregate) {
|
|
188
|
-
const dropMatch = definedFunc.fullDefinition.match(/CREATE\s+(OR\s+REPLACE\s+)?AGGREGATE\s+([^(]+)\(/i);
|
|
189
|
-
if (dropMatch) {
|
|
190
|
-
const functionName = dropMatch[2].trim();
|
|
191
|
-
const argsMatch = definedFunc.fullDefinition.match(/CREATE\s+(OR\s+REPLACE\s+)?AGGREGATE\s+[^(]+\(([^)]*)\)/i);
|
|
192
|
-
const args = argsMatch ? argsMatch[2].trim() : '';
|
|
193
|
-
await knex.raw(`DROP AGGREGATE IF EXISTS ${functionName}${args ? `(${args})` : ''}`);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
await knex.raw(definedFunc.fullDefinition);
|
|
197
|
-
console.info(`✓ Updated ${definedFunc.isAggregate ? 'aggregate' : 'function'}: ${definedFunc.signature}\n`);
|
|
198
|
-
updatedCount++;
|
|
199
|
-
} catch (error: any) {
|
|
200
|
-
console.error(
|
|
201
|
-
`✗ Failed to update ${definedFunc.isAggregate ? 'aggregate' : 'function'} ${definedFunc.signature}:`,
|
|
202
|
-
error.message,
|
|
203
|
-
);
|
|
204
|
-
throw error;
|
|
205
|
-
}
|
|
206
|
-
} else {
|
|
207
|
-
console.info(
|
|
208
|
-
`○ Skipped ${definedFunc.isAggregate ? 'aggregate' : 'function'} (unchanged): ${definedFunc.signature}`,
|
|
209
|
-
);
|
|
210
|
-
skippedCount++;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
console.info(`\nSummary: ${updatedCount} updated, ${skippedCount} skipped`);
|
|
216
|
-
if (updatedCount > 0) {
|
|
217
|
-
console.info('Functions updated successfully.');
|
|
218
|
-
} else {
|
|
219
|
-
console.info('All functions are up to date.');
|
|
220
|
-
}
|
|
221
|
-
};
|