@smartive/graphql-magic 23.6.1-next.1 → 23.6.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/.gqmrc.json +2 -1
- package/CHANGELOG.md +2 -2
- package/dist/bin/gqm.cjs +87 -85
- package/dist/cjs/index.cjs +95 -95
- package/dist/esm/db/generate.js +5 -5
- package/dist/esm/db/generate.js.map +1 -1
- package/dist/esm/migrations/generate.js +7 -11
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/migrations/index.d.ts +2 -1
- package/dist/esm/migrations/index.js +2 -1
- package/dist/esm/migrations/index.js.map +1 -1
- package/dist/esm/models/utils.d.ts +6 -7
- package/dist/esm/models/utils.js +5 -6
- package/dist/esm/models/utils.js.map +1 -1
- package/dist/esm/permissions/check.js +2 -2
- package/dist/esm/permissions/check.js.map +1 -1
- package/dist/esm/resolvers/mutations.js +6 -6
- package/dist/esm/resolvers/mutations.js.map +1 -1
- package/dist/esm/resolvers/resolvers.js +3 -9
- package/dist/esm/resolvers/resolvers.js.map +1 -1
- package/dist/esm/schema/generate.js +3 -9
- package/dist/esm/schema/generate.js.map +1 -1
- package/docker-compose.yml +2 -3
- package/package.json +1 -1
- package/src/db/generate.ts +5 -15
- package/src/migrations/generate.ts +6 -10
- package/src/migrations/index.ts +2 -1
- package/src/models/utils.ts +7 -8
- package/src/permissions/check.ts +2 -2
- package/src/resolvers/mutations.ts +6 -6
- package/src/resolvers/resolvers.ts +7 -13
- package/src/schema/generate.ts +28 -26
- package/tests/unit/generate-as.spec.ts +238 -0
- package/tests/utils/functions.ts +1 -0
package/.gqmrc.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
## [23.6.1
|
|
1
|
+
## [23.6.1](https://github.com/smartive/graphql-magic/compare/v23.6.0...v23.6.1) (2026-02-24)
|
|
2
2
|
|
|
3
3
|
### Bug Fixes
|
|
4
4
|
|
|
5
|
-
*
|
|
5
|
+
* correctly generate types for fields that are dynamic e.g. generateAs expression ([8a63cf1](https://github.com/smartive/graphql-magic/commit/8a63cf18a742b5b6530f582c20e8f802ef2cb354))
|
package/dist/bin/gqm.cjs
CHANGED
|
@@ -558,8 +558,8 @@ var getLabel = (s) => (0, import_startCase.default)((0, import_camelCase.default
|
|
|
558
558
|
var and = (...predicates) => (field) => predicates.every((predicate) => predicate(field));
|
|
559
559
|
var not = (predicate) => (field) => !predicate(field);
|
|
560
560
|
var isRootModel = (model) => !!model.root;
|
|
561
|
-
var isCreatableModel = (model) => model.creatable && model.fields.some(isCreatableField);
|
|
562
|
-
var isUpdatableModel = (model) => model.updatable && model.fields.some(isUpdatableField);
|
|
561
|
+
var isCreatableModel = (model) => !!model.creatable && model.fields.some(isCreatableField);
|
|
562
|
+
var isUpdatableModel = (model) => !!model.updatable && model.fields.some(isUpdatableField);
|
|
563
563
|
var isCreatableField = (field) => !field.inherited && !!field.creatable;
|
|
564
564
|
var isUpdatableField = (field) => !field.inherited && !!field.updatable;
|
|
565
565
|
var modelNeedsTable = (model) => model.fields.some((field) => !field.inherited);
|
|
@@ -568,9 +568,11 @@ var isInherited = (field) => !!field.inherited;
|
|
|
568
568
|
var isInTable = (field) => field.name === "id" || !field.inherited;
|
|
569
569
|
var isQueriableField = ({ queriable }) => queriable !== false;
|
|
570
570
|
var isCustomField = (field) => field.kind === "custom";
|
|
571
|
-
var
|
|
572
|
-
var isStoredInDatabase = (field) => field.generateAs?.type !== "expression";
|
|
571
|
+
var isDynamicField = (field) => !!field.generateAs || isCustomField(field);
|
|
572
|
+
var isStoredInDatabase = (field) => !isCustomField(field) && field.generateAs?.type !== "expression";
|
|
573
573
|
var isSimpleField = and(not(isRelation), not(isCustomField));
|
|
574
|
+
var isUpdatable = ({ updatable }) => !!updatable;
|
|
575
|
+
var isCreatable = ({ creatable }) => !!creatable;
|
|
574
576
|
var summonByName = (array, value2) => summonByKey(array, "name", value2);
|
|
575
577
|
var summonByKey = (array, key, value2) => summon(array, (element) => (0, import_get.default)(element, key) === value2, `No element found with ${key} ${value2}`);
|
|
576
578
|
var summon = (array, cb, errorMessage) => {
|
|
@@ -696,12 +698,12 @@ var generateDBModels = (models, dateLibrary) => {
|
|
|
696
698
|
for (const model of models.entities) {
|
|
697
699
|
const fields2 = model.relations.some((relation) => relation.field.foreignKey === "id") ? model.fields.filter((field) => field.name !== "id") : model.fields;
|
|
698
700
|
writer.write(`export type ${model.name} = `).inlineBlock(() => {
|
|
699
|
-
for (const field of fields2.filter(
|
|
701
|
+
for (const field of fields2.filter(isStoredInDatabase)) {
|
|
700
702
|
writer.write(`'${getColumnName(field)}': ${getFieldType(field, dateLibrary)}${field.nonNull ? "" : " | null"};`).newLine();
|
|
701
703
|
}
|
|
702
704
|
}).blankLine();
|
|
703
705
|
writer.write(`export type ${model.name}Initializer = `).inlineBlock(() => {
|
|
704
|
-
for (const field of fields2.filter(
|
|
706
|
+
for (const field of fields2.filter(and(isInTable, not(isDynamicField)))) {
|
|
705
707
|
writer.write(
|
|
706
708
|
`'${getColumnName(field)}'${field.nonNull && field.defaultValue === void 0 ? "" : "?"}: ${getFieldType(
|
|
707
709
|
field,
|
|
@@ -712,7 +714,7 @@ var generateDBModels = (models, dateLibrary) => {
|
|
|
712
714
|
}
|
|
713
715
|
}).blankLine();
|
|
714
716
|
writer.write(`export type ${model.name}Mutator = `).inlineBlock(() => {
|
|
715
|
-
for (const field of fields2.filter(
|
|
717
|
+
for (const field of fields2.filter(and(isInTable, not(isDynamicField)))) {
|
|
716
718
|
writer.write(
|
|
717
719
|
`'${getColumnName(field)}'?: ${getFieldType(field, dateLibrary, true)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
|
|
718
720
|
).newLine();
|
|
@@ -720,7 +722,7 @@ var generateDBModels = (models, dateLibrary) => {
|
|
|
720
722
|
}).blankLine();
|
|
721
723
|
if (!isRootModel(model)) {
|
|
722
724
|
writer.write(`export type ${model.name}Seed = `).inlineBlock(() => {
|
|
723
|
-
for (const field of fields2.filter(not(
|
|
725
|
+
for (const field of fields2.filter(not(isDynamicField))) {
|
|
724
726
|
if (model.parent && field.name === "type") {
|
|
725
727
|
continue;
|
|
726
728
|
}
|
|
@@ -781,6 +783,75 @@ var generateKnexTables = (models) => {
|
|
|
781
783
|
return writer.toString();
|
|
782
784
|
};
|
|
783
785
|
|
|
786
|
+
// src/migrations/generate-functions.ts
|
|
787
|
+
var generateFunctionsFromDatabase = async (knex2) => {
|
|
788
|
+
const regularFunctions = await knex2.raw(`
|
|
789
|
+
SELECT
|
|
790
|
+
pg_get_functiondef(p.oid) as definition
|
|
791
|
+
FROM pg_proc p
|
|
792
|
+
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
793
|
+
WHERE n.nspname = 'public'
|
|
794
|
+
AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
|
|
795
|
+
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
796
|
+
`);
|
|
797
|
+
const aggregateFunctions = await knex2.raw(`
|
|
798
|
+
SELECT
|
|
799
|
+
p.proname as name,
|
|
800
|
+
pg_get_function_identity_arguments(p.oid) as arguments,
|
|
801
|
+
a.aggtransfn::regproc::text as trans_func,
|
|
802
|
+
a.aggfinalfn::regproc::text as final_func,
|
|
803
|
+
a.agginitval as init_val,
|
|
804
|
+
pg_catalog.format_type(a.aggtranstype, NULL) as state_type
|
|
805
|
+
FROM pg_proc p
|
|
806
|
+
JOIN pg_aggregate a ON p.oid = a.aggfnoid
|
|
807
|
+
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
808
|
+
WHERE n.nspname = 'public'
|
|
809
|
+
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
810
|
+
`);
|
|
811
|
+
const functions = [];
|
|
812
|
+
for (const row of regularFunctions.rows || []) {
|
|
813
|
+
if (row.definition) {
|
|
814
|
+
functions.push(row.definition.trim());
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
for (const row of aggregateFunctions.rows || []) {
|
|
818
|
+
const name2 = row.name || "";
|
|
819
|
+
const argumentsStr = row.arguments || "";
|
|
820
|
+
const transFunc = row.trans_func || "";
|
|
821
|
+
const finalFunc = row.final_func || "";
|
|
822
|
+
const initVal = row.init_val;
|
|
823
|
+
const stateType = row.state_type || "";
|
|
824
|
+
if (!name2 || !transFunc || !stateType) {
|
|
825
|
+
continue;
|
|
826
|
+
}
|
|
827
|
+
let aggregateDef = `CREATE AGGREGATE ${name2}(${argumentsStr}) (
|
|
828
|
+
`;
|
|
829
|
+
aggregateDef += ` SFUNC = ${transFunc},
|
|
830
|
+
`;
|
|
831
|
+
aggregateDef += ` STYPE = ${stateType}`;
|
|
832
|
+
if (finalFunc) {
|
|
833
|
+
aggregateDef += `,
|
|
834
|
+
FINALFUNC = ${finalFunc}`;
|
|
835
|
+
}
|
|
836
|
+
if (initVal !== null && initVal !== void 0) {
|
|
837
|
+
const initValStr = typeof initVal === "string" ? `'${initVal}'` : String(initVal);
|
|
838
|
+
aggregateDef += `,
|
|
839
|
+
INITCOND = ${initValStr}`;
|
|
840
|
+
}
|
|
841
|
+
aggregateDef += "\n);";
|
|
842
|
+
functions.push(aggregateDef);
|
|
843
|
+
}
|
|
844
|
+
if (functions.length === 0) {
|
|
845
|
+
return `export const functions: string[] = [];
|
|
846
|
+
`;
|
|
847
|
+
}
|
|
848
|
+
const functionsArrayString = functions.map((func) => ` ${JSON.stringify(func)}`).join(",\n");
|
|
849
|
+
return `export const functions: string[] = [
|
|
850
|
+
${functionsArrayString},
|
|
851
|
+
];
|
|
852
|
+
`;
|
|
853
|
+
};
|
|
854
|
+
|
|
784
855
|
// src/migrations/generate.ts
|
|
785
856
|
var import_code_block_writer2 = __toESM(require("code-block-writer"), 1);
|
|
786
857
|
var import_knex_schema_inspector = require("knex-schema-inspector");
|
|
@@ -1215,7 +1286,7 @@ var MigrationGenerator = class {
|
|
|
1215
1286
|
writer.writeLine(`deleteRootType: row.deleteRootType,`);
|
|
1216
1287
|
writer.writeLine(`deleteRootId: row.deleteRootId,`);
|
|
1217
1288
|
}
|
|
1218
|
-
for (const { name: name2, kind } of model.fields.filter(isUpdatableField)
|
|
1289
|
+
for (const { name: name2, kind } of model.fields.filter(and(isUpdatableField, isStoredInDatabase))) {
|
|
1219
1290
|
const col = kind === "relation" ? `${name2}Id` : name2;
|
|
1220
1291
|
writer.writeLine(`${col}: row.${col},`);
|
|
1221
1292
|
}
|
|
@@ -1235,8 +1306,8 @@ var MigrationGenerator = class {
|
|
|
1235
1306
|
up,
|
|
1236
1307
|
down
|
|
1237
1308
|
);
|
|
1238
|
-
const missingRevisionFields = model.fields.filter(isUpdatableField)
|
|
1239
|
-
({ name: name2, ...field }) =>
|
|
1309
|
+
const missingRevisionFields = model.fields.filter(and(isUpdatableField, isStoredInDatabase)).filter(
|
|
1310
|
+
({ name: name2, ...field }) => !this.getColumn(revisionTable, field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
1240
1311
|
);
|
|
1241
1312
|
this.createRevisionFields(model, missingRevisionFields, up, down);
|
|
1242
1313
|
const revisionFieldsToRemove = model.fields.filter(
|
|
@@ -1394,7 +1465,7 @@ var MigrationGenerator = class {
|
|
|
1394
1465
|
});
|
|
1395
1466
|
});
|
|
1396
1467
|
if (isUpdatableModel(model)) {
|
|
1397
|
-
const updatableFields = fields2.filter(isUpdatableField)
|
|
1468
|
+
const updatableFields = fields2.filter(and(isUpdatableField, isStoredInDatabase));
|
|
1398
1469
|
if (!updatableFields.length) {
|
|
1399
1470
|
return;
|
|
1400
1471
|
}
|
|
@@ -1442,7 +1513,7 @@ var MigrationGenerator = class {
|
|
|
1442
1513
|
});
|
|
1443
1514
|
});
|
|
1444
1515
|
if (isUpdatableModel(model)) {
|
|
1445
|
-
const updatableFields = fields2.filter(isUpdatableField)
|
|
1516
|
+
const updatableFields = fields2.filter(and(isUpdatableField, isStoredInDatabase));
|
|
1446
1517
|
if (!updatableFields.length) {
|
|
1447
1518
|
return;
|
|
1448
1519
|
}
|
|
@@ -1480,7 +1551,7 @@ var MigrationGenerator = class {
|
|
|
1480
1551
|
writer.writeLine(`table.uuid('deleteRootId');`);
|
|
1481
1552
|
}
|
|
1482
1553
|
}
|
|
1483
|
-
for (const field of model.fields.filter(and(isUpdatableField, not(isInherited)))
|
|
1554
|
+
for (const field of model.fields.filter(and(isUpdatableField, not(isInherited), isStoredInDatabase))) {
|
|
1484
1555
|
this.column(field, { setUnique: false, setDefault: false });
|
|
1485
1556
|
}
|
|
1486
1557
|
});
|
|
@@ -1922,75 +1993,6 @@ var getMigrationDate = () => {
|
|
|
1922
1993
|
return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
|
1923
1994
|
};
|
|
1924
1995
|
|
|
1925
|
-
// src/migrations/generate-functions.ts
|
|
1926
|
-
var generateFunctionsFromDatabase = async (knex2) => {
|
|
1927
|
-
const regularFunctions = await knex2.raw(`
|
|
1928
|
-
SELECT
|
|
1929
|
-
pg_get_functiondef(p.oid) as definition
|
|
1930
|
-
FROM pg_proc p
|
|
1931
|
-
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
1932
|
-
WHERE n.nspname = 'public'
|
|
1933
|
-
AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
|
|
1934
|
-
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
1935
|
-
`);
|
|
1936
|
-
const aggregateFunctions = await knex2.raw(`
|
|
1937
|
-
SELECT
|
|
1938
|
-
p.proname as name,
|
|
1939
|
-
pg_get_function_identity_arguments(p.oid) as arguments,
|
|
1940
|
-
a.aggtransfn::regproc::text as trans_func,
|
|
1941
|
-
a.aggfinalfn::regproc::text as final_func,
|
|
1942
|
-
a.agginitval as init_val,
|
|
1943
|
-
pg_catalog.format_type(a.aggtranstype, NULL) as state_type
|
|
1944
|
-
FROM pg_proc p
|
|
1945
|
-
JOIN pg_aggregate a ON p.oid = a.aggfnoid
|
|
1946
|
-
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
1947
|
-
WHERE n.nspname = 'public'
|
|
1948
|
-
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
1949
|
-
`);
|
|
1950
|
-
const functions = [];
|
|
1951
|
-
for (const row of regularFunctions.rows || []) {
|
|
1952
|
-
if (row.definition) {
|
|
1953
|
-
functions.push(row.definition.trim());
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
for (const row of aggregateFunctions.rows || []) {
|
|
1957
|
-
const name2 = row.name || "";
|
|
1958
|
-
const argumentsStr = row.arguments || "";
|
|
1959
|
-
const transFunc = row.trans_func || "";
|
|
1960
|
-
const finalFunc = row.final_func || "";
|
|
1961
|
-
const initVal = row.init_val;
|
|
1962
|
-
const stateType = row.state_type || "";
|
|
1963
|
-
if (!name2 || !transFunc || !stateType) {
|
|
1964
|
-
continue;
|
|
1965
|
-
}
|
|
1966
|
-
let aggregateDef = `CREATE AGGREGATE ${name2}(${argumentsStr}) (
|
|
1967
|
-
`;
|
|
1968
|
-
aggregateDef += ` SFUNC = ${transFunc},
|
|
1969
|
-
`;
|
|
1970
|
-
aggregateDef += ` STYPE = ${stateType}`;
|
|
1971
|
-
if (finalFunc) {
|
|
1972
|
-
aggregateDef += `,
|
|
1973
|
-
FINALFUNC = ${finalFunc}`;
|
|
1974
|
-
}
|
|
1975
|
-
if (initVal !== null && initVal !== void 0) {
|
|
1976
|
-
const initValStr = typeof initVal === "string" ? `'${initVal}'` : String(initVal);
|
|
1977
|
-
aggregateDef += `,
|
|
1978
|
-
INITCOND = ${initValStr}`;
|
|
1979
|
-
}
|
|
1980
|
-
aggregateDef += "\n);";
|
|
1981
|
-
functions.push(aggregateDef);
|
|
1982
|
-
}
|
|
1983
|
-
if (functions.length === 0) {
|
|
1984
|
-
return `export const functions: string[] = [];
|
|
1985
|
-
`;
|
|
1986
|
-
}
|
|
1987
|
-
const functionsArrayString = functions.map((func) => ` ${JSON.stringify(func)}`).join(",\n");
|
|
1988
|
-
return `export const functions: string[] = [
|
|
1989
|
-
${functionsArrayString},
|
|
1990
|
-
];
|
|
1991
|
-
`;
|
|
1992
|
-
};
|
|
1993
|
-
|
|
1994
1996
|
// src/permissions/generate.ts
|
|
1995
1997
|
var ACTIONS = ["READ", "CREATE", "UPDATE", "DELETE", "RESTORE", "LINK"];
|
|
1996
1998
|
|
|
@@ -2255,7 +2257,7 @@ var generateDefinitions = ({
|
|
|
2255
2257
|
types.push(
|
|
2256
2258
|
input(
|
|
2257
2259
|
`Create${model.name}`,
|
|
2258
|
-
model.fields.filter((
|
|
2260
|
+
model.fields.filter(and(isCreatable, isStoredInDatabase)).map(
|
|
2259
2261
|
(field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID", nonNull: field.nonNull } : {
|
|
2260
2262
|
name: field.name,
|
|
2261
2263
|
type: field.kind === "json" ? `Create${field.type}` : field.type,
|
|
@@ -2270,7 +2272,7 @@ var generateDefinitions = ({
|
|
|
2270
2272
|
types.push(
|
|
2271
2273
|
input(
|
|
2272
2274
|
`Update${model.name}`,
|
|
2273
|
-
model.fields.filter((
|
|
2275
|
+
model.fields.filter(and(isUpdatable, isStoredInDatabase)).map(
|
|
2274
2276
|
(field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID" } : {
|
|
2275
2277
|
name: field.name,
|
|
2276
2278
|
type: field.kind === "json" ? `Update${field.type}` : field.type,
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -133,12 +133,12 @@ __export(index_exports, {
|
|
|
133
133
|
isCreatableField: () => isCreatableField,
|
|
134
134
|
isCreatableModel: () => isCreatableModel,
|
|
135
135
|
isCustomField: () => isCustomField,
|
|
136
|
+
isDynamicField: () => isDynamicField,
|
|
136
137
|
isEntityModel: () => isEntityModel,
|
|
137
138
|
isEnum: () => isEnum,
|
|
138
139
|
isEnumModel: () => isEnumModel,
|
|
139
140
|
isFieldNode: () => isFieldNode,
|
|
140
141
|
isFragmentSpreadNode: () => isFragmentSpreadNode,
|
|
141
|
-
isGenerateAsField: () => isGenerateAsField,
|
|
142
142
|
isInTable: () => isInTable,
|
|
143
143
|
isInherited: () => isInherited,
|
|
144
144
|
isInlineFragmentNode: () => isInlineFragmentNode,
|
|
@@ -833,8 +833,8 @@ var isScalarModel = (model) => model instanceof ScalarModel;
|
|
|
833
833
|
var isObjectModel = (model) => model instanceof ObjectModel;
|
|
834
834
|
var isInputModel = (model) => model instanceof InputModel;
|
|
835
835
|
var isInterfaceModel = (model) => model instanceof InterfaceModel;
|
|
836
|
-
var isCreatableModel = (model) => model.creatable && model.fields.some(isCreatableField);
|
|
837
|
-
var isUpdatableModel = (model) => model.updatable && model.fields.some(isUpdatableField);
|
|
836
|
+
var isCreatableModel = (model) => !!model.creatable && model.fields.some(isCreatableField);
|
|
837
|
+
var isUpdatableModel = (model) => !!model.updatable && model.fields.some(isUpdatableField);
|
|
838
838
|
var isCreatableField = (field) => !field.inherited && !!field.creatable;
|
|
839
839
|
var isUpdatableField = (field) => !field.inherited && !!field.updatable;
|
|
840
840
|
var modelNeedsTable = (model) => model.fields.some((field) => !field.inherited);
|
|
@@ -847,8 +847,8 @@ var isInTable = (field) => field.name === "id" || !field.inherited;
|
|
|
847
847
|
var isToOneRelation = (field) => isRelation(field) && !!field.toOne;
|
|
848
848
|
var isQueriableField = ({ queriable }) => queriable !== false;
|
|
849
849
|
var isCustomField = (field) => field.kind === "custom";
|
|
850
|
-
var
|
|
851
|
-
var isStoredInDatabase = (field) => field.generateAs?.type !== "expression";
|
|
850
|
+
var isDynamicField = (field) => !!field.generateAs || isCustomField(field);
|
|
851
|
+
var isStoredInDatabase = (field) => !isCustomField(field) && field.generateAs?.type !== "expression";
|
|
852
852
|
var isVisible = ({ hidden }) => hidden !== true;
|
|
853
853
|
var isSimpleField = and(not(isRelation), not(isCustomField));
|
|
854
854
|
var isUpdatable = ({ updatable }) => !!updatable;
|
|
@@ -1072,12 +1072,12 @@ var generateDBModels = (models, dateLibrary) => {
|
|
|
1072
1072
|
for (const model of models.entities) {
|
|
1073
1073
|
const fields2 = model.relations.some((relation) => relation.field.foreignKey === "id") ? model.fields.filter((field) => field.name !== "id") : model.fields;
|
|
1074
1074
|
writer.write(`export type ${model.name} = `).inlineBlock(() => {
|
|
1075
|
-
for (const field of fields2.filter(
|
|
1075
|
+
for (const field of fields2.filter(isStoredInDatabase)) {
|
|
1076
1076
|
writer.write(`'${getColumnName(field)}': ${getFieldType(field, dateLibrary)}${field.nonNull ? "" : " | null"};`).newLine();
|
|
1077
1077
|
}
|
|
1078
1078
|
}).blankLine();
|
|
1079
1079
|
writer.write(`export type ${model.name}Initializer = `).inlineBlock(() => {
|
|
1080
|
-
for (const field of fields2.filter(
|
|
1080
|
+
for (const field of fields2.filter(and(isInTable, not(isDynamicField)))) {
|
|
1081
1081
|
writer.write(
|
|
1082
1082
|
`'${getColumnName(field)}'${field.nonNull && field.defaultValue === void 0 ? "" : "?"}: ${getFieldType(
|
|
1083
1083
|
field,
|
|
@@ -1088,7 +1088,7 @@ var generateDBModels = (models, dateLibrary) => {
|
|
|
1088
1088
|
}
|
|
1089
1089
|
}).blankLine();
|
|
1090
1090
|
writer.write(`export type ${model.name}Mutator = `).inlineBlock(() => {
|
|
1091
|
-
for (const field of fields2.filter(
|
|
1091
|
+
for (const field of fields2.filter(and(isInTable, not(isDynamicField)))) {
|
|
1092
1092
|
writer.write(
|
|
1093
1093
|
`'${getColumnName(field)}'?: ${getFieldType(field, dateLibrary, true)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
|
|
1094
1094
|
).newLine();
|
|
@@ -1096,7 +1096,7 @@ var generateDBModels = (models, dateLibrary) => {
|
|
|
1096
1096
|
}).blankLine();
|
|
1097
1097
|
if (!isRootModel(model)) {
|
|
1098
1098
|
writer.write(`export type ${model.name}Seed = `).inlineBlock(() => {
|
|
1099
|
-
for (const field of fields2.filter(not(
|
|
1099
|
+
for (const field of fields2.filter(not(isDynamicField))) {
|
|
1100
1100
|
if (model.parent && field.name === "type") {
|
|
1101
1101
|
continue;
|
|
1102
1102
|
}
|
|
@@ -1157,6 +1157,75 @@ var generateKnexTables = (models) => {
|
|
|
1157
1157
|
return writer.toString();
|
|
1158
1158
|
};
|
|
1159
1159
|
|
|
1160
|
+
// src/migrations/generate-functions.ts
|
|
1161
|
+
var generateFunctionsFromDatabase = async (knex) => {
|
|
1162
|
+
const regularFunctions = await knex.raw(`
|
|
1163
|
+
SELECT
|
|
1164
|
+
pg_get_functiondef(p.oid) as definition
|
|
1165
|
+
FROM pg_proc p
|
|
1166
|
+
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
1167
|
+
WHERE n.nspname = 'public'
|
|
1168
|
+
AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
|
|
1169
|
+
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
1170
|
+
`);
|
|
1171
|
+
const aggregateFunctions = await knex.raw(`
|
|
1172
|
+
SELECT
|
|
1173
|
+
p.proname as name,
|
|
1174
|
+
pg_get_function_identity_arguments(p.oid) as arguments,
|
|
1175
|
+
a.aggtransfn::regproc::text as trans_func,
|
|
1176
|
+
a.aggfinalfn::regproc::text as final_func,
|
|
1177
|
+
a.agginitval as init_val,
|
|
1178
|
+
pg_catalog.format_type(a.aggtranstype, NULL) as state_type
|
|
1179
|
+
FROM pg_proc p
|
|
1180
|
+
JOIN pg_aggregate a ON p.oid = a.aggfnoid
|
|
1181
|
+
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
1182
|
+
WHERE n.nspname = 'public'
|
|
1183
|
+
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
1184
|
+
`);
|
|
1185
|
+
const functions = [];
|
|
1186
|
+
for (const row of regularFunctions.rows || []) {
|
|
1187
|
+
if (row.definition) {
|
|
1188
|
+
functions.push(row.definition.trim());
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
for (const row of aggregateFunctions.rows || []) {
|
|
1192
|
+
const name2 = row.name || "";
|
|
1193
|
+
const argumentsStr = row.arguments || "";
|
|
1194
|
+
const transFunc = row.trans_func || "";
|
|
1195
|
+
const finalFunc = row.final_func || "";
|
|
1196
|
+
const initVal = row.init_val;
|
|
1197
|
+
const stateType = row.state_type || "";
|
|
1198
|
+
if (!name2 || !transFunc || !stateType) {
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
let aggregateDef = `CREATE AGGREGATE ${name2}(${argumentsStr}) (
|
|
1202
|
+
`;
|
|
1203
|
+
aggregateDef += ` SFUNC = ${transFunc},
|
|
1204
|
+
`;
|
|
1205
|
+
aggregateDef += ` STYPE = ${stateType}`;
|
|
1206
|
+
if (finalFunc) {
|
|
1207
|
+
aggregateDef += `,
|
|
1208
|
+
FINALFUNC = ${finalFunc}`;
|
|
1209
|
+
}
|
|
1210
|
+
if (initVal !== null && initVal !== void 0) {
|
|
1211
|
+
const initValStr = typeof initVal === "string" ? `'${initVal}'` : String(initVal);
|
|
1212
|
+
aggregateDef += `,
|
|
1213
|
+
INITCOND = ${initValStr}`;
|
|
1214
|
+
}
|
|
1215
|
+
aggregateDef += "\n);";
|
|
1216
|
+
functions.push(aggregateDef);
|
|
1217
|
+
}
|
|
1218
|
+
if (functions.length === 0) {
|
|
1219
|
+
return `export const functions: string[] = [];
|
|
1220
|
+
`;
|
|
1221
|
+
}
|
|
1222
|
+
const functionsArrayString = functions.map((func) => ` ${JSON.stringify(func)}`).join(",\n");
|
|
1223
|
+
return `export const functions: string[] = [
|
|
1224
|
+
${functionsArrayString},
|
|
1225
|
+
];
|
|
1226
|
+
`;
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1160
1229
|
// src/migrations/generate.ts
|
|
1161
1230
|
var import_code_block_writer2 = __toESM(require("code-block-writer"), 1);
|
|
1162
1231
|
var import_knex_schema_inspector = require("knex-schema-inspector");
|
|
@@ -1790,7 +1859,7 @@ var checkCanWrite = async (ctx, model, data, action) => {
|
|
|
1790
1859
|
}
|
|
1791
1860
|
const query = ctx.knex.first();
|
|
1792
1861
|
let linked = false;
|
|
1793
|
-
for (const field of model.fields.filter(
|
|
1862
|
+
for (const field of model.fields.filter(isStoredInDatabase).filter((field2) => field2.generated || (action === "CREATE" ? field2.creatable : field2.updatable))) {
|
|
1794
1863
|
const fieldPermissions = field[action === "CREATE" ? "creatable" : "updatable"];
|
|
1795
1864
|
const role2 = getRole(ctx);
|
|
1796
1865
|
if (getColumnName(field) in data && fieldPermissions && typeof fieldPermissions === "object" && !fieldPermissions.roles?.includes(role2)) {
|
|
@@ -2302,7 +2371,7 @@ var createEntity = async (modelName, input2, ctx, trigger = "direct-call") => wi
|
|
|
2302
2371
|
if (model.parent) {
|
|
2303
2372
|
const rootInput = {};
|
|
2304
2373
|
const childInput = { id };
|
|
2305
|
-
for (const field of model.fields.filter(not(
|
|
2374
|
+
for (const field of model.fields.filter(not(isDynamicField))) {
|
|
2306
2375
|
const columnName = field.kind === "relation" ? `${field.name}Id` : field.name;
|
|
2307
2376
|
if (columnName in normalizedInput) {
|
|
2308
2377
|
if (field.inherited) {
|
|
@@ -2316,7 +2385,7 @@ var createEntity = async (modelName, input2, ctx, trigger = "direct-call") => wi
|
|
|
2316
2385
|
await ctx2.knex(model.name).insert(childInput);
|
|
2317
2386
|
} else {
|
|
2318
2387
|
const insertData = { ...normalizedInput };
|
|
2319
|
-
for (const field of model.fields.filter(
|
|
2388
|
+
for (const field of model.fields.filter(isDynamicField)) {
|
|
2320
2389
|
const columnName = field.kind === "relation" ? `${field.name}Id` : field.name;
|
|
2321
2390
|
delete insertData[columnName];
|
|
2322
2391
|
}
|
|
@@ -2682,7 +2751,7 @@ var createRevision = async (model, data, ctx) => {
|
|
|
2682
2751
|
rootRevisionData.deleted = data.deleted || false;
|
|
2683
2752
|
}
|
|
2684
2753
|
const childRevisionData = { id: revisionId };
|
|
2685
|
-
for (const field of model.fields.filter((
|
|
2754
|
+
for (const field of model.fields.filter(and(isUpdatableField, not(isDynamicField)))) {
|
|
2686
2755
|
const col = field.kind === "relation" ? `${field.name}Id` : field.name;
|
|
2687
2756
|
let value2;
|
|
2688
2757
|
if (field.nonNull && (!(col in data) || col === void 0 || col === null)) {
|
|
@@ -2746,7 +2815,7 @@ var doUpdate = async (model, currentEntity, update, ctx) => {
|
|
|
2746
2815
|
if (model.parent) {
|
|
2747
2816
|
const rootInput = {};
|
|
2748
2817
|
const childInput = {};
|
|
2749
|
-
for (const field of model.fields.filter(not(
|
|
2818
|
+
for (const field of model.fields.filter(not(isDynamicField))) {
|
|
2750
2819
|
const columnName = field.kind === "relation" ? `${field.name}Id` : field.name;
|
|
2751
2820
|
if (columnName in update) {
|
|
2752
2821
|
if (field.inherited) {
|
|
@@ -2764,7 +2833,7 @@ var doUpdate = async (model, currentEntity, update, ctx) => {
|
|
|
2764
2833
|
}
|
|
2765
2834
|
} else {
|
|
2766
2835
|
const updateData = { ...update };
|
|
2767
|
-
for (const field of model.fields.filter(
|
|
2836
|
+
for (const field of model.fields.filter(isDynamicField)) {
|
|
2768
2837
|
const columnName = field.kind === "relation" ? `${field.name}Id` : field.name;
|
|
2769
2838
|
delete updateData[columnName];
|
|
2770
2839
|
}
|
|
@@ -2792,10 +2861,10 @@ var getResolvers = (models) => {
|
|
|
2792
2861
|
])
|
|
2793
2862
|
};
|
|
2794
2863
|
const mutations = [
|
|
2795
|
-
...models.entities.filter(not(isRootModel)
|
|
2864
|
+
...models.entities.filter(and(not(isRootModel), isCreatable)).map((model) => ({
|
|
2796
2865
|
[`create${model.name}`]: mutationResolver
|
|
2797
2866
|
})),
|
|
2798
|
-
...models.entities.filter(not(isRootModel)
|
|
2867
|
+
...models.entities.filter(and(not(isRootModel), isUpdatable)).map((model) => ({
|
|
2799
2868
|
[`update${model.name}`]: mutationResolver
|
|
2800
2869
|
})),
|
|
2801
2870
|
...models.entities.filter(not(isRootModel)).filter(({ deletable }) => deletable).map((model) => ({
|
|
@@ -3231,7 +3300,7 @@ var MigrationGenerator = class {
|
|
|
3231
3300
|
writer.writeLine(`deleteRootType: row.deleteRootType,`);
|
|
3232
3301
|
writer.writeLine(`deleteRootId: row.deleteRootId,`);
|
|
3233
3302
|
}
|
|
3234
|
-
for (const { name: name2, kind } of model.fields.filter(isUpdatableField)
|
|
3303
|
+
for (const { name: name2, kind } of model.fields.filter(and(isUpdatableField, isStoredInDatabase))) {
|
|
3235
3304
|
const col = kind === "relation" ? `${name2}Id` : name2;
|
|
3236
3305
|
writer.writeLine(`${col}: row.${col},`);
|
|
3237
3306
|
}
|
|
@@ -3251,8 +3320,8 @@ var MigrationGenerator = class {
|
|
|
3251
3320
|
up,
|
|
3252
3321
|
down
|
|
3253
3322
|
);
|
|
3254
|
-
const missingRevisionFields = model.fields.filter(isUpdatableField)
|
|
3255
|
-
({ name: name2, ...field }) =>
|
|
3323
|
+
const missingRevisionFields = model.fields.filter(and(isUpdatableField, isStoredInDatabase)).filter(
|
|
3324
|
+
({ name: name2, ...field }) => !this.getColumn(revisionTable, field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
|
|
3256
3325
|
);
|
|
3257
3326
|
this.createRevisionFields(model, missingRevisionFields, up, down);
|
|
3258
3327
|
const revisionFieldsToRemove = model.fields.filter(
|
|
@@ -3410,7 +3479,7 @@ var MigrationGenerator = class {
|
|
|
3410
3479
|
});
|
|
3411
3480
|
});
|
|
3412
3481
|
if (isUpdatableModel(model)) {
|
|
3413
|
-
const updatableFields = fields2.filter(isUpdatableField)
|
|
3482
|
+
const updatableFields = fields2.filter(and(isUpdatableField, isStoredInDatabase));
|
|
3414
3483
|
if (!updatableFields.length) {
|
|
3415
3484
|
return;
|
|
3416
3485
|
}
|
|
@@ -3458,7 +3527,7 @@ var MigrationGenerator = class {
|
|
|
3458
3527
|
});
|
|
3459
3528
|
});
|
|
3460
3529
|
if (isUpdatableModel(model)) {
|
|
3461
|
-
const updatableFields = fields2.filter(isUpdatableField)
|
|
3530
|
+
const updatableFields = fields2.filter(and(isUpdatableField, isStoredInDatabase));
|
|
3462
3531
|
if (!updatableFields.length) {
|
|
3463
3532
|
return;
|
|
3464
3533
|
}
|
|
@@ -3496,7 +3565,7 @@ var MigrationGenerator = class {
|
|
|
3496
3565
|
writer.writeLine(`table.uuid('deleteRootId');`);
|
|
3497
3566
|
}
|
|
3498
3567
|
}
|
|
3499
|
-
for (const field of model.fields.filter(and(isUpdatableField, not(isInherited)))
|
|
3568
|
+
for (const field of model.fields.filter(and(isUpdatableField, not(isInherited), isStoredInDatabase))) {
|
|
3500
3569
|
this.column(field, { setUnique: false, setDefault: false });
|
|
3501
3570
|
}
|
|
3502
3571
|
});
|
|
@@ -3938,75 +4007,6 @@ var getMigrationDate = () => {
|
|
|
3938
4007
|
return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
|
3939
4008
|
};
|
|
3940
4009
|
|
|
3941
|
-
// src/migrations/generate-functions.ts
|
|
3942
|
-
var generateFunctionsFromDatabase = async (knex) => {
|
|
3943
|
-
const regularFunctions = await knex.raw(`
|
|
3944
|
-
SELECT
|
|
3945
|
-
pg_get_functiondef(p.oid) as definition
|
|
3946
|
-
FROM pg_proc p
|
|
3947
|
-
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
3948
|
-
WHERE n.nspname = 'public'
|
|
3949
|
-
AND NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid)
|
|
3950
|
-
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
3951
|
-
`);
|
|
3952
|
-
const aggregateFunctions = await knex.raw(`
|
|
3953
|
-
SELECT
|
|
3954
|
-
p.proname as name,
|
|
3955
|
-
pg_get_function_identity_arguments(p.oid) as arguments,
|
|
3956
|
-
a.aggtransfn::regproc::text as trans_func,
|
|
3957
|
-
a.aggfinalfn::regproc::text as final_func,
|
|
3958
|
-
a.agginitval as init_val,
|
|
3959
|
-
pg_catalog.format_type(a.aggtranstype, NULL) as state_type
|
|
3960
|
-
FROM pg_proc p
|
|
3961
|
-
JOIN pg_aggregate a ON p.oid = a.aggfnoid
|
|
3962
|
-
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
3963
|
-
WHERE n.nspname = 'public'
|
|
3964
|
-
ORDER BY p.proname, pg_get_function_identity_arguments(p.oid)
|
|
3965
|
-
`);
|
|
3966
|
-
const functions = [];
|
|
3967
|
-
for (const row of regularFunctions.rows || []) {
|
|
3968
|
-
if (row.definition) {
|
|
3969
|
-
functions.push(row.definition.trim());
|
|
3970
|
-
}
|
|
3971
|
-
}
|
|
3972
|
-
for (const row of aggregateFunctions.rows || []) {
|
|
3973
|
-
const name2 = row.name || "";
|
|
3974
|
-
const argumentsStr = row.arguments || "";
|
|
3975
|
-
const transFunc = row.trans_func || "";
|
|
3976
|
-
const finalFunc = row.final_func || "";
|
|
3977
|
-
const initVal = row.init_val;
|
|
3978
|
-
const stateType = row.state_type || "";
|
|
3979
|
-
if (!name2 || !transFunc || !stateType) {
|
|
3980
|
-
continue;
|
|
3981
|
-
}
|
|
3982
|
-
let aggregateDef = `CREATE AGGREGATE ${name2}(${argumentsStr}) (
|
|
3983
|
-
`;
|
|
3984
|
-
aggregateDef += ` SFUNC = ${transFunc},
|
|
3985
|
-
`;
|
|
3986
|
-
aggregateDef += ` STYPE = ${stateType}`;
|
|
3987
|
-
if (finalFunc) {
|
|
3988
|
-
aggregateDef += `,
|
|
3989
|
-
FINALFUNC = ${finalFunc}`;
|
|
3990
|
-
}
|
|
3991
|
-
if (initVal !== null && initVal !== void 0) {
|
|
3992
|
-
const initValStr = typeof initVal === "string" ? `'${initVal}'` : String(initVal);
|
|
3993
|
-
aggregateDef += `,
|
|
3994
|
-
INITCOND = ${initValStr}`;
|
|
3995
|
-
}
|
|
3996
|
-
aggregateDef += "\n);";
|
|
3997
|
-
functions.push(aggregateDef);
|
|
3998
|
-
}
|
|
3999
|
-
if (functions.length === 0) {
|
|
4000
|
-
return `export const functions: string[] = [];
|
|
4001
|
-
`;
|
|
4002
|
-
}
|
|
4003
|
-
const functionsArrayString = functions.map((func) => ` ${JSON.stringify(func)}`).join(",\n");
|
|
4004
|
-
return `export const functions: string[] = [
|
|
4005
|
-
${functionsArrayString},
|
|
4006
|
-
];
|
|
4007
|
-
`;
|
|
4008
|
-
};
|
|
4009
|
-
|
|
4010
4010
|
// src/permissions/generate.ts
|
|
4011
4011
|
var ACTIONS = ["READ", "CREATE", "UPDATE", "DELETE", "RESTORE", "LINK"];
|
|
4012
4012
|
var generatePermissions = (models, config) => {
|
|
@@ -4364,7 +4364,7 @@ var generateDefinitions = ({
|
|
|
4364
4364
|
types.push(
|
|
4365
4365
|
input(
|
|
4366
4366
|
`Create${model.name}`,
|
|
4367
|
-
model.fields.filter((
|
|
4367
|
+
model.fields.filter(and(isCreatable, isStoredInDatabase)).map(
|
|
4368
4368
|
(field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID", nonNull: field.nonNull } : {
|
|
4369
4369
|
name: field.name,
|
|
4370
4370
|
type: field.kind === "json" ? `Create${field.type}` : field.type,
|
|
@@ -4379,7 +4379,7 @@ var generateDefinitions = ({
|
|
|
4379
4379
|
types.push(
|
|
4380
4380
|
input(
|
|
4381
4381
|
`Update${model.name}`,
|
|
4382
|
-
model.fields.filter((
|
|
4382
|
+
model.fields.filter(and(isUpdatable, isStoredInDatabase)).map(
|
|
4383
4383
|
(field) => field.kind === "relation" ? { name: `${field.name}Id`, type: "ID" } : {
|
|
4384
4384
|
name: field.name,
|
|
4385
4385
|
type: field.kind === "json" ? `Update${field.type}` : field.type,
|
|
@@ -4631,12 +4631,12 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql6.buildAST
|
|
|
4631
4631
|
isCreatableField,
|
|
4632
4632
|
isCreatableModel,
|
|
4633
4633
|
isCustomField,
|
|
4634
|
+
isDynamicField,
|
|
4634
4635
|
isEntityModel,
|
|
4635
4636
|
isEnum,
|
|
4636
4637
|
isEnumModel,
|
|
4637
4638
|
isFieldNode,
|
|
4638
4639
|
isFragmentSpreadNode,
|
|
4639
|
-
isGenerateAsField,
|
|
4640
4640
|
isInTable,
|
|
4641
4641
|
isInherited,
|
|
4642
4642
|
isInlineFragmentNode,
|