@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
@@ -17,20 +17,10 @@ import {
17
17
  summonByName,
18
18
  typeToField,
19
19
  } from '../models/utils';
20
- import { getColumnName } from '../resolvers';
21
20
  import { Value } from '../values';
22
- import { ParsedFunction } from './types';
23
21
 
24
22
  type Callbacks = (() => void)[];
25
23
 
26
- type DatabaseFunction = {
27
- name: string;
28
- signature: string;
29
- body: string;
30
- isAggregate: boolean;
31
- definition?: string;
32
- };
33
-
34
24
  export class MigrationGenerator {
35
25
  // eslint-disable-next-line @typescript-eslint/dot-notation
36
26
  private writer: CodeBlockWriter = new CodeBlockWriter['default']({
@@ -42,14 +32,11 @@ export class MigrationGenerator {
42
32
  private uuidUsed?: boolean;
43
33
  private nowUsed?: boolean;
44
34
  public needsMigration = false;
45
- private knex: Knex;
46
35
 
47
36
  constructor(
48
37
  knex: Knex,
49
38
  private models: Models,
50
- private parsedFunctions?: ParsedFunction[],
51
39
  ) {
52
- this.knex = knex;
53
40
  this.schema = SchemaInspector(knex);
54
41
  }
55
42
 
@@ -70,8 +57,6 @@ export class MigrationGenerator {
70
57
  down,
71
58
  );
72
59
 
73
- await this.handleFunctions(up, down);
74
-
75
60
  for (const model of models.entities) {
76
61
  if (model.deleted) {
77
62
  up.push(() => {
@@ -142,9 +127,7 @@ export class MigrationGenerator {
142
127
  foreignKey: 'id',
143
128
  });
144
129
  }
145
- for (const field of model.fields
146
- .filter(not(isInherited))
147
- .filter((f) => !(f.generateAs?.type === 'expression'))) {
130
+ for (const field of model.fields.filter(not(isInherited))) {
148
131
  this.column(field);
149
132
  }
150
133
  });
@@ -155,8 +138,12 @@ export class MigrationGenerator {
155
138
  });
156
139
  } else {
157
140
  // Rename fields
158
- const fieldsToRename = model.fields.filter(not(isInherited)).filter(({ oldName }) => oldName);
159
- this.renameFields(model.name, fieldsToRename, up, down);
141
+ this.renameFields(
142
+ model,
143
+ model.fields.filter(not(isInherited)).filter(({ oldName }) => oldName),
144
+ up,
145
+ down,
146
+ );
160
147
 
161
148
  // Add missing fields
162
149
  this.createFields(
@@ -166,7 +153,6 @@ export class MigrationGenerator {
166
153
  .filter(
167
154
  ({ name, ...field }) =>
168
155
  field.kind !== 'custom' &&
169
- !(field.generateAs?.type === 'expression') &&
170
156
  !this.getColumn(model.name, field.kind === 'relation' ? field.foreignKey || `${name}Id` : name),
171
157
  ),
172
158
  up,
@@ -175,7 +161,7 @@ export class MigrationGenerator {
175
161
 
176
162
  // Update fields
177
163
  const rawExistingFields = model.fields.filter((field) => {
178
- if (!field.generateAs || field.generateAs.type === 'expression') {
164
+ if (!field.generateAs) {
179
165
  return false;
180
166
  }
181
167
 
@@ -184,7 +170,7 @@ export class MigrationGenerator {
184
170
  return false;
185
171
  }
186
172
 
187
- if (col.generation_expression !== field.generateAs.expression) {
173
+ if (col.generation_expression !== field.generateAs) {
188
174
  return true;
189
175
  }
190
176
 
@@ -194,9 +180,7 @@ export class MigrationGenerator {
194
180
  this.updateFieldsRaw(model, rawExistingFields, up, down);
195
181
  }
196
182
 
197
- const existingFields = model.fields.filter(
198
- (field) => (!field.generateAs || field.generateAs.type === 'expression') && this.hasChanged(model, field),
199
- );
183
+ const existingFields = model.fields.filter((field) => !field.generateAs && this.hasChanged(model, field));
200
184
  this.updateFields(model, existingFields, up, down);
201
185
  }
202
186
 
@@ -228,9 +212,7 @@ export class MigrationGenerator {
228
212
  writer.writeLine(`deleteRootId: row.deleteRootId,`);
229
213
  }
230
214
 
231
- for (const { name, kind } of model.fields
232
- .filter(isUpdatableField)
233
- .filter((f) => !(f.generateAs?.type === 'expression'))) {
215
+ for (const { name, kind } of model.fields.filter(isUpdatableField)) {
234
216
  const col = kind === 'relation' ? `${name}Id` : name;
235
217
 
236
218
  writer.writeLine(`${col}: row.${col},`);
@@ -249,23 +231,11 @@ export class MigrationGenerator {
249
231
  });
250
232
  } else {
251
233
  const revisionTable = `${model.name}Revision`;
252
-
253
- this.renameFields(
254
- revisionTable,
255
- model.fields
256
- .filter(isUpdatableField)
257
- .filter(not(isInherited))
258
- .filter(({ oldName }) => oldName),
259
- up,
260
- down,
261
- );
262
-
263
234
  const missingRevisionFields = model.fields
264
235
  .filter(isUpdatableField)
265
236
  .filter(
266
237
  ({ name, ...field }) =>
267
238
  field.kind !== 'custom' &&
268
- !(field.generateAs?.type === 'expression') &&
269
239
  !this.getColumn(revisionTable, field.kind === 'relation' ? field.foreignKey || `${name}Id` : name),
270
240
  );
271
241
 
@@ -352,14 +322,14 @@ export class MigrationGenerator {
352
322
  return writer.toString();
353
323
  }
354
324
 
355
- private renameFields(tableName: string, fields: EntityField[], up: Callbacks, down: Callbacks) {
325
+ private renameFields(model: EntityModel, fields: EntityField[], up: Callbacks, down: Callbacks) {
356
326
  if (!fields.length) {
357
327
  return;
358
328
  }
359
329
 
360
330
  up.push(() => {
361
331
  for (const field of fields) {
362
- this.alterTable(tableName, () => {
332
+ this.alterTable(model.name, () => {
363
333
  this.renameColumn(
364
334
  field.kind === 'relation' ? `${field.oldName}Id` : get(field, 'oldName'),
365
335
  field.kind === 'relation' ? `${field.name}Id` : field.name,
@@ -370,7 +340,7 @@ export class MigrationGenerator {
370
340
 
371
341
  down.push(() => {
372
342
  for (const field of fields) {
373
- this.alterTable(tableName, () => {
343
+ this.alterTable(model.name, () => {
374
344
  this.renameColumn(
375
345
  field.kind === 'relation' ? `${field.name}Id` : field.name,
376
346
  field.kind === 'relation' ? `${field.oldName}Id` : get(field, 'oldName'),
@@ -380,7 +350,7 @@ export class MigrationGenerator {
380
350
  });
381
351
 
382
352
  for (const field of fields) {
383
- summonByName(this.columns[tableName], field.kind === 'relation' ? `${field.oldName!}Id` : field.oldName!).name =
353
+ summonByName(this.columns[model.name], field.kind === 'relation' ? `${field.oldName!}Id` : field.oldName!).name =
384
354
  field.kind === 'relation' ? `${field.name}Id` : field.name;
385
355
  }
386
356
  }
@@ -395,10 +365,6 @@ export class MigrationGenerator {
395
365
  const updates: Callbacks = [];
396
366
  const postAlter: Callbacks = [];
397
367
  for (const field of fields) {
398
- if (field.generateAs?.type === 'expression') {
399
- continue;
400
- }
401
-
402
368
  alter.push(() => this.column(field, { setNonNull: field.defaultValue !== undefined }));
403
369
 
404
370
  if (field.generateAs) {
@@ -464,7 +430,7 @@ export class MigrationGenerator {
464
430
  });
465
431
 
466
432
  if (isUpdatableModel(model)) {
467
- const updatableFields = fields.filter(isUpdatableField).filter((f) => !(f.generateAs?.type === 'expression'));
433
+ const updatableFields = fields.filter(isUpdatableField);
468
434
  if (!updatableFields.length) {
469
435
  return;
470
436
  }
@@ -518,7 +484,7 @@ export class MigrationGenerator {
518
484
  });
519
485
 
520
486
  if (isUpdatableModel(model)) {
521
- const updatableFields = fields.filter(isUpdatableField).filter((f) => !(f.generateAs?.type === 'expression'));
487
+ const updatableFields = fields.filter(isUpdatableField);
522
488
  if (!updatableFields.length) {
523
489
  return;
524
490
  }
@@ -562,9 +528,7 @@ export class MigrationGenerator {
562
528
  }
563
529
  }
564
530
 
565
- for (const field of model.fields
566
- .filter(and(isUpdatableField, not(isInherited)))
567
- .filter((f) => !(f.generateAs?.type === 'expression'))) {
531
+ for (const field of model.fields.filter(and(isUpdatableField, not(isInherited)))) {
568
532
  this.column(field, { setUnique: false, setDefault: false });
569
533
  }
570
534
  });
@@ -582,31 +546,23 @@ export class MigrationGenerator {
582
546
  });
583
547
 
584
548
  // Insert data for missing revisions columns
585
- const revisionFieldsWithDataToCopy = missingRevisionFields.filter(
586
- (field) =>
587
- this.columns[model.name].find((col) => col.name === getColumnName(field)) ||
588
- field.defaultValue !== undefined ||
589
- field.nonNull,
590
- );
591
- if (revisionFieldsWithDataToCopy.length) {
592
- this.writer
593
- .write(`await knex('${model.name}Revision').update(`)
594
- .inlineBlock(() => {
595
- for (const { name, kind: type } of revisionFieldsWithDataToCopy) {
596
- const col = type === 'relation' ? `${name}Id` : name;
597
- this.writer
598
- .write(
599
- `${col}: knex.raw('(select "${col}" from "${model.name}" where "${model.name}".id = "${
600
- model.name
601
- }Revision"."${typeToField(model.name)}Id")'),`,
602
- )
603
- .newLine();
604
- }
605
- })
606
- .write(');')
607
- .newLine()
608
- .blankLine();
609
- }
549
+ this.writer
550
+ .write(`await knex('${model.name}Revision').update(`)
551
+ .inlineBlock(() => {
552
+ for (const { name, kind: type } of missingRevisionFields) {
553
+ const col = type === 'relation' ? `${name}Id` : name;
554
+ this.writer
555
+ .write(
556
+ `${col}: knex.raw('(select "${col}" from "${model.name}" where "${model.name}".id = "${
557
+ model.name
558
+ }Revision"."${typeToField(model.name)}Id")'),`,
559
+ )
560
+ .newLine();
561
+ }
562
+ })
563
+ .write(');')
564
+ .newLine()
565
+ .blankLine();
610
566
 
611
567
  const nonNullableMissingRevisionFields = missingRevisionFields.filter(({ nonNull }) => nonNull);
612
568
  if (nonNullableMissingRevisionFields.length) {
@@ -690,7 +646,7 @@ export class MigrationGenerator {
690
646
  }
691
647
 
692
648
  private renameColumn(from: string, to: string) {
693
- this.writer.writeLine(`table.renameColumn('${from}', '${to}');`);
649
+ this.writer.writeLine(`table.renameColumn('${from}', '${to}')`);
694
650
  }
695
651
 
696
652
  private value(value: Value) {
@@ -725,10 +681,6 @@ export class MigrationGenerator {
725
681
  };
726
682
  const kind = field.kind;
727
683
  if (field.generateAs) {
728
- if (field.generateAs.type === 'expression') {
729
- throw new Error(`Expression fields cannot be created in SQL schema.`);
730
- }
731
-
732
684
  let type = '';
733
685
  switch (kind) {
734
686
  case undefined:
@@ -737,9 +689,6 @@ export class MigrationGenerator {
737
689
  case 'Float':
738
690
  type = `decimal(${field.precision ?? 'undefined'}, ${field.scale ?? 'undefined'})`;
739
691
  break;
740
- case 'Boolean':
741
- type = 'boolean';
742
- break;
743
692
  default:
744
693
  throw new Error(`Generated columns of kind ${kind} and type ${field.type} are not supported yet.`);
745
694
  }
@@ -759,10 +708,10 @@ export class MigrationGenerator {
759
708
  this.writer.write(`, ALTER COLUMN "${name}" DROP NOT NULL`);
760
709
  }
761
710
  }
762
- this.writer.write(`, ALTER COLUMN "${name}" SET EXPRESSION AS (${field.generateAs.expression})`);
711
+ this.writer.write(`, ALTER COLUMN "${name}" SET EXPRESSION AS (${field.generateAs})`);
763
712
  } else {
764
713
  this.writer.write(
765
- `${alter ? 'ALTER' : 'ADD'} COLUMN "${name}" ${type}${nonNull() ? ' not null' : ''} GENERATED ALWAYS AS (${field.generateAs.expression}) STORED`,
714
+ `${alter ? 'ALTER' : 'ADD'} COLUMN "${name}" ${type}${nonNull() ? ' not null' : ''} GENERATED ALWAYS AS (${field.generateAs}) STORED`,
766
715
  );
767
716
  }
768
717
 
@@ -795,10 +744,6 @@ export class MigrationGenerator {
795
744
  };
796
745
  const kind = field.kind;
797
746
  if (field.generateAs) {
798
- if (field.generateAs.type === 'expression') {
799
- throw new Error(`Expression fields cannot be created in SQL schema.`);
800
- }
801
-
802
747
  let type = '';
803
748
  switch (kind) {
804
749
  case undefined:
@@ -807,9 +752,6 @@ export class MigrationGenerator {
807
752
  case 'Float':
808
753
  type = `decimal(${field.precision ?? 'undefined'}, ${field.scale ?? 'undefined'})`;
809
754
  break;
810
- case 'Boolean':
811
- type = 'boolean';
812
- break;
813
755
  default:
814
756
  throw new Error(`Generated columns of kind ${kind} and type ${field.type} are not supported yet.`);
815
757
  }
@@ -818,7 +760,7 @@ export class MigrationGenerator {
818
760
  throw new Error(`Generated columns of kind ${kind} are not supported yet.`);
819
761
  }
820
762
  this.writer.write(
821
- `table.specificType('${name}', '${type}${nonNull() ? ' not null' : ''} GENERATED ALWAYS AS (${field.generateAs.expression}) ${field.generateAs.type === 'virtual' ? 'VIRTUAL' : 'STORED'}')`,
763
+ `table.specificType('${name}', '${type}${nonNull() ? ' not null' : ''} GENERATED ALWAYS AS (${field.generateAs}) STORED')`,
822
764
  );
823
765
  if (alter) {
824
766
  this.writer.write('.alter()');
@@ -923,19 +865,15 @@ export class MigrationGenerator {
923
865
  }
924
866
 
925
867
  private hasChanged(model: EntityModel, field: EntityField) {
926
- if (field.generateAs?.type === 'expression') {
927
- return false;
928
- }
929
-
930
868
  const col = this.getColumn(model.name, field.kind === 'relation' ? `${field.name}Id` : field.name);
931
869
  if (!col) {
932
870
  return false;
933
871
  }
934
872
 
935
873
  if (field.generateAs) {
936
- if (col.generation_expression !== field.generateAs.expression) {
874
+ if (col.generation_expression !== field.generateAs) {
937
875
  throw new Error(
938
- `Column ${col.name} has specific type ${col.generation_expression} but expected ${field.generateAs.expression}`,
876
+ `Column ${col.name} has specific type ${col.generation_expression} but expected ${field.generateAs}`,
939
877
  );
940
878
  }
941
879
  }
@@ -980,237 +918,6 @@ export class MigrationGenerator {
980
918
 
981
919
  return false;
982
920
  }
983
-
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
- private async handleFunctions(up: Callbacks, down: Callbacks) {
1123
- if (!this.parsedFunctions || this.parsedFunctions.length === 0) {
1124
- return;
1125
- }
1126
-
1127
- const definedFunctions = this.parsedFunctions;
1128
-
1129
- const dbFunctions = await this.getDatabaseFunctions();
1130
- const dbFunctionsBySignature = new Map<string, DatabaseFunction>();
1131
- for (const func of dbFunctions) {
1132
- dbFunctionsBySignature.set(func.signature, func);
1133
- }
1134
-
1135
- const definedFunctionsBySignature = new Map<string, ParsedFunction>();
1136
- for (const func of definedFunctions) {
1137
- definedFunctionsBySignature.set(func.signature, func);
1138
- }
1139
-
1140
- const functionsToRestore: { func: DatabaseFunction; definition: string }[] = [];
1141
-
1142
- for (const definedFunc of definedFunctions) {
1143
- const dbFunc = dbFunctionsBySignature.get(definedFunc.signature);
1144
-
1145
- if (!dbFunc) {
1146
- up.push(() => {
1147
- this.writer.writeLine(`await knex.raw(\`${definedFunc.fullDefinition.replace(/`/g, '\\`')}\`);`).blankLine();
1148
- });
1149
-
1150
- down.push(() => {
1151
- const isAggregate = definedFunc.isAggregate;
1152
- const dropMatch = definedFunc.fullDefinition.match(/CREATE\s+(OR\s+REPLACE\s+)?(FUNCTION|AGGREGATE)\s+([^(]+)\(/i);
1153
- if (dropMatch) {
1154
- const functionName = dropMatch[3].trim();
1155
- const argsMatch = definedFunc.fullDefinition.match(
1156
- /CREATE\s+(OR\s+REPLACE\s+)?(FUNCTION|AGGREGATE)\s+[^(]+\(([^)]*)\)/i,
1157
- );
1158
- const args = argsMatch ? argsMatch[3].trim() : '';
1159
- const dropType = isAggregate ? 'AGGREGATE' : 'FUNCTION';
1160
- this.writer
1161
- .writeLine(`await knex.raw(\`DROP ${dropType} IF EXISTS ${functionName}${args ? `(${args})` : ''}\`);`)
1162
- .blankLine();
1163
- }
1164
- });
1165
- } else {
1166
- const dbBody = dbFunc.isAggregate
1167
- ? this.normalizeAggregateDefinition(dbFunc.body)
1168
- : this.normalizeFunctionBody(dbFunc.body);
1169
- const definedBody = definedFunc.isAggregate
1170
- ? this.normalizeAggregateDefinition(definedFunc.body)
1171
- : this.normalizeFunctionBody(definedFunc.body);
1172
-
1173
- if (dbBody !== definedBody) {
1174
- const oldDefinition = dbFunc.definition || dbFunc.body;
1175
-
1176
- up.push(() => {
1177
- this.writer.writeLine(`await knex.raw(\`${definedFunc.fullDefinition.replace(/`/g, '\\`')}\`);`).blankLine();
1178
- });
1179
-
1180
- down.push(() => {
1181
- if (oldDefinition) {
1182
- this.writer.writeLine(`await knex.raw(\`${oldDefinition.replace(/`/g, '\\`')}\`);`).blankLine();
1183
- }
1184
- });
1185
- }
1186
- }
1187
- }
1188
-
1189
- for (const dbFunc of dbFunctions) {
1190
- if (!definedFunctionsBySignature.has(dbFunc.signature)) {
1191
- const definition = dbFunc.definition || dbFunc.body;
1192
-
1193
- if (definition) {
1194
- functionsToRestore.push({ func: dbFunc, definition });
1195
-
1196
- down.push(() => {
1197
- const argsMatch = dbFunc.signature.match(/\(([^)]*)\)/);
1198
- const args = argsMatch ? argsMatch[1] : '';
1199
- const dropType = dbFunc.isAggregate ? 'AGGREGATE' : 'FUNCTION';
1200
- this.writer
1201
- .writeLine(`await knex.raw(\`DROP ${dropType} IF EXISTS ${dbFunc.name}${args ? `(${args})` : ''}\`);`)
1202
- .blankLine();
1203
- });
1204
- }
1205
- }
1206
- }
1207
-
1208
- for (const { definition } of functionsToRestore) {
1209
- up.push(() => {
1210
- this.writer.writeLine(`await knex.raw(\`${definition.replace(/`/g, '\\`')}\`);`).blankLine();
1211
- });
1212
- }
1213
- }
1214
921
  }
1215
922
 
1216
923
  export const getMigrationDate = () => {
@@ -1,5 +1,3 @@
1
1
  // created from 'create-ts-index'
2
2
 
3
3
  export * from './generate';
4
- export * from './generate-functions';
5
- export * from './update-functions';
@@ -90,10 +90,7 @@ export type EntityFieldDefinition = FieldDefinitionBase &
90
90
  indent?: boolean;
91
91
  // If true the field is hidden in the admin interface
92
92
  hidden?: boolean;
93
- generateAs?: {
94
- expression: string;
95
- type: 'virtual' | 'stored' | 'expression';
96
- };
93
+ generateAs?: string;
97
94
 
98
95
  // Temporary fields for the generation of migrations
99
96
  deleted?: true;