@smartive/graphql-magic 9.1.2 → 10.0.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.
Files changed (120) hide show
  1. package/.eslintrc +2 -10
  2. package/.github/workflows/release.yml +1 -1
  3. package/.gqmrc.json +6 -0
  4. package/CHANGELOG.md +2 -2
  5. package/README.md +1 -1
  6. package/dist/bin/gqm.cjs +684 -330
  7. package/dist/cjs/index.cjs +998 -554
  8. package/dist/esm/api/execute.js +1 -1
  9. package/dist/esm/api/execute.js.map +1 -1
  10. package/dist/esm/client/mutations.d.ts +2 -2
  11. package/dist/esm/client/mutations.js +5 -4
  12. package/dist/esm/client/mutations.js.map +1 -1
  13. package/dist/esm/client/queries.d.ts +12 -17
  14. package/dist/esm/client/queries.js +30 -50
  15. package/dist/esm/client/queries.js.map +1 -1
  16. package/dist/esm/context.d.ts +1 -2
  17. package/dist/esm/db/generate.d.ts +3 -3
  18. package/dist/esm/db/generate.js +31 -29
  19. package/dist/esm/db/generate.js.map +1 -1
  20. package/dist/esm/migrations/generate.d.ts +3 -4
  21. package/dist/esm/migrations/generate.js +114 -107
  22. package/dist/esm/migrations/generate.js.map +1 -1
  23. package/dist/esm/models/index.d.ts +1 -0
  24. package/dist/esm/models/index.js +1 -0
  25. package/dist/esm/models/index.js.map +1 -1
  26. package/dist/esm/models/model-definitions.d.ts +189 -0
  27. package/dist/esm/models/model-definitions.js +2 -0
  28. package/dist/esm/models/model-definitions.js.map +1 -0
  29. package/dist/esm/models/models.d.ts +128 -174
  30. package/dist/esm/models/models.js +411 -1
  31. package/dist/esm/models/models.js.map +1 -1
  32. package/dist/esm/models/mutation-hook.d.ts +2 -2
  33. package/dist/esm/models/utils.d.ts +35 -497
  34. package/dist/esm/models/utils.js +21 -144
  35. package/dist/esm/models/utils.js.map +1 -1
  36. package/dist/esm/permissions/check.d.ts +3 -3
  37. package/dist/esm/permissions/check.js +14 -7
  38. package/dist/esm/permissions/check.js.map +1 -1
  39. package/dist/esm/permissions/generate.js +6 -6
  40. package/dist/esm/permissions/generate.js.map +1 -1
  41. package/dist/esm/resolvers/filters.d.ts +8 -0
  42. package/dist/esm/resolvers/filters.js +28 -25
  43. package/dist/esm/resolvers/filters.js.map +1 -1
  44. package/dist/esm/resolvers/index.d.ts +1 -0
  45. package/dist/esm/resolvers/index.js +1 -0
  46. package/dist/esm/resolvers/index.js.map +1 -1
  47. package/dist/esm/resolvers/mutations.js +85 -21
  48. package/dist/esm/resolvers/mutations.js.map +1 -1
  49. package/dist/esm/resolvers/node.d.ts +13 -15
  50. package/dist/esm/resolvers/node.js +41 -36
  51. package/dist/esm/resolvers/node.js.map +1 -1
  52. package/dist/esm/resolvers/resolver.js +19 -49
  53. package/dist/esm/resolvers/resolver.js.map +1 -1
  54. package/dist/esm/resolvers/resolvers.d.ts +1 -8
  55. package/dist/esm/resolvers/resolvers.js +15 -7
  56. package/dist/esm/resolvers/resolvers.js.map +1 -1
  57. package/dist/esm/resolvers/selects.d.ts +3 -0
  58. package/dist/esm/resolvers/selects.js +50 -0
  59. package/dist/esm/resolvers/selects.js.map +1 -0
  60. package/dist/esm/resolvers/utils.d.ts +12 -4
  61. package/dist/esm/resolvers/utils.js +30 -22
  62. package/dist/esm/resolvers/utils.js.map +1 -1
  63. package/dist/esm/schema/generate.d.ts +4 -4
  64. package/dist/esm/schema/generate.js +122 -131
  65. package/dist/esm/schema/generate.js.map +1 -1
  66. package/dist/esm/schema/utils.d.ts +1 -1
  67. package/dist/esm/schema/utils.js +2 -1
  68. package/dist/esm/schema/utils.js.map +1 -1
  69. package/knexfile.ts +31 -0
  70. package/migrations/20230912185644_setup.ts +127 -0
  71. package/package.json +16 -14
  72. package/src/api/execute.ts +1 -1
  73. package/src/bin/gqm/gqm.ts +25 -23
  74. package/src/bin/gqm/parse-models.ts +5 -5
  75. package/src/bin/gqm/settings.ts +13 -4
  76. package/src/bin/gqm/static-eval.ts +5 -0
  77. package/src/bin/gqm/templates.ts +23 -3
  78. package/src/client/mutations.ts +11 -5
  79. package/src/client/queries.ts +43 -80
  80. package/src/context.ts +1 -2
  81. package/src/db/generate.ts +41 -41
  82. package/src/migrations/generate.ts +165 -146
  83. package/src/models/index.ts +1 -0
  84. package/src/models/model-definitions.ts +168 -0
  85. package/src/models/models.ts +510 -166
  86. package/src/models/mutation-hook.ts +2 -2
  87. package/src/models/utils.ts +53 -187
  88. package/src/permissions/check.ts +19 -11
  89. package/src/permissions/generate.ts +6 -6
  90. package/src/resolvers/filters.ts +44 -28
  91. package/src/resolvers/index.ts +1 -0
  92. package/src/resolvers/mutations.ts +98 -36
  93. package/src/resolvers/node.ts +79 -51
  94. package/src/resolvers/resolver.ts +20 -74
  95. package/src/resolvers/resolvers.ts +18 -7
  96. package/src/resolvers/selects.ts +77 -0
  97. package/src/resolvers/utils.ts +41 -25
  98. package/src/schema/generate.ts +106 -127
  99. package/src/schema/utils.ts +2 -1
  100. package/tests/api/__snapshots__/inheritance.spec.ts.snap +83 -0
  101. package/tests/api/inheritance.spec.ts +130 -0
  102. package/tests/generated/api/index.ts +1174 -0
  103. package/tests/generated/client/index.ts +1163 -0
  104. package/tests/generated/client/mutations.ts +109 -0
  105. package/tests/generated/db/index.ts +291 -0
  106. package/tests/generated/db/knex.ts +14 -0
  107. package/tests/generated/models.json +675 -0
  108. package/tests/generated/schema.graphql +325 -0
  109. package/tests/unit/__snapshots__/resolve.spec.ts.snap +23 -0
  110. package/tests/unit/queries.spec.ts +5 -5
  111. package/tests/unit/resolve.spec.ts +8 -8
  112. package/tests/utils/database/knex.ts +5 -13
  113. package/tests/utils/database/seed.ts +57 -18
  114. package/tests/utils/models.ts +62 -7
  115. package/tests/utils/server.ts +5 -5
  116. package/tsconfig.eslint.json +1 -0
  117. package/tests/unit/__snapshots__/generate.spec.ts.snap +0 -128
  118. package/tests/unit/generate.spec.ts +0 -8
  119. package/tests/utils/database/schema.ts +0 -64
  120. package/tests/utils/generate-migration.ts +0 -24
@@ -30,13 +30,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  var src_exports = {};
31
31
  __export(src_exports, {
32
32
  AliasGenerator: () => AliasGenerator,
33
+ EntityModel: () => EntityModel,
34
+ EnumModel: () => EnumModel,
33
35
  ForbiddenError: () => ForbiddenError,
34
36
  GraphQLError: () => GraphQLError,
35
37
  ID_ALIAS: () => ID_ALIAS,
38
+ InputModel: () => InputModel,
39
+ InterfaceModel: () => InterfaceModel,
40
+ ManyToManyRelation: () => ManyToManyRelation,
36
41
  MigrationGenerator: () => MigrationGenerator,
42
+ Model: () => Model,
43
+ Models: () => Models,
44
+ NormalRelation: () => NormalRelation,
37
45
  NotFoundError: () => NotFoundError,
46
+ ObjectModel: () => ObjectModel,
38
47
  PermissionError: () => PermissionError,
48
+ RawEnumModel: () => RawEnumModel,
49
+ Relation: () => Relation,
50
+ ReverseRelation: () => ReverseRelation,
39
51
  SPECIAL_FILTERS: () => SPECIAL_FILTERS,
52
+ ScalarModel: () => ScalarModel,
53
+ TYPE_ALIAS: () => TYPE_ALIAS,
40
54
  UserInputError: () => UserInputError,
41
55
  actionableRelations: () => actionableRelations,
42
56
  addJoin: () => addJoin,
@@ -45,6 +59,7 @@ __export(src_exports, {
45
59
  applyFilters: () => applyFilters,
46
60
  applyJoins: () => applyJoins,
47
61
  applyPermissions: () => applyPermissions,
62
+ applySelects: () => applySelects,
48
63
  args: () => args,
49
64
  checkCanWrite: () => checkCanWrite,
50
65
  directive: () => directive,
@@ -62,6 +77,8 @@ __export(src_exports, {
62
77
  generateMutations: () => generateMutations,
63
78
  generatePermissions: () => generatePermissions,
64
79
  get: () => get,
80
+ getColumn: () => getColumn,
81
+ getColumnName: () => getColumnName,
65
82
  getEditEntityRelationsQuery: () => getEditEntityRelationsQuery,
66
83
  getEntityListQuery: () => getEntityListQuery,
67
84
  getEntityQuery: () => getEntityQuery,
@@ -72,16 +89,8 @@ __export(src_exports, {
72
89
  getInlineFragments: () => getInlineFragments,
73
90
  getJoins: () => getJoins,
74
91
  getLabel: () => getLabel,
75
- getManyToManyRelation: () => getManyToManyRelation,
76
- getManyToManyRelations: () => getManyToManyRelations,
77
92
  getManyToManyRelationsQuery: () => getManyToManyRelationsQuery,
78
93
  getMigrationDate: () => getMigrationDate,
79
- getModelLabel: () => getModelLabel,
80
- getModelLabelPlural: () => getModelLabelPlural,
81
- getModelPlural: () => getModelPlural,
82
- getModelPluralField: () => getModelPluralField,
83
- getModelSlug: () => getModelSlug,
84
- getModels: () => getModels,
85
94
  getMutationQuery: () => getMutationQuery,
86
95
  getNameOrAlias: () => getNameOrAlias,
87
96
  getPermissionStack: () => getPermissionStack,
@@ -94,6 +103,7 @@ __export(src_exports, {
94
103
  getTypeName: () => getTypeName,
95
104
  getUpdateEntityQuery: () => getUpdateEntityQuery,
96
105
  gql: () => gql,
106
+ hasName: () => hasName,
97
107
  hash: () => hash,
98
108
  hydrate: () => hydrate,
99
109
  iface: () => iface,
@@ -105,12 +115,14 @@ __export(src_exports, {
105
115
  isCustomField: () => isCustomField,
106
116
  isEntityModel: () => isEntityModel,
107
117
  isEnum: () => isEnum,
108
- isEnumList: () => isEnumList,
109
118
  isEnumModel: () => isEnumModel,
110
119
  isFieldNode: () => isFieldNode,
111
120
  isFragmentSpreadNode: () => isFragmentSpreadNode,
121
+ isInTable: () => isInTable,
122
+ isInherited: () => isInherited,
112
123
  isInlineFragmentNode: () => isInlineFragmentNode,
113
124
  isInputModel: () => isInputModel,
125
+ isInterfaceModel: () => isInterfaceModel,
114
126
  isListType: () => isListType,
115
127
  isObjectModel: () => isObjectModel,
116
128
  isPrimitive: () => isPrimitive,
@@ -118,16 +130,20 @@ __export(src_exports, {
118
130
  isQueriableField: () => isQueriableField,
119
131
  isRawEnumModel: () => isRawEnumModel,
120
132
  isRelation: () => isRelation,
133
+ isRootModel: () => isRootModel,
121
134
  isScalarModel: () => isScalarModel,
122
135
  isSimpleField: () => isSimpleField,
123
136
  isToOneRelation: () => isToOneRelation,
124
137
  isUpdatable: () => isUpdatable,
125
138
  isUpdatableBy: () => isUpdatableBy,
139
+ isUpdatableField: () => isUpdatableField,
140
+ isUpdatableModel: () => isUpdatableModel,
126
141
  isVisible: () => isVisible,
127
142
  isVisibleRelation: () => isVisibleRelation,
128
143
  it: () => it,
129
144
  list: () => list,
130
145
  merge: () => merge2,
146
+ modelNeedsTable: () => modelNeedsTable,
131
147
  mutationResolver: () => mutationResolver,
132
148
  name: () => name,
133
149
  namedType: () => namedType,
@@ -137,6 +153,7 @@ __export(src_exports, {
137
153
  normalizeValueByTypeDefinition: () => normalizeValueByTypeDefinition,
138
154
  not: () => not,
139
155
  object: () => object,
156
+ or: () => or,
140
157
  ors: () => ors,
141
158
  printSchema: () => printSchema,
142
159
  printSchemaFromDocument: () => printSchemaFromDocument,
@@ -163,7 +180,7 @@ var execute = async ({
163
180
  body,
164
181
  ...ctx
165
182
  }) => {
166
- const document2 = generate(ctx.rawModels);
183
+ const document2 = generate(ctx.models);
167
184
  const generatedResolvers = getResolvers(ctx.models);
168
185
  const schema = (0, import_schema.makeExecutableSchema)({
169
186
  typeDefs: document2,
@@ -199,9 +216,9 @@ var gql = (chunks, ...variables) => {
199
216
  // src/client/mutations.ts
200
217
  var import_upperCase = __toESM(require("lodash/upperCase"), 1);
201
218
  var constantCase = (str) => (0, import_upperCase.default)(str).replace(/ /g, "_");
202
- var generateMutations = (models) => {
219
+ var generateMutations = (models, gqmModule = "@smartive/graphql-magic") => {
203
220
  const parts = [];
204
- for (const { name: name2, creatable, updatable, deletable } of models.filter(isEntityModel)) {
221
+ for (const { name: name2, creatable, updatable, deletable } of models.entities.filter(not(isRootModel))) {
205
222
  if (creatable) {
206
223
  parts.push(
207
224
  `export const CREATE_${constantCase(
@@ -232,11 +249,20 @@ var generateMutations = (models) => {
232
249
  mutation Delete${name2}Mutation($id: ID!) {
233
250
  delete${name2}(where: { id: $id })
234
251
  }
252
+ \`;`
253
+ );
254
+ parts.push(
255
+ `export const RESTORE_${constantCase(
256
+ name2
257
+ )} = gql\`
258
+ mutation Restore${name2}Mutation($id: ID!) {
259
+ restore${name2}(where: { id: $id })
260
+ }
235
261
  \`;`
236
262
  );
237
263
  }
238
264
  }
239
- return `import { gql } from "@smartive/graphql-magic";
265
+ return `import { gql } from "${gqmModule}";
240
266
 
241
267
  ${parts.join("\n\n")}`;
242
268
  };
@@ -246,96 +272,104 @@ var import_upperFirst = __toESM(require("lodash/upperFirst"), 1);
246
272
 
247
273
  // src/models/utils.ts
248
274
  var import_assert = __toESM(require("assert"), 1);
249
- var import_inflection = require("inflection");
250
- var import_camelCase = __toESM(require("lodash/camelCase"), 1);
275
+ var import_lodash3 = require("lodash");
251
276
  var import_get = __toESM(require("lodash/get"), 1);
252
- var import_kebabCase = __toESM(require("lodash/kebabCase"), 1);
253
- var import_startCase = __toESM(require("lodash/startCase"), 1);
254
- var isNotFalsy = (v) => typeof v !== "undefined" && v !== null && v !== false;
255
- var merge2 = (objects) => (objects || []).filter(isNotFalsy).reduce((i, acc) => ({ ...acc, ...i }), {});
256
- var typeToField = (type) => type.substr(0, 1).toLowerCase() + type.substr(1);
257
- var getModelPlural = (model) => model.plural || (0, import_inflection.pluralize)(model.name);
258
- var getModelPluralField = (model) => typeToField(getModelPlural(model));
259
- var getModelSlug = (model) => (0, import_kebabCase.default)(getModelPlural(model));
260
- var getModelLabelPlural = (model) => getLabel(getModelPlural(model));
261
- var getModelLabel = (model) => getLabel(model.name);
262
- var getLabel = (s) => (0, import_startCase.default)((0, import_camelCase.default)(s));
263
- var isEntityModel = (model) => model.kind === "entity";
264
- var isEnumModel = (model) => model.kind === "enum";
265
- var isRawEnumModel = (model) => model.kind === "raw-enum";
266
- var isScalarModel = (model) => model.kind === "scalar";
267
- var isObjectModel = (model) => model.kind === "object";
268
- var isInputModel = (model) => model.kind === "input";
269
- var isEnumList = (models, field) => field?.list === true && models.find(({ name: name2 }) => name2 === field.kind)?.kind === "enum";
270
- var and = (...predicates) => (field) => predicates.every((predicate) => predicate(field));
271
- var not = (predicate) => (field) => !predicate(field);
272
- var isPrimitive = (field) => field.kind === void 0 || field.kind === "primitive";
273
- var isEnum = (field) => field.kind === "enum";
274
- var isRelation = (field) => field.kind === "relation";
275
- var isToOneRelation = (field) => isRelation(field) && !!field.toOne;
276
- var isQueriableField = ({ queriable }) => queriable !== false;
277
- var isCustomField = (field) => field.kind === "custom";
278
- var isVisible = ({ hidden }) => hidden !== true;
279
- var isSimpleField = and(not(isRelation), not(isCustomField));
280
- var isUpdatable = ({ updatable }) => !!updatable;
281
- var isCreatable = ({ creatable }) => !!creatable;
282
- var isQueriableBy = (role) => (field) => field.queriable !== false && (field.queriable === void 0 || field.queriable === true || !field.queriable.roles || field.queriable.roles.includes(role));
283
- var isUpdatableBy = (role) => (field) => field.updatable && (field.updatable === true || !field.updatable.roles || field.updatable.roles.includes(role));
284
- var isCreatableBy = (role) => (field) => field.creatable && (field.creatable === true || !field.creatable.roles || field.creatable.roles.includes(role));
285
- var actionableRelations = (model, action) => model.fields.filter(isRelation).filter(
286
- (field) => field[`${action === "filter" ? action : action.slice(0, -1)}able`]
287
- );
288
- var getModels = (rawModels) => {
289
- const models = rawModels.filter(isEntityModel).map((model) => {
290
- const objectModel = {
291
- ...model,
292
- fieldsByName: {},
293
- relations: [],
294
- relationsByName: {},
295
- reverseRelations: [],
296
- reverseRelationsByName: {},
297
- fields: [
298
- { name: "id", type: "ID", nonNull: true, unique: true, primary: true, generated: true },
299
- ...model.fields,
300
- ...model.creatable ? [
277
+
278
+ // src/models/models.ts
279
+ var import_inflection = require("inflection");
280
+ var import_lodash2 = require("lodash");
281
+ var Models = class {
282
+ models;
283
+ modelsByName = {};
284
+ scalars;
285
+ rawEnums;
286
+ enums;
287
+ inputs;
288
+ interfaces;
289
+ objects;
290
+ entities;
291
+ definitions;
292
+ constructor(definitions) {
293
+ this.definitions = (0, import_lodash2.cloneDeep)(definitions);
294
+ this.definitions.push(
295
+ {
296
+ kind: "scalar",
297
+ name: "DateTime"
298
+ },
299
+ { kind: "scalar", name: "Upload" },
300
+ {
301
+ kind: "raw-enum",
302
+ name: "Order",
303
+ values: ["ASC", "DESC"]
304
+ }
305
+ );
306
+ const entities = this.definitions.filter(isEntityModelDefinition);
307
+ for (const entity of entities) {
308
+ if (entity.root) {
309
+ this.definitions.push({
310
+ kind: "enum",
311
+ name: `${entity.name}Type`,
312
+ values: entities.filter((subModel) => subModel.parent === entity.name).map((subModel) => subModel.name)
313
+ });
314
+ }
315
+ entity.fields = [
316
+ {
317
+ name: "id",
318
+ type: "ID",
319
+ nonNull: true,
320
+ unique: true,
321
+ primary: true,
322
+ generated: true
323
+ },
324
+ ...entity.root ? [
325
+ {
326
+ name: "type",
327
+ kind: "enum",
328
+ type: `${entity.name}Type`,
329
+ nonNull: true,
330
+ generated: true
331
+ }
332
+ ] : [],
333
+ ...entity.fields,
334
+ ...entity.creatable ? [
301
335
  {
302
336
  name: "createdAt",
303
337
  type: "DateTime",
304
338
  nonNull: true,
305
339
  orderable: true,
306
340
  generated: true,
307
- ...typeof model.creatable === "object" && model.creatable.createdAt
341
+ ...typeof entity.creatable === "object" && entity.creatable.createdAt
308
342
  },
309
343
  {
310
344
  name: "createdBy",
311
345
  kind: "relation",
312
346
  type: "User",
313
347
  nonNull: true,
314
- reverse: `created${getModelPlural(model)}`,
348
+ reverse: `created${getModelPlural(entity)}`,
315
349
  generated: true,
316
- ...typeof model.creatable === "object" && model.creatable.createdBy
350
+ ...typeof entity.creatable === "object" && entity.creatable.createdBy
317
351
  }
318
352
  ] : [],
319
- ...model.updatable ? [
353
+ ...entity.updatable ? [
320
354
  {
321
355
  name: "updatedAt",
322
356
  type: "DateTime",
323
357
  nonNull: true,
324
358
  orderable: true,
325
359
  generated: true,
326
- ...typeof model.updatable === "object" && model.updatable.updatedAt
360
+ ...typeof entity.updatable === "object" && entity.updatable.updatedAt
327
361
  },
328
362
  {
329
363
  name: "updatedBy",
330
364
  kind: "relation",
331
365
  type: "User",
332
366
  nonNull: true,
333
- reverse: `updated${getModelPlural(model)}`,
367
+ reverse: `updated${getModelPlural(entity)}`,
334
368
  generated: true,
335
- ...typeof model.updatable === "object" && model.updatable.updatedBy
369
+ ...typeof entity.updatable === "object" && entity.updatable.updatedBy
336
370
  }
337
371
  ] : [],
338
- ...model.deletable ? [
372
+ ...entity.deletable ? [
339
373
  {
340
374
  name: "deleted",
341
375
  type: "Boolean",
@@ -343,65 +377,349 @@ var getModels = (rawModels) => {
343
377
  defaultValue: false,
344
378
  filterable: { default: false },
345
379
  generated: true,
346
- ...typeof model.deletable === "object" && model.deletable.deleted
380
+ ...typeof entity.deletable === "object" && entity.deletable.deleted
347
381
  },
348
382
  {
349
383
  name: "deletedAt",
350
384
  type: "DateTime",
351
385
  orderable: true,
352
386
  generated: true,
353
- ...typeof model.deletable === "object" && model.deletable.deletedAt
387
+ ...typeof entity.deletable === "object" && entity.deletable.deletedAt
354
388
  },
355
389
  {
356
390
  name: "deletedBy",
357
391
  kind: "relation",
358
392
  type: "User",
359
- reverse: `deleted${getModelPlural(model)}`,
393
+ reverse: `deleted${getModelPlural(entity)}`,
360
394
  generated: true,
361
- ...typeof model.deletable === "object" && model.deletable.deletedBy
395
+ ...typeof entity.deletable === "object" && entity.deletable.deletedBy
362
396
  }
363
397
  ] : []
364
- ].map((field) => ({
365
- ...field,
366
- ...field.kind === "relation" && {
367
- foreignKey: field.foreignKey || `${field.name}Id`
398
+ ];
399
+ for (const field of entity.fields) {
400
+ if (field.kind === "relation") {
401
+ field.foreignKey = field.foreignKey || `${field.name}Id`;
368
402
  }
369
- }))
370
- };
371
- for (const field of objectModel.fields) {
372
- objectModel.fieldsByName[field.name] = field;
403
+ }
373
404
  }
374
- return objectModel;
375
- });
376
- for (const model of models) {
377
- for (const field of model.fields) {
378
- if (field.kind !== "relation") {
379
- continue;
405
+ for (const model of entities) {
406
+ if (model.parent) {
407
+ const parent = summonByName(entities, model.parent);
408
+ const INHERITED_FIELDS = ["queriable", "listQueriable", "creatable", "updatable", "deletable"];
409
+ Object.assign(model, (0, import_lodash2.pick)(parent, INHERITED_FIELDS), (0, import_lodash2.pick)(model, INHERITED_FIELDS));
410
+ model.fields = [
411
+ ...parent.fields.map((field) => ({
412
+ ...field,
413
+ ...field.kind === "relation" && field.reverse && { reverse: field.reverse.replace(getModelPlural(parent), getModelPlural(model)) },
414
+ ...model.fields.find((childField) => childField.name === field.name),
415
+ inherited: true
416
+ })),
417
+ ...model.fields.filter((field) => !parent.fields.some((parentField) => parentField.name === field.name))
418
+ ];
380
419
  }
381
- const fieldModel = summonByName(models, field.type);
382
- const reverseRelation = {
383
- kind: "relation",
384
- name: field.reverse || (field.toOne ? typeToField(model.name) : getModelPluralField(model)),
385
- foreignKey: get(field, "foreignKey"),
386
- type: model.name,
387
- toOne: !!field.toOne,
388
- fieldModel,
389
- field,
390
- model
391
- };
392
- const relation = {
393
- field,
394
- model: fieldModel,
395
- reverseRelation
396
- };
397
- model.relations.push(relation);
398
- model.relationsByName[relation.field.name] = relation;
399
- fieldModel.reverseRelations.push(reverseRelation);
400
- fieldModel.reverseRelationsByName[reverseRelation.name] = reverseRelation;
401
420
  }
421
+ this.models = this.definitions.map(
422
+ (definition) => new MODEL_KIND_TO_CLASS_MAPPING[definition.kind](this, definition)
423
+ );
424
+ for (const model of this.models) {
425
+ this.modelsByName[model.name] = model;
426
+ }
427
+ this.entities = this.models.filter((model) => model instanceof EntityModel);
428
+ this.enums = this.models.filter((model) => model instanceof EnumModel);
429
+ this.inputs = this.models.filter((model) => model instanceof InputModel);
430
+ this.interfaces = this.models.filter((model) => model instanceof InterfaceModel);
431
+ this.objects = this.models.filter((model) => model instanceof ObjectModel);
432
+ this.rawEnums = this.models.filter((model) => model instanceof RawEnumModel);
433
+ this.scalars = this.models.filter((model) => model instanceof ScalarModel);
434
+ }
435
+ getModel(name2, kind) {
436
+ const model = get(this.modelsByName, name2);
437
+ if (!kind) {
438
+ return model;
439
+ }
440
+ const expectedType = MODEL_KIND_TO_CLASS_MAPPING[kind];
441
+ if (!(model instanceof expectedType)) {
442
+ throw new Error(`Model ${name2} is not of kind ${kind}.`);
443
+ }
444
+ return model;
445
+ }
446
+ };
447
+ var Model = class {
448
+ constructor(models, definition) {
449
+ this.models = models;
450
+ Object.assign(this, definition);
451
+ this.plural = definition.plural || (0, import_inflection.pluralize)(definition.name);
452
+ }
453
+ name;
454
+ plural;
455
+ description;
456
+ };
457
+ var ScalarModel = class extends Model {
458
+ kind;
459
+ };
460
+ var EnumModel = class extends Model {
461
+ kind;
462
+ values;
463
+ deleted;
464
+ constructor(models, definition) {
465
+ super(models, definition);
466
+ Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
467
+ }
468
+ };
469
+ var RawEnumModel = class extends Model {
470
+ kind;
471
+ values;
472
+ constructor(models, definition) {
473
+ super(models, definition);
474
+ Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
475
+ }
476
+ };
477
+ var InterfaceModel = class extends Model {
478
+ kind;
479
+ fields;
480
+ constructor(models, definition) {
481
+ super(models, definition);
482
+ Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
483
+ }
484
+ };
485
+ var InputModel = class extends Model {
486
+ kind;
487
+ fields;
488
+ constructor(models, definition) {
489
+ super(models, definition);
490
+ Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
491
+ }
492
+ };
493
+ var ObjectModel = class extends Model {
494
+ kind;
495
+ fields;
496
+ constructor(models, definition) {
497
+ super(models, definition);
498
+ Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
499
+ }
500
+ };
501
+ var EntityModel = class extends Model {
502
+ kind;
503
+ root;
504
+ parent;
505
+ interfaces;
506
+ queriable;
507
+ listQueriable;
508
+ creatable;
509
+ updatable;
510
+ deletable;
511
+ displayField;
512
+ defaultOrderBy;
513
+ fields;
514
+ // temporary fields for the generation of migrations
515
+ deleted;
516
+ oldName;
517
+ fieldsByName = {};
518
+ fieldsByColumnName = {};
519
+ _relations;
520
+ _relationsByName;
521
+ _reverseRelations;
522
+ _reverseRelationsByName;
523
+ _manyToManyRelations;
524
+ _manyToManyRelationsByName;
525
+ pluralField;
526
+ slug;
527
+ labelPlural;
528
+ label;
529
+ _parentModel;
530
+ constructor(models, definition) {
531
+ super(models, definition);
532
+ Object.assign(this, (0, import_lodash2.omit)(definition, "name", "plural", "description"));
533
+ this.pluralField = typeToField(this.plural);
534
+ this.slug = (0, import_lodash2.kebabCase)(this.plural);
535
+ this.labelPlural = getLabel(this.plural);
536
+ this.label = getLabel(definition.name);
537
+ for (const field of definition.fields) {
538
+ this.fieldsByName[field.name] = field;
539
+ }
540
+ }
541
+ getField(name2) {
542
+ return get(this.fieldsByName, name2);
543
+ }
544
+ get relations() {
545
+ if (!this._relations) {
546
+ this._relations = this.fields.filter(isRelation).map((relationField) => new NormalRelation(this, relationField, this.models.getModel(relationField.type, "entity")));
547
+ }
548
+ return this._relations;
549
+ }
550
+ get relationsByName() {
551
+ if (!this._relationsByName) {
552
+ this._relationsByName = {};
553
+ for (const relation of this.relations) {
554
+ this._relationsByName[relation.name] = relation;
555
+ }
556
+ }
557
+ return this._relationsByName;
558
+ }
559
+ getRelation(name2) {
560
+ return get(this.relationsByName, name2);
561
+ }
562
+ get reverseRelations() {
563
+ if (!this._reverseRelations) {
564
+ this._reverseRelations = this.models.entities.flatMap(
565
+ (model) => model.relations.filter((relation) => relation.targetModel.name === this.name || relation.targetModel.name === this.rootModel.name).map((relation) => relation.reverse)
566
+ );
567
+ }
568
+ return this._reverseRelations;
569
+ }
570
+ get reverseRelationsByName() {
571
+ if (!this._reverseRelationsByName) {
572
+ this._reverseRelationsByName = {};
573
+ for (const reverseRelation of this.reverseRelations) {
574
+ this._reverseRelationsByName[reverseRelation.name] = reverseRelation;
575
+ }
576
+ }
577
+ return this._reverseRelationsByName;
578
+ }
579
+ getReverseRelation(name2) {
580
+ return get(this.reverseRelationsByName, name2);
581
+ }
582
+ get manyToManyRelations() {
583
+ if (!this._manyToManyRelations) {
584
+ this._manyToManyRelations = [];
585
+ for (const relationFromSource of this.reverseRelations) {
586
+ const relationToTarget = relationFromSource.targetModel.relations.find(
587
+ (relation) => !relation.field.generated && relation.field.name !== relationFromSource.field.name
588
+ );
589
+ if (!relationToTarget) {
590
+ continue;
591
+ }
592
+ const inapplicableFields = relationFromSource.targetModel.fields.filter(
593
+ (otherField) => !otherField.generated && ![relationFromSource.field.name, relationToTarget.field.name].includes(otherField.name)
594
+ );
595
+ if (inapplicableFields.length) {
596
+ continue;
597
+ }
598
+ this._manyToManyRelations.push(new ManyToManyRelation(relationFromSource, relationToTarget));
599
+ }
600
+ }
601
+ return this._manyToManyRelations;
602
+ }
603
+ get manyToManyRelationsByName() {
604
+ if (!this._manyToManyRelationsByName) {
605
+ this._manyToManyRelationsByName = {};
606
+ for (const manyToManyRelation of this.manyToManyRelations) {
607
+ this._manyToManyRelationsByName[manyToManyRelation.name] = manyToManyRelation;
608
+ }
609
+ }
610
+ return this._manyToManyRelationsByName;
611
+ }
612
+ getManyToManyRelation(name2) {
613
+ return get(this.manyToManyRelationsByName, name2);
614
+ }
615
+ get parentModel() {
616
+ if (this.parent) {
617
+ if (!this._parentModel) {
618
+ this._parentModel = this.models.getModel(this.parent, "entity");
619
+ }
620
+ return this._parentModel;
621
+ }
622
+ }
623
+ get rootModel() {
624
+ return this.parentModel || this;
625
+ }
626
+ };
627
+ var MODEL_KIND_TO_CLASS_MAPPING = {
628
+ entity: EntityModel,
629
+ enum: EnumModel,
630
+ input: InputModel,
631
+ interface: InterfaceModel,
632
+ object: ObjectModel,
633
+ "raw-enum": RawEnumModel,
634
+ scalar: ScalarModel
635
+ };
636
+ var Relation = class {
637
+ constructor(name2, sourceModel, field, targetModel) {
638
+ this.name = name2;
639
+ this.sourceModel = sourceModel;
640
+ this.field = field;
641
+ this.targetModel = targetModel;
642
+ }
643
+ };
644
+ var NormalRelation = class extends Relation {
645
+ constructor(sourceModel, field, targetModel) {
646
+ super(field.name, sourceModel, field, targetModel);
647
+ this.field = field;
648
+ this.reverse = new ReverseRelation(this);
649
+ }
650
+ reverse;
651
+ };
652
+ var ReverseRelation = class extends Relation {
653
+ constructor(reverse) {
654
+ super(
655
+ reverse.field.reverse || (reverse.field.toOne ? typeToField(reverse.sourceModel.name) : reverse.sourceModel.pluralField),
656
+ reverse.targetModel,
657
+ reverse.field,
658
+ reverse.sourceModel
659
+ );
660
+ this.reverse = reverse;
661
+ }
662
+ };
663
+ var ManyToManyRelation = class {
664
+ name;
665
+ sourceModel;
666
+ relationFromSource;
667
+ relationModel;
668
+ relationToTarget;
669
+ targetModel;
670
+ constructor(relationFromSource, relationToTarget) {
671
+ this.name = relationFromSource.name;
672
+ this.sourceModel = relationFromSource.sourceModel;
673
+ this.relationFromSource = relationFromSource;
674
+ this.relationModel = relationFromSource.targetModel;
675
+ if (this.relationModel !== relationToTarget.sourceModel) {
676
+ throw new Error(`Relation model is ambiguous.`);
677
+ }
678
+ this.relationToTarget = relationToTarget;
679
+ this.targetModel = relationToTarget.targetModel;
402
680
  }
403
- return models;
404
681
  };
682
+ var isEntityModelDefinition = (definition) => definition.kind === "entity";
683
+ var getModelPlural = (model) => model.plural || (0, import_inflection.pluralize)(model.name);
684
+
685
+ // src/models/utils.ts
686
+ var isNotFalsy = (v) => typeof v !== "undefined" && v !== null && v !== false;
687
+ var merge2 = (objects) => (objects || []).filter(isNotFalsy).reduce((i, acc) => ({ ...acc, ...i }), {});
688
+ var typeToField = (type) => type.substr(0, 1).toLowerCase() + type.substr(1);
689
+ var getLabel = (s) => (0, import_lodash3.startCase)((0, import_lodash3.camelCase)(s));
690
+ var or = (...predicates) => (field) => predicates.some((predicate) => predicate(field));
691
+ var and = (...predicates) => (field) => predicates.every((predicate) => predicate(field));
692
+ var not = (predicate) => (field) => !predicate(field);
693
+ var isRootModel = (model) => model.root;
694
+ var isEntityModel = (model) => model instanceof EntityModel;
695
+ var isEnumModel = (model) => model instanceof EnumModel;
696
+ var isRawEnumModel = (model) => model instanceof RawEnumModel;
697
+ var isScalarModel = (model) => model instanceof ScalarModel;
698
+ var isObjectModel = (model) => model instanceof ObjectModel;
699
+ var isInputModel = (model) => model instanceof InputModel;
700
+ var isInterfaceModel = (model) => model instanceof InterfaceModel;
701
+ var isUpdatableModel = (model) => model.updatable && model.fields.some(isUpdatableField);
702
+ var isUpdatableField = (field) => !field.inherited && !!field.updatable;
703
+ var modelNeedsTable = (model) => model.fields.some((field) => !field.inherited);
704
+ var hasName = (name2) => (field) => field.name == name2;
705
+ var isPrimitive = (field) => field.kind === void 0 || field.kind === "primitive";
706
+ var isEnum = (field) => field.kind === "enum";
707
+ var isRelation = (field) => field.kind === "relation";
708
+ var isInherited = (field) => field.inherited;
709
+ var isInTable = (field) => field.name === "id" || !field.inherited;
710
+ var isToOneRelation = (field) => isRelation(field) && !!field.toOne;
711
+ var isQueriableField = ({ queriable }) => queriable !== false;
712
+ var isCustomField = (field) => field.kind === "custom";
713
+ var isVisible = ({ hidden }) => hidden !== true;
714
+ var isSimpleField = and(not(isRelation), not(isCustomField));
715
+ var isUpdatable = ({ updatable }) => !!updatable;
716
+ var isCreatable = ({ creatable }) => !!creatable;
717
+ var isQueriableBy = (role) => (field) => field.queriable !== false && (field.queriable === void 0 || field.queriable === true || !field.queriable.roles || field.queriable.roles.includes(role));
718
+ var isUpdatableBy = (role) => (field) => field.updatable && (field.updatable === true || !field.updatable.roles || field.updatable.roles.includes(role));
719
+ var isCreatableBy = (role) => (field) => field.creatable && (field.creatable === true || !field.creatable.roles || field.creatable.roles.includes(role));
720
+ var actionableRelations = (model, action) => model.relations.filter(
721
+ (relation) => relation.field[`${action === "filter" ? action : action.slice(0, -1)}able`]
722
+ );
405
723
  var summonByName = (array, value2) => summonByKey(array, "name", value2);
406
724
  var summonByKey = (array, key, value2) => summon(array, (element) => (0, import_get.default)(element, key) === value2, `No element found with ${key} ${value2}`);
407
725
  var summon = (array, cb, errorMessage) => {
@@ -426,8 +744,9 @@ var it = (object2) => {
426
744
  var get = (object2, key) => {
427
745
  const value2 = it(object2)[key];
428
746
  if (value2 === void 0 || value2 === null) {
429
- console.trace();
430
- throw new Error(`Object doesn't have ${String(key)}`);
747
+ const error = new Error(`Object doesn't have ${String(key)}`);
748
+ console.warn(error);
749
+ throw error;
431
750
  }
432
751
  return value2;
433
752
  };
@@ -456,73 +775,49 @@ var getUpdateEntityQuery = (model, role, fields2, additionalFields = "") => `que
456
775
  ${additionalFields}
457
776
  }
458
777
  }`;
459
- var getEditEntityRelationsQuery = (models, model, action, fields2, ignoreFields, additionalFields = {}) => {
778
+ var getEditEntityRelationsQuery = (model, action, fields2, ignoreFields, additionalFields = {}) => {
460
779
  const relations = actionableRelations(model, action).filter(
461
780
  ({ name: name2 }) => (!fields2 || fields2.includes(name2)) && (!ignoreFields || !ignoreFields.includes(name2))
462
781
  );
463
782
  return !!relations.length && `query ${(0, import_upperFirst.default)(action)}${model.name}Relations {
464
- ${relations.map(({ name: name2, type }) => {
465
- const model2 = summonByName(models, type);
783
+ ${relations.map((relation) => {
466
784
  let filters = "";
467
- if (model2.displayField) {
468
- const displayField2 = model2.fieldsByName[model2.displayField];
785
+ if (relation.targetModel.displayField) {
786
+ const displayField2 = relation.targetModel.fieldsByName[relation.targetModel.displayField];
469
787
  if (displayField2.orderable) {
470
- filters = `(orderBy: [{ ${model2.displayField}: ASC }])`;
788
+ filters = `(orderBy: [{ ${relation.targetModel.displayField}: ASC }])`;
471
789
  }
472
790
  }
473
- return `${name2}: ${getModelPluralField(model2)}${filters} {
791
+ return `${relation.name}: ${relation.targetModel.pluralField}${filters} {
474
792
  id
475
- display: ${model2.displayField || "id"}
476
- ${additionalFields[name2] || ""}
793
+ display: ${relation.targetModel.displayField || "id"}
794
+ ${additionalFields[relation.name] || ""}
477
795
  }`;
478
796
  }).join(" ")}
479
797
  }`;
480
798
  };
481
- var getManyToManyRelations = (model, fields2, ignoreFields) => {
482
- const manyToManyRelations = [];
483
- for (const field of model.reverseRelations) {
484
- if (fields2 && !fields2.includes(field.name) || ignoreFields && ignoreFields.includes(field.name)) {
485
- continue;
486
- }
487
- const relation = field.model.relations.find(
488
- (relation2) => !relation2.field.generated && relation2.field.name !== field.field.name
489
- );
490
- if (!relation) {
491
- continue;
492
- }
493
- const inapplicableFields = field.model.fields.filter(
494
- (otherField) => !otherField.generated && ![field.field.name, relation.field.name].includes(otherField.name)
495
- );
496
- if (inapplicableFields.length) {
497
- continue;
498
- }
499
- manyToManyRelations.push([field, relation]);
500
- }
501
- return manyToManyRelations;
502
- };
503
- var getManyToManyRelation = (model, name2) => getManyToManyRelations(model, [name2])[0];
504
799
  var getManyToManyRelationsQuery = (model, action, manyToManyRelations) => !!manyToManyRelations.length && (action === "update" ? `query Update${model.name}ManyToManyRelations($id: ID!) {
505
800
  ${typeToField(model.name)}(where: { id: $id }) {
506
- ${manyToManyRelations.map(([reverseRelation, { field }]) => {
507
- return `${reverseRelation.name} {
801
+ ${manyToManyRelations.map((relation) => {
802
+ return `${relation.name} {
508
803
  id
509
- ${field.name} {
804
+ ${relation.relationToTarget.name} {
510
805
  id
511
806
  }
512
807
  }`;
513
808
  }).join(" ")}
514
809
  }
515
- ${manyToManyRelations.map(([reverseRelation, { model: model2 }]) => {
516
- return `${reverseRelation.name}: ${getModelPluralField(model2)} {
810
+ ${manyToManyRelations.map((relation) => {
811
+ return `${relation.name}: ${relation.targetModel.pluralField} {
517
812
  id
518
- ${model2.displayField || ""}
813
+ ${relation.targetModel.displayField || ""}
519
814
  }`;
520
815
  }).join(" ")}
521
816
  }` : `query Create${model.name}ManyToManyRelations {
522
- ${manyToManyRelations.map(([reverseRelation, { model: model2 }]) => {
523
- return `${reverseRelation.name}: ${getModelPluralField(model2)} {
817
+ ${manyToManyRelations.map((relation) => {
818
+ return `${relation.name}: ${relation.targetModel.pluralField} {
524
819
  id
525
- ${model2.displayField || ""}
820
+ ${relation.targetModel.displayField || ""}
526
821
  }`;
527
822
  }).join(" ")}
528
823
  }`);
@@ -548,14 +843,14 @@ var getMutationQuery = (model, action) => action === "create" ? `
548
843
  var displayField = (model) => `
549
844
  ${model.displayField ? `display: ${model.displayField}` : ""}
550
845
  `;
551
- var getEntityListQuery = (model, role, additionalFields = "", root) => `query ${getModelPlural(model)}List(
846
+ var getEntityListQuery = (model, role, additionalFields = "", root) => `query ${model.plural}List(
552
847
  ${root ? "$id: ID!," : ""}
553
848
  $limit: Int!,
554
849
  $where: ${model.name}Where!,
555
850
  ${model.fields.some(({ searchable }) => searchable) ? "$search: String," : ""}
556
851
  ) {
557
852
  ${root ? `root: ${typeToField(root.model.name)}(where: { id: $id }) {` : ""}
558
- data: ${root ? root.reverseRelationName : getModelPluralField(model)}(limit: $limit, where: $where, ${model.fields.some(({ searchable }) => searchable) ? ", search: $search" : ""}) {
853
+ data: ${root ? root.reverseRelationName : model.pluralField}(limit: $limit, where: $where, ${model.fields.some(({ searchable }) => searchable) ? ", search: $search" : ""}) {
559
854
  ${displayField(model)}
560
855
  ${model.fields.filter(and(isSimpleField, isQueriableBy(role))).map(({ name: name2 }) => name2)}
561
856
  ${additionalFields}
@@ -564,37 +859,38 @@ var getEntityListQuery = (model, role, additionalFields = "", root) => `query ${
564
859
  }`;
565
860
  var isVisibleRelation = (visibleRelationsByRole, modelName, role) => {
566
861
  const whitelist = visibleRelationsByRole[role]?.[modelName];
567
- return ({ name: name2 }) => whitelist ? whitelist.includes(name2) : true;
862
+ return (relation) => whitelist ? whitelist.includes(relation.name) : true;
568
863
  };
569
- var getEntityQuery = (models, model, role, visibleRelationsByRole, typesWithSubRelations) => `query Admin${model.name} ($id: ID!) {
864
+ var getEntityQuery = (model, role, visibleRelationsByRole, typesWithSubRelations) => `query Admin${model.name} ($id: ID!) {
570
865
  data: ${typeToField(model.name)}(where: { id: $id }) {
571
866
  ${displayField(model)}
572
867
  ${model.fields.filter(and(isSimpleField, isQueriableBy(role))).map(({ name: name2 }) => name2)}
573
868
  ${queryRelations(
574
- models,
575
- model.fields.filter(isRelation).filter(isVisibleRelation(visibleRelationsByRole, model.name, role)),
869
+ model.models,
870
+ model.relations.filter(isVisibleRelation(visibleRelationsByRole, model.name, role)),
576
871
  role,
577
872
  typesWithSubRelations
578
873
  )}
579
874
  ${queryRelations(
580
- models,
581
- model.reverseRelations.filter(and(isToOneRelation, isVisibleRelation(visibleRelationsByRole, model.name, role))),
875
+ model.models,
876
+ model.reverseRelations.filter(
877
+ (reverseRelation) => isToOneRelation(reverseRelation.field) && isVisibleRelation(visibleRelationsByRole, model.name, role)(reverseRelation)
878
+ ),
582
879
  role,
583
880
  typesWithSubRelations
584
881
  )}
585
882
  }
586
883
  }`;
587
884
  var getFindEntityQuery = (model, role) => `query Find${model.name}($where: ${model.name}Where!, $orderBy: [${model.name}OrderBy!]) {
588
- data: ${getModelPluralField(model)}(limit: 1, where: $where, orderBy: $orderBy) {
885
+ data: ${model.pluralField}(limit: 1, where: $where, orderBy: $orderBy) {
589
886
  ${model.fields.filter(and(isSimpleField, isQueriableBy(role))).map(({ name: name2 }) => name2)}
590
887
  }
591
888
  }`;
592
- var queryRelations = (models, relations, role, typesWithSubRelations) => relations.map(({ name: name2, type }) => {
593
- const relatedModel = summonByName(models, type);
594
- const subRelations = typesWithSubRelations.includes(type) ? relatedModel.fields.filter(isRelation) : [];
595
- return `${name2} {
889
+ var queryRelations = (models, relations, role, typesWithSubRelations) => relations.map((relation) => {
890
+ const subRelations = typesWithSubRelations.includes(relation.targetModel.name) ? relation.targetModel.relations : [];
891
+ return `${relation.name} {
596
892
  id
597
- ${displayField(relatedModel)}
893
+ ${displayField(relation.targetModel)}
598
894
  ${subRelations.length > 0 ? queryRelations(models, subRelations, role, typesWithSubRelations) : ""}
599
895
  }`;
600
896
  }).join("\n");
@@ -611,56 +907,59 @@ var PRIMITIVE_TYPES = {
611
907
  DateTime: "DateTime | string"
612
908
  };
613
909
  var OPTIONAL_SEED_FIELDS = ["createdAt", "createdById", "updatedAt", "updatedById", "deletedAt", "deletedById"];
614
- var generateDBModels = (rawModels) => {
910
+ var generateDBModels = (models) => {
615
911
  const writer = new import_code_block_writer.default["default"]({
616
912
  useSingleQuote: true,
617
913
  indentNumberOfSpaces: 2
618
914
  });
619
915
  writer.write(`import { DateTime } from 'luxon';`).blankLine();
620
- for (const enm2 of rawModels.filter(isEnumModel)) {
916
+ for (const enm2 of models.enums) {
621
917
  writer.write(`export type ${enm2.name} = ${enm2.values.map((v) => `'${v}'`).join(" | ")};`).blankLine();
622
918
  }
623
- const models = getModels(rawModels);
624
- for (const model of models) {
625
- const fields2 = model.fields.some((field) => field.kind === "relation" && field.foreignKey === "id") ? model.fields.filter((field) => field.name !== "id") : model.fields;
919
+ for (const model of models.entities) {
920
+ const fields2 = model.relations.some((relation) => relation.field.foreignKey === "id") ? model.fields.filter((field) => field.name !== "id") : model.fields;
626
921
  writer.write(`export type ${model.name} = `).inlineBlock(() => {
627
922
  for (const field of fields2.filter(not(isCustomField))) {
628
- writer.write(`'${getFieldName(field)}': ${getFieldType(field)}${field.nonNull ? "" : " | null"},`).newLine();
923
+ writer.write(`'${getColumnName(field)}': ${getFieldType(field)}${field.nonNull ? "" : " | null"};`).newLine();
629
924
  }
630
925
  }).blankLine();
631
926
  writer.write(`export type ${model.name}Initializer = `).inlineBlock(() => {
632
- for (const field of fields2.filter(not(isCustomField))) {
927
+ for (const field of fields2.filter(not(isCustomField)).filter(isInTable)) {
633
928
  writer.write(
634
- `'${getFieldName(field)}'${field.nonNull && field.defaultValue === void 0 ? "" : "?"}: ${getFieldType(
929
+ `'${getColumnName(field)}'${field.nonNull && field.defaultValue === void 0 ? "" : "?"}: ${getFieldType(
635
930
  field
636
- )}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"},`
931
+ )}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
637
932
  ).newLine();
638
933
  }
639
934
  }).blankLine();
640
935
  writer.write(`export type ${model.name}Mutator = `).inlineBlock(() => {
641
- for (const field of fields2.filter(not(isCustomField))) {
642
- writer.write(
643
- `'${getFieldName(field)}'?: ${getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"},`
644
- ).newLine();
645
- }
646
- }).blankLine();
647
- writer.write(`export type ${model.name}Seed = `).inlineBlock(() => {
648
- for (const field of fields2.filter(not(isCustomField))) {
649
- const fieldName = getFieldName(field);
936
+ for (const field of fields2.filter(not(isCustomField)).filter(isInTable)) {
650
937
  writer.write(
651
- `'${getFieldName(field)}'${field.nonNull && field.defaultValue === void 0 && !OPTIONAL_SEED_FIELDS.includes(fieldName) ? "" : "?"}: ${field.kind === "enum" ? field.list ? "string[]" : "string" : getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"},`
938
+ `'${getColumnName(field)}'?: ${getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
652
939
  ).newLine();
653
940
  }
654
941
  }).blankLine();
942
+ if (!isRootModel(model)) {
943
+ writer.write(`export type ${model.name}Seed = `).inlineBlock(() => {
944
+ for (const field of fields2.filter(not(isCustomField))) {
945
+ if (model.parent && field.name === "type") {
946
+ continue;
947
+ }
948
+ const fieldName = getColumnName(field);
949
+ writer.write(
950
+ `'${getColumnName(field)}'${field.nonNull && field.defaultValue === void 0 && !OPTIONAL_SEED_FIELDS.includes(fieldName) ? "" : "?"}: ${field.kind === "enum" ? field.list ? "string[]" : "string" : getFieldType(field)}${field.list ? " | string" : ""}${field.nonNull ? "" : " | null"};`
951
+ ).newLine();
952
+ }
953
+ }).blankLine();
954
+ }
655
955
  }
656
956
  writer.write(`export type SeedData = `).inlineBlock(() => {
657
- for (const model of models) {
658
- writer.write(`${model.name}: ${model.name}Seed[],`).newLine();
957
+ for (const model of models.entities.filter(not(isRootModel))) {
958
+ writer.write(`${model.name}: ${model.name}Seed[];`).newLine();
659
959
  }
660
960
  });
661
961
  return writer.toString();
662
962
  };
663
- var getFieldName = (field) => field.kind === "relation" ? field.foreignKey || `${field.name}Id` : field.name;
664
963
  var getFieldType = (field) => {
665
964
  const kind = field.kind;
666
965
  switch (kind) {
@@ -681,19 +980,18 @@ var getFieldType = (field) => {
681
980
  }
682
981
  }
683
982
  };
684
- var generateKnexTables = (rawModels) => {
983
+ var generateKnexTables = (models) => {
685
984
  const writer = new import_code_block_writer.default["default"]({
686
985
  useSingleQuote: true,
687
986
  indentNumberOfSpaces: 2
688
987
  });
689
- const models = getModels(rawModels);
690
988
  writer.write(`import { Knex } from 'knex';`).newLine();
691
989
  writer.write(
692
- `import { ${models.map((model) => `${model.name}, ${model.name}Initializer, ${model.name}Mutator`).join(", ")} } from '.';`
990
+ `import { ${models.entities.map((model) => `${model.name}, ${model.name}Initializer, ${model.name}Mutator`).join(", ")} } from '.';`
693
991
  ).blankLine();
694
992
  writer.write(`declare module 'knex/types/tables' `).inlineBlock(() => {
695
993
  writer.write(`interface Tables `).inlineBlock(() => {
696
- for (const model of models) {
994
+ for (const model of models.entities) {
697
995
  writer.write(`'${model.name}': Knex.CompositeTableType<${model.name}, ${model.name}Initializer, ${model.name}Mutator>,`).newLine();
698
996
  }
699
997
  });
@@ -706,10 +1004,9 @@ var import_code_block_writer2 = __toESM(require("code-block-writer"), 1);
706
1004
  var import_knex_schema_inspector = require("knex-schema-inspector");
707
1005
  var import_lowerFirst = __toESM(require("lodash/lowerFirst"), 1);
708
1006
  var MigrationGenerator = class {
709
- constructor(knex, rawModels) {
710
- this.rawModels = rawModels;
1007
+ constructor(knex, models) {
1008
+ this.models = models;
711
1009
  this.schema = (0, import_knex_schema_inspector.SchemaInspector)(knex);
712
- this.models = getModels(rawModels);
713
1010
  }
714
1011
  writer = new import_code_block_writer2.default["default"]({
715
1012
  useSingleQuote: true,
@@ -719,9 +1016,8 @@ var MigrationGenerator = class {
719
1016
  columns = {};
720
1017
  uuidUsed;
721
1018
  nowUsed;
722
- models;
723
1019
  async generate() {
724
- const { writer, schema, rawModels, models } = this;
1020
+ const { writer, schema, models } = this;
725
1021
  const enums = (await schema.knex("pg_type").where({ typtype: "e" }).select("typname")).map(({ typname }) => typname);
726
1022
  const tables = await schema.tables();
727
1023
  for (const table of tables) {
@@ -730,11 +1026,11 @@ var MigrationGenerator = class {
730
1026
  const up = [];
731
1027
  const down = [];
732
1028
  this.createEnums(
733
- rawModels.filter(isEnumModel).filter((enm2) => !enums.includes((0, import_lowerFirst.default)(enm2.name))),
1029
+ this.models.enums.filter((enm2) => !enums.includes((0, import_lowerFirst.default)(enm2.name))),
734
1030
  up,
735
1031
  down
736
1032
  );
737
- for (const model of models) {
1033
+ for (const model of models.entities) {
738
1034
  if (model.deleted) {
739
1035
  up.push(() => {
740
1036
  this.dropTable(model.name);
@@ -746,7 +1042,7 @@ var MigrationGenerator = class {
746
1042
  }
747
1043
  });
748
1044
  });
749
- if (model.updatable) {
1045
+ if (isUpdatableModel(model)) {
750
1046
  up.push(() => {
751
1047
  this.dropTable(`${model.name}Revision`);
752
1048
  });
@@ -765,7 +1061,7 @@ var MigrationGenerator = class {
765
1061
  tables[tables.indexOf(model.oldName)] = model.name;
766
1062
  this.columns[model.name] = this.columns[model.oldName];
767
1063
  delete this.columns[model.oldName];
768
- if (model.updatable) {
1064
+ if (isUpdatableModel(model)) {
769
1065
  up.push(() => {
770
1066
  this.renameTable(`${model.oldName}Revision`, `${model.name}Revision`);
771
1067
  this.alterTable(`${model.name}Revision`, () => {
@@ -783,92 +1079,102 @@ var MigrationGenerator = class {
783
1079
  delete this.columns[`${model.oldName}Revision`];
784
1080
  }
785
1081
  }
786
- if (!tables.includes(model.name)) {
787
- up.push(() => {
788
- this.createTable(model.name, () => {
789
- for (const field of model.fields) {
790
- this.column(field);
791
- }
792
- });
793
- });
794
- down.push(() => {
795
- this.dropTable(model.name);
796
- });
797
- } else {
798
- this.renameFields(
799
- model,
800
- model.fields.filter(({ oldName }) => oldName),
801
- up,
802
- down
803
- );
804
- this.createFields(
805
- model,
806
- model.fields.filter(
807
- ({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[model.name].some(
808
- (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
809
- )
810
- ),
811
- up,
812
- down
813
- );
814
- const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
815
- const col = this.columns[model.name].find((col2) => col2.name === (kind === "relation" ? `${name2}Id` : name2));
816
- if (!col) {
817
- return false;
818
- }
819
- return !nonNull2 && !col.is_nullable;
820
- });
821
- this.updateFields(model, existingFields, up, down);
822
- }
823
- if (model.updatable) {
824
- if (!tables.includes(`${model.name}Revision`)) {
1082
+ if (modelNeedsTable(model)) {
1083
+ if (!tables.includes(model.name)) {
825
1084
  up.push(() => {
826
- this.createRevisionTable(model);
827
- });
828
- if (tables.includes(model.name)) {
829
- up.push(() => {
830
- writer.block(() => {
831
- writer.writeLine(`const data = await knex('${model.name}');`);
832
- writer.write(`if (data.length)`).block(() => {
833
- writer.write(`await knex.batchInsert('${model.name}Revision', data.map((row) => (`).inlineBlock(() => {
834
- writer.writeLine(`id: uuid(),`);
835
- writer.writeLine(`${typeToField(model.name)}Id: row.id,`);
836
- this.nowUsed = true;
837
- writer.writeLine(`createdAt: row.updatedAt || row.createdAt || now,`);
838
- writer.writeLine(`createdById: row.updatedById || row.createdById,`);
839
- if (model.deletable) {
840
- writer.writeLine(`deleted: row.deleted,`);
841
- }
842
- for (const { name: name2, kind } of model.fields.filter(({ updatable }) => updatable)) {
843
- const col = kind === "relation" ? `${name2}Id` : name2;
844
- writer.writeLine(`${col}: row.${col},`);
845
- }
846
- }).write(")));").newLine();
1085
+ this.createTable(model.name, () => {
1086
+ if (model.parent) {
1087
+ this.column({
1088
+ ...model.fieldsByName.id,
1089
+ kind: "relation",
1090
+ type: model.parent,
1091
+ foreignKey: "id"
847
1092
  });
848
- }).blankLine();
1093
+ }
1094
+ for (const field of model.fields.filter(not(isInherited))) {
1095
+ this.column(field);
1096
+ }
849
1097
  });
850
- }
1098
+ });
851
1099
  down.push(() => {
852
- this.dropTable(`${model.name}Revision`);
1100
+ this.dropTable(model.name);
853
1101
  });
854
1102
  } else {
855
- const revisionTable = `${model.name}Revision`;
856
- const missingRevisionFields = model.fields.filter(
857
- ({ name: name2, updatable, ...field }) => field.kind !== "custom" && updatable && !this.columns[revisionTable].some(
858
- (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
859
- )
1103
+ this.renameFields(
1104
+ model,
1105
+ model.fields.filter(not(isInherited)).filter(({ oldName }) => oldName),
1106
+ up,
1107
+ down
860
1108
  );
861
- this.createRevisionFields(model, missingRevisionFields, up, down);
862
- const revisionFieldsToRemove = model.fields.filter(
863
- ({ name: name2, updatable, generated, ...field }) => !generated && field.kind !== "custom" && !updatable && !(field.kind === "relation" && field.foreignKey === "id") && this.columns[revisionTable].some(
864
- (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
865
- )
1109
+ this.createFields(
1110
+ model,
1111
+ model.fields.filter(not(isInherited)).filter(
1112
+ ({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[model.name].some(
1113
+ (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
1114
+ )
1115
+ ),
1116
+ up,
1117
+ down
866
1118
  );
867
- this.createRevisionFields(model, revisionFieldsToRemove, down, up);
1119
+ const existingFields = model.fields.filter(({ name: name2, kind, nonNull: nonNull2 }) => {
1120
+ const col = this.columns[model.name].find((col2) => col2.name === (kind === "relation" ? `${name2}Id` : name2));
1121
+ if (!col) {
1122
+ return false;
1123
+ }
1124
+ return !nonNull2 && !col.is_nullable;
1125
+ });
1126
+ this.updateFields(model, existingFields, up, down);
1127
+ }
1128
+ if (isUpdatableModel(model)) {
1129
+ if (!tables.includes(`${model.name}Revision`)) {
1130
+ up.push(() => {
1131
+ this.createRevisionTable(model);
1132
+ });
1133
+ if (tables.includes(model.name)) {
1134
+ up.push(() => {
1135
+ writer.block(() => {
1136
+ writer.writeLine(`const data = await knex('${model.name}');`);
1137
+ writer.write(`if (data.length)`).block(() => {
1138
+ writer.write(`await knex.batchInsert('${model.name}Revision', data.map((row) => (`).inlineBlock(() => {
1139
+ writer.writeLine(`id: uuid(),`);
1140
+ writer.writeLine(`${typeToField(model.name)}Id: row.id,`);
1141
+ this.nowUsed = true;
1142
+ writer.writeLine(`createdAt: row.updatedAt || row.createdAt || now,`);
1143
+ writer.writeLine(`createdById: row.updatedById || row.createdById,`);
1144
+ if (model.deletable) {
1145
+ writer.writeLine(`deleted: row.deleted,`);
1146
+ }
1147
+ for (const { name: name2, kind } of model.fields.filter(isUpdatableField)) {
1148
+ const col = kind === "relation" ? `${name2}Id` : name2;
1149
+ writer.writeLine(`${col}: row.${col},`);
1150
+ }
1151
+ }).write(")));").newLine();
1152
+ });
1153
+ }).blankLine();
1154
+ });
1155
+ }
1156
+ down.push(() => {
1157
+ this.dropTable(`${model.name}Revision`);
1158
+ });
1159
+ } else {
1160
+ const revisionTable = `${model.name}Revision`;
1161
+ const missingRevisionFields = model.fields.filter(isUpdatableField).filter(
1162
+ ({ name: name2, ...field }) => field.kind !== "custom" && !this.columns[revisionTable].some(
1163
+ (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
1164
+ )
1165
+ );
1166
+ this.createRevisionFields(model, missingRevisionFields, up, down);
1167
+ const revisionFieldsToRemove = model.fields.filter(
1168
+ ({ name: name2, updatable, generated, ...field }) => !generated && field.kind !== "custom" && !updatable && !(field.kind === "relation" && field.foreignKey === "id") && this.columns[revisionTable].some(
1169
+ (col) => col.name === (field.kind === "relation" ? field.foreignKey || `${name2}Id` : name2)
1170
+ )
1171
+ );
1172
+ this.createRevisionFields(model, revisionFieldsToRemove, down, up);
1173
+ }
868
1174
  }
869
1175
  }
870
1176
  }
871
- for (const model of getModels(rawModels)) {
1177
+ for (const model of models.entities) {
872
1178
  if (tables.includes(model.name)) {
873
1179
  this.createFields(
874
1180
  model,
@@ -876,10 +1182,10 @@ var MigrationGenerator = class {
876
1182
  down,
877
1183
  up
878
1184
  );
879
- if (model.updatable) {
1185
+ if (isUpdatableModel(model)) {
880
1186
  this.createRevisionFields(
881
1187
  model,
882
- model.fields.filter(({ deleted, updatable }) => updatable && deleted),
1188
+ model.fields.filter(isUpdatableField).filter(({ deleted }) => deleted),
883
1189
  down,
884
1190
  up
885
1191
  );
@@ -887,7 +1193,7 @@ var MigrationGenerator = class {
887
1193
  }
888
1194
  }
889
1195
  this.createEnums(
890
- rawModels.filter(isEnumModel).filter((enm2) => enm2.deleted),
1196
+ this.models.enums.filter((enm2) => enm2.deleted),
891
1197
  down,
892
1198
  up
893
1199
  );
@@ -995,8 +1301,8 @@ var MigrationGenerator = class {
995
1301
  }
996
1302
  });
997
1303
  });
998
- if (model.updatable) {
999
- const updatableFields = fields2.filter(({ updatable }) => updatable);
1304
+ if (isUpdatableModel(model)) {
1305
+ const updatableFields = fields2.filter(isUpdatableField);
1000
1306
  if (!updatableFields.length) {
1001
1307
  return;
1002
1308
  }
@@ -1024,15 +1330,15 @@ var MigrationGenerator = class {
1024
1330
  const writer = this.writer;
1025
1331
  this.createTable(`${model.name}Revision`, () => {
1026
1332
  writer.writeLine(`table.uuid('id').notNullable().primary();`);
1027
- writer.writeLine(`table.uuid('${typeToField(model.name)}Id').notNullable();`);
1028
- writer.write(`table.uuid('createdById')`);
1029
- writer.write(".notNullable()");
1030
- writer.write(";").newLine();
1031
- writer.writeLine(`table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now(0));`);
1032
- if (model.deletable) {
1033
- writer.writeLine(`table.boolean('deleted').notNullable();`);
1333
+ if (!model.parent) {
1334
+ writer.writeLine(`table.uuid('${typeToField(model.name)}Id').notNullable();`);
1335
+ writer.writeLine(`table.uuid('createdById').notNullable();`);
1336
+ writer.writeLine(`table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now(0));`);
1337
+ if (model.deletable) {
1338
+ writer.writeLine(`table.boolean('deleted').notNullable();`);
1339
+ }
1034
1340
  }
1035
- for (const field of model.fields.filter((field2) => field2.updatable)) {
1341
+ for (const field of model.fields.filter(and(isUpdatableField, not(isInherited)))) {
1036
1342
  this.column(field, { setUnique: false, setDefault: false });
1037
1343
  }
1038
1344
  });
@@ -1080,7 +1386,7 @@ var MigrationGenerator = class {
1080
1386
  `await knex.raw(\`CREATE TYPE "${name2}" AS ENUM (${enm2.values.map((value2) => `'${value2}'`).join(",")})\`);`
1081
1387
  ).newLine()
1082
1388
  );
1083
- down.push(() => this.writer.writeLine(`await knex.raw('DROP TYPE "${name2}"')`));
1389
+ down.push(() => this.writer.writeLine(`await knex.raw('DROP TYPE "${name2}"');`));
1084
1390
  }
1085
1391
  }
1086
1392
  migration(name2, cbs) {
@@ -1160,7 +1466,7 @@ var MigrationGenerator = class {
1160
1466
  if (field.double) {
1161
1467
  col(`table.double('${name2}')`);
1162
1468
  } else {
1163
- col(`table.decimal('${name2}', ${get(field, "precision")}, ${get(field, "scale")})`);
1469
+ col(`table.decimal('${name2}', ${field.precision ?? "undefined"}, ${field.scale ?? "undefined"})`);
1164
1470
  }
1165
1471
  break;
1166
1472
  case "String":
@@ -1181,14 +1487,16 @@ var MigrationGenerator = class {
1181
1487
  }
1182
1488
  break;
1183
1489
  case "relation":
1184
- col(`table.uuid('${name2}Id')`);
1490
+ col(`table.uuid('${field.foreignKey}')`);
1185
1491
  if (foreign && !alter) {
1186
- this.writer.writeLine(`table.foreign('${name2}Id').references('id').inTable('${field.type}');`);
1492
+ this.writer.writeLine(
1493
+ `table.foreign('${field.foreignKey}').references('id').inTable('${field.type}').onDelete('CASCADE');`
1494
+ );
1187
1495
  }
1188
1496
  break;
1189
1497
  case "enum":
1190
1498
  if (list2) {
1191
- this.writer.write(`table.specificType('${name2}', '"${typeToField(field.type)}"[]');`);
1499
+ this.writer.write(`table.specificType('${name2}', '"${typeToField(field.type)}"[]')`);
1192
1500
  } else {
1193
1501
  this.writer.write(`table.enum('${name2}', null as any, `).inlineBlock(() => {
1194
1502
  this.writer.writeLine(`useNative: true,`);
@@ -1252,7 +1560,9 @@ var PermissionError = class extends ForbiddenError {
1252
1560
  // src/resolvers/utils.ts
1253
1561
  var import_crypto = require("crypto");
1254
1562
  var import_graphql3 = require("graphql");
1563
+ var import_lodash4 = require("lodash");
1255
1564
  var ID_ALIAS = "ID";
1565
+ var TYPE_ALIAS = "TYPE";
1256
1566
  var getTypeName = (t) => {
1257
1567
  switch (t.kind) {
1258
1568
  case "ListType":
@@ -1278,18 +1588,16 @@ var isFragmentSpreadNode = (n) => n.kind === import_graphql3.Kind.FRAGMENT_SPREA
1278
1588
  var getType = (schema, name2) => get(schema.getType(name2), "astNode");
1279
1589
  var getFragmentTypeName = (node) => get(get(node.typeCondition, "name"), "value");
1280
1590
  function hydrate(node, raw) {
1281
- const tableAlias = node.tableAlias;
1591
+ const resultAlias = node.resultAlias;
1282
1592
  const res = raw.map((entry) => {
1283
1593
  const res2 = {};
1284
1594
  outer:
1285
1595
  for (const [column, value2] of Object.entries(entry)) {
1286
1596
  let current = res2;
1287
- const shortParts = column.split("__");
1288
- const fieldName = shortParts.pop();
1289
- const columnWithoutField = shortParts.join("__");
1597
+ const [, columnWithoutField, fieldName] = column.match(/^(.*\w)__(\w+)$/);
1290
1598
  const longColumn = node.ctx.aliases.getLong(columnWithoutField);
1291
- const longColumnWithoutRoot = longColumn.replace(new RegExp(`^${tableAlias}(__)?`), "");
1292
- const allParts = [tableAlias, ...longColumnWithoutRoot ? longColumnWithoutRoot.split("__") : [], fieldName];
1599
+ const longColumnWithoutRoot = longColumn.replace(new RegExp(`^${resultAlias}(__)?`), "");
1600
+ const allParts = [resultAlias, ...longColumnWithoutRoot ? longColumnWithoutRoot.split("__") : [], fieldName];
1293
1601
  for (let i = 0; i < allParts.length - 1; i++) {
1294
1602
  const part = allParts[i];
1295
1603
  if (!current[part]) {
@@ -1303,7 +1611,7 @@ function hydrate(node, raw) {
1303
1611
  }
1304
1612
  current[it(fieldName)] = value2;
1305
1613
  }
1306
- return res2[tableAlias];
1614
+ return res2[resultAlias];
1307
1615
  });
1308
1616
  return res;
1309
1617
  }
@@ -1312,12 +1620,12 @@ var ors = (query, [first, ...rest]) => {
1312
1620
  return query;
1313
1621
  }
1314
1622
  return query.where((subQuery) => {
1315
- subQuery.where((subSubQuery) => {
1316
- first(subSubQuery);
1623
+ void subQuery.where((subSubQuery) => {
1624
+ void first(subSubQuery);
1317
1625
  });
1318
1626
  for (const cb of rest) {
1319
- subQuery.orWhere((subSubQuery) => {
1320
- cb(subSubQuery);
1627
+ void subQuery.orWhere((subSubQuery) => {
1628
+ void cb(subSubQuery);
1321
1629
  });
1322
1630
  }
1323
1631
  });
@@ -1331,15 +1639,26 @@ var getNameOrAlias = (node) => {
1331
1639
  };
1332
1640
  var apply = (target, ops) => ops.reduce((target2, op) => op(target2), target);
1333
1641
  var applyJoins = (aliases, query, joins) => {
1334
- for (const [tableName, { table1Alias, column1, column2 }] of Object.entries(joins)) {
1335
- const [table, alias] = tableName.split(":");
1642
+ for (const { table1Alias, table2Name, table2Alias, column1, column2 } of joins) {
1336
1643
  const table1ShortAlias = aliases.getShort(table1Alias);
1337
- const table2ShortAlias = aliases.getShort(alias);
1338
- query.leftJoin(`${table} as ${table2ShortAlias}`, `${table1ShortAlias}.${column1}`, `${table2ShortAlias}.${column2}`);
1644
+ const table2ShortAlias = aliases.getShort(table2Alias);
1645
+ void query.leftJoin(
1646
+ `${table2Name} as ${table2ShortAlias}`,
1647
+ `${table1ShortAlias}.${column1}`,
1648
+ `${table2ShortAlias}.${column2}`
1649
+ );
1339
1650
  }
1340
1651
  };
1341
- var addJoin = (joins, table1Alias, table2, alias2, column1, column2) => {
1342
- joins[`${table2}:${alias2}`] ||= { table1Alias, column1, column2 };
1652
+ var addJoin = (joins, table1Alias, table2Name, table2Alias, column1, column2) => {
1653
+ const join = { table1Alias, table2Name, table2Alias, column1, column2 };
1654
+ const existingJoin = joins.find((j) => j.table2Alias === join.table2Alias);
1655
+ if (existingJoin) {
1656
+ if (!(0, import_lodash4.isEqual)(existingJoin, join)) {
1657
+ throw new Error(`Join collision: ${existingJoin}, ${join}`);
1658
+ }
1659
+ } else {
1660
+ joins.push(join);
1661
+ }
1343
1662
  };
1344
1663
  var AliasGenerator = class {
1345
1664
  reverse = {};
@@ -1362,6 +1681,11 @@ var AliasGenerator = class {
1362
1681
  }
1363
1682
  };
1364
1683
  var hash = (s) => (0, import_crypto.createHash)("md5").update(JSON.stringify(s)).digest("hex");
1684
+ var getColumnName = (field) => field.kind === "relation" ? field.foreignKey || `${field.name}Id` : field.name;
1685
+ var getColumn = (node, key) => {
1686
+ const field = node.model.fields.find((field2) => getColumnName(field2) === key);
1687
+ return `${node.ctx.aliases.getShort(field.inherited ? node.rootTableAlias : node.tableAlias)}.${key}`;
1688
+ };
1365
1689
 
1366
1690
  // src/permissions/check.ts
1367
1691
  var getPermissionStack = (ctx, type, action) => {
@@ -1406,7 +1730,7 @@ var applyPermissions = (ctx, type, tableAlias, query, action, verifiedPermission
1406
1730
  return permissionStack;
1407
1731
  };
1408
1732
  var getEntityToMutate = async (ctx, model, where, action) => {
1409
- const query = ctx.knex(model.name).where(where).first();
1733
+ const query = ctx.knex(model.parent || model.name).where(where).first();
1410
1734
  let entity = await query.clone();
1411
1735
  if (!entity) {
1412
1736
  console.error(
@@ -1422,6 +1746,10 @@ var getEntityToMutate = async (ctx, model, where, action) => {
1422
1746
  );
1423
1747
  throw new PermissionError(action, `this ${model.name}`, "no available permissions applied");
1424
1748
  }
1749
+ if (model.parent) {
1750
+ const subEntity = await ctx.knex(model.name).where({ id: entity.id }).first();
1751
+ Object.assign(entity, subEntity);
1752
+ }
1425
1753
  return entity;
1426
1754
  };
1427
1755
  var checkCanWrite = async (ctx, model, data, action) => {
@@ -1430,7 +1758,7 @@ var checkCanWrite = async (ctx, model, data, action) => {
1430
1758
  return;
1431
1759
  }
1432
1760
  if (permissionStack === false) {
1433
- throw new PermissionError(action, getModelPlural(model), "no applicable permissions");
1761
+ throw new PermissionError(action, model.plural, "no applicable permissions");
1434
1762
  }
1435
1763
  const query = ctx.knex.select(1).first();
1436
1764
  let linked = false;
@@ -1478,10 +1806,10 @@ var permissionLinkQuery = (ctx, subQuery, links, id) => {
1478
1806
  subQuery.where({ [`${alias}.id`]: ctx.user.id });
1479
1807
  }
1480
1808
  if (where) {
1481
- applyWhere(summonByName(ctx.models, type), subQuery, alias, where, aliases);
1809
+ applyWhere(ctx.models.getModel(type, "entity"), subQuery, alias, where, aliases);
1482
1810
  }
1483
1811
  for (const { type: type2, foreignKey, reverse, where: where2 } of links) {
1484
- const model = summonByName(ctx.models, type2);
1812
+ const model = ctx.models.getModel(type2, "entity");
1485
1813
  const subAlias = aliases.getShort();
1486
1814
  if (reverse) {
1487
1815
  subQuery.leftJoin(`${type2} as ${subAlias}`, `${alias}.${foreignKey || "id"}`, `${subAlias}.id`);
@@ -1502,11 +1830,11 @@ var applyWhere = (model, query, alias, where, aliases) => {
1502
1830
  if (relation) {
1503
1831
  const subAlias = aliases.getShort();
1504
1832
  query.leftJoin(
1505
- `${relation.model.name} as ${subAlias}`,
1833
+ `${relation.targetModel.name} as ${subAlias}`,
1506
1834
  `${alias}.${relation.field.foreignKey || `${relation.field.name}Id`}`,
1507
1835
  `${subAlias}.id`
1508
1836
  );
1509
- applyWhere(relation.model, query, subAlias, value2, aliases);
1837
+ applyWhere(relation.targetModel, query, subAlias, value2, aliases);
1510
1838
  } else if (Array.isArray(value2)) {
1511
1839
  query.whereIn(`${alias}.${key}`, value2);
1512
1840
  } else {
@@ -1554,7 +1882,7 @@ var generatePermissions = (models, config) => {
1554
1882
  };
1555
1883
  var addPermissions = (models, permissions, links, block) => {
1556
1884
  const { type } = links[links.length - 1];
1557
- const model = summonByName(models, type);
1885
+ const model = models.getModel(type, "entity");
1558
1886
  for (const action of ACTIONS) {
1559
1887
  if (action === "READ" || action in block) {
1560
1888
  if (!permissions[type]) {
@@ -1579,13 +1907,13 @@ var addPermissions = (models, permissions, links, block) => {
1579
1907
  reverse: true
1580
1908
  };
1581
1909
  } else {
1582
- const field2 = model.reverseRelationsByName[relation];
1583
- if (!field2) {
1910
+ const reverseRelation = model.reverseRelationsByName[relation];
1911
+ if (!reverseRelation) {
1584
1912
  throw new Error(`Relation ${relation} in model ${model.name} does not exist.`);
1585
1913
  }
1586
1914
  link = {
1587
- type: field2.model.name,
1588
- foreignKey: field2.foreignKey
1915
+ type: reverseRelation.targetModel.name,
1916
+ foreignKey: reverseRelation.field.foreignKey
1589
1917
  };
1590
1918
  }
1591
1919
  if (subBlock.WHERE) {
@@ -1730,13 +2058,18 @@ var applyFilters = (node, query, joins) => {
1730
2058
  if (orderBy) {
1731
2059
  applyOrderBy(node, orderBy, query);
1732
2060
  }
2061
+ if (node.model.parent) {
2062
+ void query.where({
2063
+ [getColumn(node, "type")]: node.model.name
2064
+ });
2065
+ }
1733
2066
  if (where) {
1734
2067
  const ops = [];
1735
2068
  applyWhere2(node, where, ops, joins);
1736
- apply(query, ops);
2069
+ void apply(query, ops);
1737
2070
  }
1738
2071
  if (search) {
1739
- applySearch(node, search, query);
2072
+ void applySearch(node, search, query);
1740
2073
  }
1741
2074
  };
1742
2075
  var applyWhere2 = (node, where, ops, joins) => {
@@ -1748,34 +2081,34 @@ var applyWhere2 = (node, where, ops, joins) => {
1748
2081
  if (!SPECIAL_FILTERS[filter]) {
1749
2082
  throw new Error(`Invalid filter ${key}.`);
1750
2083
  }
1751
- ops.push(
1752
- (query) => query.whereRaw(SPECIAL_FILTERS[filter], [`${node.shortTableAlias}.${actualKey}`, value2])
1753
- );
2084
+ ops.push((query) => query.whereRaw(SPECIAL_FILTERS[filter], [getColumn(node, actualKey), value2]));
1754
2085
  continue;
1755
2086
  }
1756
- const field = summonByName(node.model.fields, key);
1757
- const fullKey = `${node.shortTableAlias}.${key}`;
2087
+ const field = node.model.getField(key);
1758
2088
  if (field.kind === "relation") {
1759
- const relation = get(node.model.relationsByName, field.name);
1760
- const tableAlias = `${node.model.name}__W__${key}`;
2089
+ const relation = node.model.getRelation(field.name);
2090
+ const targetModel = relation.targetModel;
2091
+ const rootModel = targetModel.parentModel || targetModel;
2092
+ const rootTableAlias = `${node.model.name}__W__${key}`;
2093
+ const tableAlias = targetModel === rootModel ? rootTableAlias : `${node.model.name}__WS__${key}`;
1761
2094
  const subNode = {
1762
2095
  ctx: node.ctx,
1763
- model: relation.model,
1764
- tableName: relation.model.name,
1765
- tableAlias,
1766
- shortTableAlias: node.ctx.aliases.getShort(tableAlias),
1767
- foreignKey: relation.field.foreignKey
2096
+ rootModel,
2097
+ rootTableAlias,
2098
+ model: targetModel,
2099
+ tableAlias
1768
2100
  };
1769
- addJoin(joins, node.tableAlias, subNode.tableName, subNode.tableAlias, get(subNode, "foreignKey"), "id");
2101
+ addJoin(joins, node.tableAlias, subNode.model.name, subNode.tableAlias, relation.field.foreignKey, "id");
1770
2102
  applyWhere2(subNode, value2, ops, joins);
1771
2103
  continue;
1772
2104
  }
2105
+ const column = getColumn(node, key);
1773
2106
  if (Array.isArray(value2)) {
1774
2107
  if (field && field.list) {
1775
2108
  ops.push(
1776
2109
  (query) => ors(
1777
2110
  query,
1778
- value2.map((v) => (subQuery) => subQuery.whereRaw("? = ANY(??)", [v, fullKey]))
2111
+ value2.map((v) => (subQuery) => subQuery.whereRaw("? = ANY(??)", [v, column]))
1779
2112
  )
1780
2113
  );
1781
2114
  continue;
@@ -1784,25 +2117,25 @@ var applyWhere2 = (node, where, ops, joins) => {
1784
2117
  if (value2.some((v) => v !== null)) {
1785
2118
  ops.push(
1786
2119
  (query) => ors(query, [
1787
- (subQuery) => subQuery.whereIn(fullKey, value2.filter((v) => v !== null)),
1788
- (subQuery) => subQuery.whereNull(fullKey)
2120
+ (subQuery) => subQuery.whereIn(column, value2.filter((v) => v !== null)),
2121
+ (subQuery) => subQuery.whereNull(column)
1789
2122
  ])
1790
2123
  );
1791
2124
  continue;
1792
2125
  }
1793
- ops.push((query) => query.whereNull(fullKey));
2126
+ ops.push((query) => query.whereNull(column));
1794
2127
  continue;
1795
2128
  }
1796
- ops.push((query) => query.whereIn(fullKey, value2));
2129
+ ops.push((query) => query.whereIn(column, value2));
1797
2130
  continue;
1798
2131
  }
1799
- ops.push((query) => query.where({ [fullKey]: value2 }));
2132
+ ops.push((query) => query.where({ [column]: value2 }));
1800
2133
  }
1801
2134
  };
1802
2135
  var applySearch = (node, search, query) => ors(
1803
2136
  query,
1804
2137
  node.model.fields.filter(({ searchable }) => searchable).map(
1805
- ({ name: name2 }) => (query2) => query2.whereILike(`${node.shortTableAlias}.${name2}`, `%${search}%`)
2138
+ ({ name: name2 }) => (query2) => query2.whereILike(getColumn(node, name2), `%${search}%`)
1806
2139
  )
1807
2140
  );
1808
2141
  var applyOrderBy = (node, orderBy, query) => {
@@ -1813,7 +2146,7 @@ var applyOrderBy = (node, orderBy, query) => {
1813
2146
  }
1814
2147
  const key = keys[0];
1815
2148
  const value2 = vals[key];
1816
- query.orderBy(`${node.shortTableAlias}.${key}`, value2);
2149
+ void query.orderBy(getColumn(node, key), value2);
1817
2150
  }
1818
2151
  };
1819
2152
 
@@ -1829,19 +2162,26 @@ var getResolverNode = ({
1829
2162
  ctx,
1830
2163
  node,
1831
2164
  tableAlias,
2165
+ rootTableAlias,
2166
+ resultAlias,
1832
2167
  baseTypeDefinition,
1833
2168
  typeName
1834
- }) => ({
1835
- ctx,
1836
- tableName: typeName,
1837
- tableAlias,
1838
- shortTableAlias: ctx.aliases.getShort(tableAlias),
1839
- baseTypeDefinition,
1840
- baseModel: ctx.models.find((model) => model.name === baseTypeDefinition.name.value),
1841
- typeDefinition: getType(ctx.info.schema, typeName),
1842
- model: summonByName(ctx.models, typeName),
1843
- selectionSet: get(node.selectionSet, "selections")
1844
- });
2169
+ }) => {
2170
+ const model = ctx.models.getModel(typeName, "entity");
2171
+ const rootModel = model.parent ? ctx.models.getModel(model.parent, "entity") : model;
2172
+ return {
2173
+ ctx,
2174
+ rootModel,
2175
+ rootTableAlias,
2176
+ model,
2177
+ tableAlias,
2178
+ resultAlias,
2179
+ baseTypeDefinition,
2180
+ baseModel: ctx.models.entities.find((model2) => model2.name === baseTypeDefinition.name.value),
2181
+ typeDefinition: getType(ctx.info.schema, typeName),
2182
+ selectionSet: get(node.selectionSet, "selections")
2183
+ };
2184
+ };
1845
2185
  var getRootFieldNode = ({
1846
2186
  ctx,
1847
2187
  node,
@@ -1850,14 +2190,17 @@ var getRootFieldNode = ({
1850
2190
  const fieldName = node.name.value;
1851
2191
  const fieldDefinition = summonByKey(baseTypeDefinition.fields || [], "name.value", fieldName);
1852
2192
  const typeName = getTypeName(fieldDefinition.type);
2193
+ const model = ctx.models.getModel(typeName, "entity");
2194
+ const rootModel = model.parent ? ctx.models.getModel(model.parent, "entity") : model;
1853
2195
  return {
1854
2196
  ctx,
1855
- tableName: typeName,
1856
- tableAlias: typeName,
1857
- shortTableAlias: ctx.aliases.getShort(typeName),
2197
+ rootModel,
2198
+ rootTableAlias: rootModel.name,
2199
+ model,
2200
+ tableAlias: model.name,
2201
+ resultAlias: rootModel.name,
1858
2202
  baseTypeDefinition,
1859
2203
  typeDefinition: getType(ctx.info.schema, typeName),
1860
- model: summonByName(ctx.models, typeName),
1861
2204
  selectionSet: get(node.selectionSet, "selections"),
1862
2205
  field: node,
1863
2206
  fieldDefinition,
@@ -1876,7 +2219,9 @@ var getInlineFragments = (node) => node.selectionSet.filter(isInlineFragmentNode
1876
2219
  (subNode) => getResolverNode({
1877
2220
  ctx: node.ctx,
1878
2221
  node: subNode,
2222
+ rootTableAlias: node.rootTableAlias,
1879
2223
  tableAlias: node.tableAlias + "__" + getFragmentTypeName(subNode),
2224
+ resultAlias: node.resultAlias,
1880
2225
  baseTypeDefinition: node.baseTypeDefinition,
1881
2226
  typeName: getFragmentTypeName(subNode)
1882
2227
  })
@@ -1885,7 +2230,9 @@ var getFragmentSpreads = (node) => node.selectionSet.filter(isFragmentSpreadNode
1885
2230
  (subNode) => getResolverNode({
1886
2231
  ctx: node.ctx,
1887
2232
  node: node.ctx.info.fragments[subNode.name.value],
2233
+ rootTableAlias: node.rootTableAlias,
1888
2234
  tableAlias: node.tableAlias,
2235
+ resultAlias: node.resultAlias,
1889
2236
  baseTypeDefinition: node.baseTypeDefinition,
1890
2237
  typeName: node.model.name
1891
2238
  })
@@ -1899,44 +2246,90 @@ var getJoins = (node, toMany) => {
1899
2246
  const fieldNameOrAlias = getNameOrAlias(subNode);
1900
2247
  const fieldDefinition = summonByKey(baseTypeDefinition.fields || [], "name.value", fieldName);
1901
2248
  const typeName = getTypeName(fieldDefinition.type);
1902
- if (isObjectModel(summonByName(ctx.rawModels, typeName))) {
2249
+ if (isObjectModel(ctx.models.getModel(typeName))) {
1903
2250
  continue;
1904
2251
  }
1905
- const baseModel = summonByName(ctx.models, baseTypeDefinition.name.value);
1906
- let foreignKey;
1907
- if (toMany) {
1908
- const reverseRelation = baseModel.reverseRelationsByName[fieldName];
1909
- if (!reverseRelation) {
1910
- continue;
1911
- }
1912
- foreignKey = reverseRelation.foreignKey;
1913
- } else {
1914
- const modelField = baseModel.fieldsByName[fieldName];
1915
- if (modelField?.kind !== "relation") {
1916
- continue;
1917
- }
1918
- foreignKey = modelField.foreignKey;
2252
+ const baseModel = ctx.models.getModel(baseTypeDefinition.name.value, "entity");
2253
+ const relation = (toMany ? baseModel.reverseRelationsByName : baseModel.relationsByName)[fieldName];
2254
+ if (!relation) {
2255
+ continue;
1919
2256
  }
1920
2257
  const tableAlias = node.tableAlias + "__" + fieldNameOrAlias;
2258
+ const model = ctx.models.getModel(typeName, "entity");
2259
+ const rootModel = model;
1921
2260
  nodes.push({
1922
2261
  ctx,
1923
- tableName: typeName,
2262
+ rootModel,
2263
+ rootTableAlias: tableAlias,
2264
+ model,
1924
2265
  tableAlias,
1925
- shortTableAlias: ctx.aliases.getShort(tableAlias),
2266
+ resultAlias: tableAlias,
1926
2267
  baseTypeDefinition,
1927
2268
  baseModel,
1928
2269
  typeDefinition: getType(ctx.info.schema, typeName),
1929
- model: summonByName(ctx.models, typeName),
1930
2270
  selectionSet: get(subNode.selectionSet, "selections"),
1931
2271
  field: subNode,
1932
2272
  fieldDefinition,
1933
- foreignKey,
2273
+ relation,
2274
+ foreignKey: relation.field.foreignKey,
1934
2275
  isList: isListType(fieldDefinition.type)
1935
2276
  });
1936
2277
  }
1937
2278
  return nodes;
1938
2279
  };
1939
2280
 
2281
+ // src/resolvers/selects.ts
2282
+ var applySelects = (node, query, joins) => {
2283
+ void query.select(
2284
+ ...[
2285
+ { tableAlias: node.rootTableAlias, resultAlias: node.resultAlias, field: "id", fieldAlias: ID_ALIAS },
2286
+ ...node.model.root ? [{ tableAlias: node.rootTableAlias, resultAlias: node.resultAlias, field: "type", fieldAlias: TYPE_ALIAS }] : [],
2287
+ ...getSimpleFields(node).filter((fieldNode) => {
2288
+ const field = node.model.fieldsByName[fieldNode.name.value];
2289
+ if (!field || field.kind === "relation" || field.kind === "custom") {
2290
+ return false;
2291
+ }
2292
+ if (typeof field.queriable === "object" && !field.queriable.roles?.includes(node.ctx.user.role)) {
2293
+ throw new PermissionError(
2294
+ "READ",
2295
+ `${node.model.name}'s field "${field.name}"`,
2296
+ "field permission not available"
2297
+ );
2298
+ }
2299
+ return true;
2300
+ }).map((fieldNode) => {
2301
+ const field = node.model.getField(fieldNode.name.value);
2302
+ if (node.model.parent && !field.inherited) {
2303
+ addJoin(joins, node.rootTableAlias, node.model.name, node.tableAlias, "id", "id");
2304
+ }
2305
+ const fieldAlias = getNameOrAlias(fieldNode);
2306
+ if ([ID_ALIAS, TYPE_ALIAS].includes(fieldAlias)) {
2307
+ throw new UserInputError(`Keyword ${fieldAlias} is reserved by graphql-magic.`);
2308
+ }
2309
+ return {
2310
+ fieldNode,
2311
+ field: fieldNode.name.value,
2312
+ tableAlias: field.inherited ? node.rootTableAlias : node.tableAlias,
2313
+ resultAlias: node.resultAlias,
2314
+ fieldAlias
2315
+ };
2316
+ })
2317
+ ].map(
2318
+ ({ tableAlias, resultAlias, field, fieldAlias }) => `${node.ctx.aliases.getShort(tableAlias)}.${field} as ${node.ctx.aliases.getShort(resultAlias)}__${fieldAlias}`
2319
+ )
2320
+ );
2321
+ for (const subNode of getInlineFragments(node)) {
2322
+ applySelects(subNode, query, joins);
2323
+ }
2324
+ for (const subNode of getFragmentSpreads(node)) {
2325
+ applySelects(subNode, query, joins);
2326
+ }
2327
+ for (const subNode of getJoins(node, false)) {
2328
+ addJoin(joins, node.tableAlias, subNode.rootModel.name, subNode.rootTableAlias, subNode.foreignKey, "id");
2329
+ applySelects(subNode, query, joins);
2330
+ }
2331
+ };
2332
+
1940
2333
  // src/resolvers/resolver.ts
1941
2334
  var queryResolver = (_parent, _args, ctx, info) => resolve({ ...ctx, info, aliases: new AliasGenerator() });
1942
2335
  var resolve = async (ctx, id) => {
@@ -1952,13 +2345,13 @@ var resolve = async (ctx, id) => {
1952
2345
  });
1953
2346
  const { query, verifiedPermissionStacks } = await buildQuery(node);
1954
2347
  if (ctx.info.fieldName === "me") {
1955
- query.where({ [`${node.shortTableAlias}.id`]: node.ctx.user.id });
1956
- }
1957
- if (!node.isList) {
1958
- query.limit(1);
2348
+ void query.where({ [getColumn(node, "id")]: node.ctx.user.id });
1959
2349
  }
1960
2350
  if (id) {
1961
- query.where({ id });
2351
+ void query.where({ [getColumn(node, "id")]: id });
2352
+ }
2353
+ if (!node.isList) {
2354
+ void query.limit(1);
1962
2355
  }
1963
2356
  const raw = await query;
1964
2357
  const res = hydrate(node, raw);
@@ -1973,20 +2366,19 @@ var resolve = async (ctx, id) => {
1973
2366
  return res[0];
1974
2367
  };
1975
2368
  var buildQuery = async (node, parentVerifiedPermissionStacks) => {
1976
- const { tableAlias, shortTableAlias, tableName, model, ctx } = node;
1977
- const query = ctx.knex.fromRaw(`"${tableName}" as "${shortTableAlias}"`);
1978
- const joins = {};
2369
+ const query = node.ctx.knex.fromRaw(`"${node.rootModel.name}" as "${node.ctx.aliases.getShort(node.resultAlias)}"`);
2370
+ const joins = [];
1979
2371
  applyFilters(node, query, joins);
1980
2372
  applySelects(node, query, joins);
1981
2373
  applyJoins(node.ctx.aliases, query, joins);
1982
2374
  const tables = [
1983
- [model.name, tableAlias],
1984
- ...Object.keys(joins).map((tableName2) => tableName2.split(":"))
2375
+ [node.rootModel.name, node.rootTableAlias],
2376
+ ...joins.map(({ table2Name, table2Alias }) => [table2Name, table2Alias])
1985
2377
  ];
1986
2378
  const verifiedPermissionStacks = {};
1987
2379
  for (const [table, alias] of tables) {
1988
2380
  const verifiedPermissionStack = applyPermissions(
1989
- ctx,
2381
+ node.ctx,
1990
2382
  table,
1991
2383
  node.ctx.aliases.getShort(alias),
1992
2384
  query,
@@ -1999,39 +2391,6 @@ var buildQuery = async (node, parentVerifiedPermissionStacks) => {
1999
2391
  }
2000
2392
  return { query, verifiedPermissionStacks };
2001
2393
  };
2002
- var applySelects = (node, query, joins) => {
2003
- query.select(
2004
- ...[
2005
- { field: "id", alias: ID_ALIAS },
2006
- ...getSimpleFields(node).filter((n) => {
2007
- const field = node.model.fields.find(({ name: name2 }) => name2 === n.name.value);
2008
- if (!field || field.kind === "relation" || field.kind === "custom") {
2009
- return false;
2010
- }
2011
- if (typeof field.queriable === "object" && !field.queriable.roles?.includes(node.ctx.user.role)) {
2012
- throw new PermissionError(
2013
- "READ",
2014
- `${node.model.name}'s field "${field.name}"`,
2015
- "field permission not available"
2016
- );
2017
- }
2018
- return true;
2019
- }).map((n) => ({ field: n.name.value, alias: getNameOrAlias(n) }))
2020
- ].map(
2021
- ({ field, alias }) => `${node.shortTableAlias}.${field} as ${node.shortTableAlias}__${alias}`
2022
- )
2023
- );
2024
- for (const subNode of getInlineFragments(node)) {
2025
- applySelects(subNode, query, joins);
2026
- }
2027
- for (const subNode of getFragmentSpreads(node)) {
2028
- applySelects(subNode, query, joins);
2029
- }
2030
- for (const subNode of getJoins(node, false)) {
2031
- addJoin(joins, node.tableAlias, subNode.tableName, subNode.tableAlias, get(subNode, "foreignKey"), "id");
2032
- applySelects(subNode, query, joins);
2033
- }
2034
- };
2035
2394
  var applySubQueries = async (node, entries, parentVerifiedPermissionStacks) => {
2036
2395
  if (!entries.length) {
2037
2396
  return;
@@ -2048,10 +2407,12 @@ var applySubQueries = async (node, entries, parentVerifiedPermissionStacks) => {
2048
2407
  const fieldName = getNameOrAlias(subNode.field);
2049
2408
  const isList = isListType(subNode.fieldDefinition.type);
2050
2409
  entries.forEach((entry) => entry[fieldName] = isList ? [] : null);
2051
- const foreignKey = get(subNode, "foreignKey");
2410
+ const foreignKey = subNode.foreignKey;
2052
2411
  const { query, verifiedPermissionStacks } = await buildQuery(subNode, parentVerifiedPermissionStacks);
2412
+ const shortTableAlias = subNode.ctx.aliases.getShort(subNode.tableAlias);
2413
+ const shortResultAlias = subNode.ctx.aliases.getShort(subNode.resultAlias);
2053
2414
  const queries = ids.map(
2054
- (id) => query.clone().select(`${subNode.shortTableAlias}.${foreignKey} as ${subNode.shortTableAlias}__${foreignKey}`).where({ [`${subNode.shortTableAlias}.${foreignKey}`]: id })
2415
+ (id) => query.clone().select(`${shortTableAlias}.${foreignKey} as ${shortResultAlias}__${foreignKey}`).where({ [`${shortTableAlias}.${foreignKey}`]: id })
2055
2416
  );
2056
2417
  const rawChildren = (await Promise.all(queries)).flat();
2057
2418
  const children = hydrate(subNode, rawChildren);
@@ -2095,7 +2456,7 @@ var mutationResolver = async (_parent, args2, partialCtx, info) => {
2095
2456
  return await partialCtx.knex.transaction(async (knex) => {
2096
2457
  const [, mutation, modelName] = it(info.fieldName.match(/^(create|update|delete|restore)(.+)$/));
2097
2458
  const ctx = { ...partialCtx, knex, info, aliases: new AliasGenerator() };
2098
- const model = summonByName(ctx.models, modelName);
2459
+ const model = ctx.models.getModel(modelName, "entity");
2099
2460
  switch (mutation) {
2100
2461
  case "create":
2101
2462
  return await create(model, args2, ctx);
@@ -2113,12 +2474,32 @@ var create = async (model, { data: input2 }, ctx) => {
2113
2474
  normalizedInput.id = (0, import_uuid.v4)();
2114
2475
  normalizedInput.createdAt = ctx.now;
2115
2476
  normalizedInput.createdById = ctx.user.id;
2477
+ if (model.parent) {
2478
+ normalizedInput.type = model.name;
2479
+ }
2116
2480
  sanitize(ctx, model, normalizedInput);
2117
2481
  await checkCanWrite(ctx, model, normalizedInput, "CREATE");
2118
2482
  await ctx.handleUploads?.(normalizedInput);
2119
2483
  const data = { prev: {}, input: input2, normalizedInput, next: normalizedInput };
2120
2484
  await ctx.mutationHook?.(model, "create", "before", data, ctx);
2121
- await ctx.knex(model.name).insert(normalizedInput);
2485
+ if (model.parent) {
2486
+ const rootInput = {};
2487
+ const childInput = { id: normalizedInput.id };
2488
+ for (const field of model.fields) {
2489
+ const columnName = field.kind === "relation" ? `${field.name}Id` : field.name;
2490
+ if (columnName in normalizedInput) {
2491
+ if (field.inherited) {
2492
+ rootInput[columnName] = normalizedInput[columnName];
2493
+ } else {
2494
+ childInput[columnName] = normalizedInput[columnName];
2495
+ }
2496
+ }
2497
+ }
2498
+ await ctx.knex(model.parent).insert(rootInput);
2499
+ await ctx.knex(model.name).insert(childInput);
2500
+ } else {
2501
+ await ctx.knex(model.name).insert(normalizedInput);
2502
+ }
2122
2503
  await createRevision(model, normalizedInput, ctx);
2123
2504
  await ctx.mutationHook?.(model, "create", "after", data, ctx);
2124
2505
  return await resolve(ctx, normalizedInput.id);
@@ -2141,7 +2522,28 @@ var update = async (model, { where, data: input2 }, ctx) => {
2141
2522
  const next = { ...prev, ...normalizedInput };
2142
2523
  const data = { prev, input: input2, normalizedInput, next };
2143
2524
  await ctx.mutationHook?.(model, "update", "before", data, ctx);
2144
- await ctx.knex(model.name).where(where).update(normalizedInput);
2525
+ if (model.parent) {
2526
+ const rootInput = {};
2527
+ const childInput = {};
2528
+ for (const field of model.fields) {
2529
+ const columnName = field.kind === "relation" ? `${field.name}Id` : field.name;
2530
+ if (columnName in normalizedInput) {
2531
+ if (field.inherited) {
2532
+ rootInput[columnName] = normalizedInput[columnName];
2533
+ } else {
2534
+ childInput[columnName] = normalizedInput[columnName];
2535
+ }
2536
+ }
2537
+ }
2538
+ if (Object.keys(rootInput).length) {
2539
+ await ctx.knex(model.parent).where({ id: prev.id }).update(rootInput);
2540
+ }
2541
+ if (Object.keys(childInput).length) {
2542
+ await ctx.knex(model.name).where({ id: prev.id }).update(childInput);
2543
+ }
2544
+ } else {
2545
+ await ctx.knex(model.name).where({ id: prev.id }).update(normalizedInput);
2546
+ }
2145
2547
  await createRevision(model, next, ctx);
2146
2548
  await ctx.mutationHook?.(model, "update", "after", data, ctx);
2147
2549
  }
@@ -2151,7 +2553,8 @@ var del = async (model, { where, dryRun }, ctx) => {
2151
2553
  if (Object.keys(where).length === 0) {
2152
2554
  throw new Error(`No ${model.name} specified.`);
2153
2555
  }
2154
- const entity = await getEntityToMutate(ctx, model, where, "DELETE");
2556
+ const rootModel = model.rootModel;
2557
+ const entity = await getEntityToMutate(ctx, rootModel, where, "DELETE");
2155
2558
  if (entity.deleted) {
2156
2559
  throw new ForbiddenError("Entity is already deleted.");
2157
2560
  }
@@ -2190,10 +2593,9 @@ var del = async (model, { where, dryRun }, ctx) => {
2190
2593
  }
2191
2594
  }
2192
2595
  for (const {
2193
- model: descendantModel,
2194
- foreignKey,
2195
- field: { name: name2, onDelete }
2196
- } of currentModel.reverseRelations) {
2596
+ targetModel: descendantModel,
2597
+ field: { name: name2, foreignKey, onDelete }
2598
+ } of currentModel.reverseRelations.filter((reverseRelation) => !reverseRelation.field.inherited)) {
2197
2599
  const query = ctx.knex(descendantModel.name).where({ [foreignKey]: entity2.id });
2198
2600
  switch (onDelete) {
2199
2601
  case "set-null": {
@@ -2235,7 +2637,7 @@ var del = async (model, { where, dryRun }, ctx) => {
2235
2637
  }
2236
2638
  }
2237
2639
  };
2238
- await deleteCascade(model, entity);
2640
+ await deleteCascade(rootModel, entity);
2239
2641
  for (const callback of [...beforeHooks, ...mutations, ...afterHooks]) {
2240
2642
  await callback();
2241
2643
  }
@@ -2252,7 +2654,8 @@ var restore = async (model, { where }, ctx) => {
2252
2654
  if (Object.keys(where).length === 0) {
2253
2655
  throw new Error(`No ${model.name} specified.`);
2254
2656
  }
2255
- const entity = await getEntityToMutate(ctx, model, where, "RESTORE");
2657
+ const rootModel = model.rootModel;
2658
+ const entity = await getEntityToMutate(ctx, rootModel, where, "RESTORE");
2256
2659
  if (!entity.deleted) {
2257
2660
  throw new ForbiddenError("Entity is not deleted.");
2258
2661
  }
@@ -2279,9 +2682,10 @@ var restore = async (model, { where }, ctx) => {
2279
2682
  await ctx.mutationHook(model, "restore", "after", data, ctx);
2280
2683
  });
2281
2684
  }
2282
- for (const { model: descendantModel, foreignKey } of currentModel.reverseRelations.filter(
2283
- ({ model: { deletable } }) => deletable
2284
- )) {
2685
+ for (const {
2686
+ targetModel: descendantModel,
2687
+ field: { foreignKey }
2688
+ } of currentModel.reverseRelations.filter((reverseRelation) => !reverseRelation.field.inherited).filter(({ targetModel: { deletable } }) => deletable)) {
2285
2689
  const query = ctx.knex(descendantModel.name).where({ [foreignKey]: relatedEntity.id });
2286
2690
  applyPermissions(ctx, descendantModel.name, descendantModel.name, query, "RESTORE");
2287
2691
  const descendants = await query;
@@ -2290,7 +2694,7 @@ var restore = async (model, { where }, ctx) => {
2290
2694
  }
2291
2695
  }
2292
2696
  };
2293
- await restoreCascade(model, entity);
2697
+ await restoreCascade(rootModel, entity);
2294
2698
  for (const callback of [...beforeHooks, ...mutations, ...afterHooks]) {
2295
2699
  await callback();
2296
2700
  }
@@ -2298,24 +2702,37 @@ var restore = async (model, { where }, ctx) => {
2298
2702
  };
2299
2703
  var createRevision = async (model, data, ctx) => {
2300
2704
  if (model.updatable) {
2301
- const revisionData = {
2302
- id: (0, import_uuid.v4)(),
2303
- [`${typeToField(model.name)}Id`]: data.id,
2705
+ const revisionId = (0, import_uuid.v4)();
2706
+ const rootRevisionData = {
2707
+ id: revisionId,
2708
+ [`${typeToField(model.parent || model.name)}Id`]: data.id,
2304
2709
  createdAt: ctx.now,
2305
2710
  createdById: ctx.user.id
2306
2711
  };
2307
2712
  if (model.deletable) {
2308
- revisionData.deleted = data.deleted || false;
2309
- }
2310
- for (const { kind: type, name: name2, nonNull: nonNull2, ...field } of model.fields.filter(({ updatable }) => updatable)) {
2311
- const col = type === "relation" ? `${name2}Id` : name2;
2312
- if (nonNull2 && (!(col in data) || col === void 0 || col === null)) {
2313
- revisionData[col] = get(field, "defaultValue");
2713
+ rootRevisionData.deleted = data.deleted || false;
2714
+ }
2715
+ const childRevisionData = { id: revisionId };
2716
+ for (const field of model.fields.filter(({ updatable }) => updatable)) {
2717
+ const col = field.kind === "relation" ? `${field.name}Id` : field.name;
2718
+ let value2;
2719
+ if (field.nonNull && (!(col in data) || col === void 0 || col === null)) {
2720
+ value2 = get(field, "defaultValue");
2721
+ } else {
2722
+ value2 = data[col];
2723
+ }
2724
+ if (!model.parent || field.inherited) {
2725
+ rootRevisionData[col] = value2;
2314
2726
  } else {
2315
- revisionData[col] = data[col];
2727
+ childRevisionData[col] = value2;
2316
2728
  }
2317
2729
  }
2318
- await ctx.knex(`${model.name}Revision`).insert(revisionData);
2730
+ if (model.parent) {
2731
+ await ctx.knex(`${model.parent}Revision`).insert(rootRevisionData);
2732
+ await ctx.knex(`${model.name}Revision`).insert(childRevisionData);
2733
+ } else {
2734
+ await ctx.knex(`${model.name}Revision`).insert(rootRevisionData);
2735
+ }
2319
2736
  }
2320
2737
  };
2321
2738
  var sanitize = (ctx, model, data) => {
@@ -2332,7 +2749,7 @@ var sanitize = (ctx, model, data) => {
2332
2749
  data[key] = data[key].endOf("day");
2333
2750
  continue;
2334
2751
  }
2335
- if (isEnumList(ctx.rawModels, field) && Array.isArray(data[key])) {
2752
+ if (field.list && field.kind === "enum" && Array.isArray(data[key])) {
2336
2753
  data[key] = `{${data[key].join(",")}}`;
2337
2754
  continue;
2338
2755
  }
@@ -2346,30 +2763,37 @@ var getResolvers = (models) => ({
2346
2763
  {
2347
2764
  me: queryResolver
2348
2765
  },
2349
- ...models.filter(({ queriable }) => queriable).map((model) => ({
2766
+ ...models.entities.filter(({ queriable }) => queriable).map((model) => ({
2350
2767
  [typeToField(model.name)]: queryResolver
2351
2768
  })),
2352
- ...models.filter(({ listQueriable }) => listQueriable).map((model) => ({
2353
- [getModelPluralField(model)]: queryResolver
2769
+ ...models.entities.filter(({ listQueriable }) => listQueriable).map((model) => ({
2770
+ [model.pluralField]: queryResolver
2354
2771
  }))
2355
2772
  ]),
2356
2773
  Mutation: merge2([
2357
- ...models.filter(({ creatable }) => creatable).map((model) => ({
2774
+ ...models.entities.filter(not(isRootModel)).filter(({ creatable }) => creatable).map((model) => ({
2358
2775
  [`create${model.name}`]: mutationResolver
2359
2776
  })),
2360
- ...models.filter(({ updatable }) => updatable).map((model) => ({
2777
+ ...models.entities.filter(not(isRootModel)).filter(({ updatable }) => updatable).map((model) => ({
2361
2778
  [`update${model.name}`]: mutationResolver
2362
2779
  })),
2363
- ...models.filter(({ deletable }) => deletable).map((model) => ({
2780
+ ...models.entities.filter(not(isRootModel)).filter(({ deletable }) => deletable).map((model) => ({
2364
2781
  [`delete${model.name}`]: mutationResolver,
2365
2782
  [`restore${model.name}`]: mutationResolver
2366
2783
  }))
2367
- ])
2784
+ ]),
2785
+ ...Object.assign(
2786
+ {},
2787
+ ...models.entities.filter(isRootModel).map((model) => ({
2788
+ [model.name]: {
2789
+ __resolveType: ({ TYPE }) => TYPE
2790
+ }
2791
+ }))
2792
+ )
2368
2793
  });
2369
2794
 
2370
2795
  // src/schema/generate.ts
2371
2796
  var import_graphql5 = require("graphql");
2372
- var import_flatMap2 = __toESM(require("lodash/flatMap"), 1);
2373
2797
 
2374
2798
  // src/schema/utils.ts
2375
2799
  var import_luxon = require("luxon");
@@ -2401,10 +2825,11 @@ var object = (nme, fds, interfaces, dvs) => ({
2401
2825
  interfaces: interfaces && interfaces.map((i) => namedType(i)),
2402
2826
  directives: directives(dvs)
2403
2827
  });
2404
- var iface = (nme, fds, dvs) => ({
2828
+ var iface = (nme, fds, interfaces, dvs) => ({
2405
2829
  name: name(nme),
2406
2830
  fields: fields(fds),
2407
2831
  kind: "InterfaceTypeDefinition",
2832
+ interfaces: interfaces && interfaces.map((i) => namedType(i)),
2408
2833
  directives: directives(dvs)
2409
2834
  });
2410
2835
  var inputValues = (fields2) => fields2.map(
@@ -2520,84 +2945,86 @@ var value = (val = null) => val === null ? {
2520
2945
  };
2521
2946
 
2522
2947
  // src/schema/generate.ts
2523
- var generateDefinitions = (rawModels) => {
2524
- const models = getModels(rawModels);
2948
+ var generateDefinitions = ({
2949
+ scalars,
2950
+ rawEnums,
2951
+ enums,
2952
+ inputs,
2953
+ interfaces,
2954
+ entities,
2955
+ objects
2956
+ }) => {
2525
2957
  return [
2526
2958
  // Predefined types
2527
- enm("Order", ["ASC", "DESC"]),
2528
- scalar("DateTime"),
2529
- scalar("Upload"),
2530
- ...rawModels.filter(isEnumModel).map((model) => enm(model.name, model.values)),
2531
- ...rawModels.filter(isRawEnumModel).map((model) => enm(model.name, model.values)),
2532
- ...rawModels.filter(isScalarModel).map((model) => scalar(model.name)),
2533
- ...rawModels.filter(isObjectModel).filter(({ name: name2 }) => !["Query", "Mutation"].includes(name2)).map((model) => object(model.name, model.fields)),
2534
- ...rawModels.filter(isInputModel).map((model) => input(model.name, model.fields)),
2535
- ...rawModels.filter(isObjectModel).filter(
2536
- (model) => models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
2959
+ ...rawEnums.map((model) => enm(model.name, model.values)),
2960
+ ...enums.map((model) => enm(model.name, model.values)),
2961
+ ...scalars.map((model) => scalar(model.name)),
2962
+ ...objects.filter(({ name: name2 }) => !["Query", "Mutation"].includes(name2)).map((model) => object(model.name, model.fields)),
2963
+ ...interfaces.map(({ name: name2, fields: fields2 }) => iface(name2, fields2)),
2964
+ ...inputs.map((model) => input(model.name, model.fields)),
2965
+ ...objects.filter(
2966
+ (model) => entities.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
2537
2967
  ).map((model) => input(`Create${model.name}`, model.fields)),
2538
- ...rawModels.filter(isObjectModel).filter(
2539
- (model) => models.some((m) => m.creatable && m.fields.some((f) => f.creatable && f.kind === "json" && f.type === model.name))
2968
+ ...objects.filter(
2969
+ (model) => entities.some((m) => m.updatable && m.fields.some((f) => f.updatable && f.kind === "json" && f.type === model.name))
2540
2970
  ).map((model) => input(`Update${model.name}`, model.fields)),
2541
- ...(0, import_flatMap2.default)(
2542
- models.map((model) => {
2543
- const types = [
2544
- object(
2545
- model.name,
2546
- [
2547
- ...model.fields.filter(isQueriableField).map((field) => ({
2548
- ...field,
2549
- type: field.type,
2550
- args: [...field.args || []],
2551
- directives: field.directives
2552
- })),
2553
- ...model.reverseRelations.map(({ name: name2, field, model: model2 }) => ({
2554
- name: name2,
2555
- type: model2.name,
2556
- list: !field.toOne,
2557
- nonNull: !field.toOne,
2558
- args: [
2559
- { name: "where", type: `${model2.name}Where` },
2560
- ...model2.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
2561
- ...model2.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${model2.name}OrderBy`, list: true }] : [],
2562
- { name: "limit", type: "Int" },
2563
- { name: "offset", type: "Int" }
2564
- ]
2565
- }))
2566
- ],
2567
- model.interfaces
2568
- ),
2569
- input(`${model.name}Where`, [
2570
- ...model.fields.filter(({ kind, unique, filterable }) => (unique || filterable) && kind !== "relation").map((field) => ({
2571
- name: field.name,
2971
+ ...entities.flatMap((model) => {
2972
+ const types = [
2973
+ (isRootModel(model) ? iface : object)(
2974
+ model.name,
2975
+ [
2976
+ ...model.fields.filter(isQueriableField).map((field) => ({
2977
+ ...field,
2572
2978
  type: field.type,
2573
- list: true,
2574
- default: typeof field.filterable === "object" ? field.filterable.default : void 0
2979
+ args: [...field.args || []],
2980
+ directives: field.directives
2575
2981
  })),
2576
- ...(0, import_flatMap2.default)(
2577
- model.fields.filter(({ comparable }) => comparable),
2578
- (field) => [
2579
- { name: `${field.name}_GT`, type: field.type },
2580
- { name: `${field.name}_GTE`, type: field.type },
2581
- { name: `${field.name}_LT`, type: field.type },
2582
- { name: `${field.name}_LTE`, type: field.type }
2583
- ]
2584
- ),
2585
- ...model.fields.filter(isRelation).filter(({ filterable }) => filterable).map(({ name: name2, type }) => ({
2982
+ ...model.reverseRelations.map(({ name: name2, field, targetModel }) => ({
2586
2983
  name: name2,
2587
- type: `${type}Where`
2984
+ type: targetModel.name,
2985
+ list: !field.toOne,
2986
+ nonNull: !field.toOne,
2987
+ args: [
2988
+ { name: "where", type: `${targetModel.name}Where` },
2989
+ ...targetModel.fields.some(({ searchable }) => searchable) ? [{ name: "search", type: "String" }] : [],
2990
+ ...targetModel.fields.some(({ orderable }) => orderable) ? [{ name: "orderBy", type: `${targetModel.name}OrderBy`, list: true }] : [],
2991
+ { name: "limit", type: "Int" },
2992
+ { name: "offset", type: "Int" }
2993
+ ]
2588
2994
  }))
2995
+ ],
2996
+ [...model.parent ? [model.parent] : [], ...model.interfaces || []]
2997
+ ),
2998
+ input(`${model.name}Where`, [
2999
+ ...model.fields.filter(({ kind, unique, filterable }) => (unique || filterable) && kind !== "relation").map((field) => ({
3000
+ name: field.name,
3001
+ type: field.type,
3002
+ list: true,
3003
+ default: typeof field.filterable === "object" ? field.filterable.default : void 0
3004
+ })),
3005
+ ...model.fields.filter(({ comparable }) => comparable).flatMap((field) => [
3006
+ { name: `${field.name}_GT`, type: field.type },
3007
+ { name: `${field.name}_GTE`, type: field.type },
3008
+ { name: `${field.name}_LT`, type: field.type },
3009
+ { name: `${field.name}_LTE`, type: field.type }
2589
3010
  ]),
3011
+ ...model.fields.filter(isRelation).filter(({ filterable }) => filterable).map(({ name: name2, type }) => ({
3012
+ name: name2,
3013
+ type: `${type}Where`
3014
+ }))
3015
+ ]),
3016
+ input(
3017
+ `${model.name}WhereUnique`,
3018
+ model.fields.filter(({ unique }) => unique).map((field) => ({ name: field.name, type: field.type }))
3019
+ ),
3020
+ ...model.fields.some(({ orderable }) => orderable) ? [
2590
3021
  input(
2591
- `${model.name}WhereUnique`,
2592
- model.fields.filter(({ unique }) => unique).map((field) => ({ name: field.name, type: field.type }))
2593
- ),
2594
- ...model.fields.some(({ orderable }) => orderable) ? [
2595
- input(
2596
- `${model.name}OrderBy`,
2597
- model.fields.filter(({ orderable }) => orderable).map(({ name: name2 }) => ({ name: name2, type: "Order" }))
2598
- )
2599
- ] : []
2600
- ];
3022
+ `${model.name}OrderBy`,
3023
+ model.fields.filter(({ orderable }) => orderable).map(({ name: name2 }) => ({ name: name2, type: "Order" }))
3024
+ )
3025
+ ] : []
3026
+ ];
3027
+ if (!isRootModel(model)) {
2601
3028
  if (model.creatable) {
2602
3029
  types.push(
2603
3030
  input(
@@ -2627,15 +3054,15 @@ var generateDefinitions = (rawModels) => {
2627
3054
  )
2628
3055
  );
2629
3056
  }
2630
- return types;
2631
- })
2632
- ),
3057
+ }
3058
+ return types;
3059
+ }),
2633
3060
  object("Query", [
2634
3061
  {
2635
3062
  name: "me",
2636
3063
  type: "User"
2637
3064
  },
2638
- ...models.filter(({ queriable }) => queriable).map(({ name: name2 }) => ({
3065
+ ...entities.filter(({ queriable }) => queriable).map(({ name: name2 }) => ({
2639
3066
  name: typeToField(name2),
2640
3067
  type: name2,
2641
3068
  nonNull: true,
@@ -2647,8 +3074,8 @@ var generateDefinitions = (rawModels) => {
2647
3074
  }
2648
3075
  ]
2649
3076
  })),
2650
- ...models.filter(({ listQueriable }) => listQueriable).map((model) => ({
2651
- name: getModelPluralField(model),
3077
+ ...entities.filter(({ listQueriable }) => listQueriable).map((model) => ({
3078
+ name: model.pluralField,
2652
3079
  type: model.name,
2653
3080
  list: true,
2654
3081
  nonNull: true,
@@ -2660,12 +3087,12 @@ var generateDefinitions = (rawModels) => {
2660
3087
  { name: "offset", type: "Int" }
2661
3088
  ]
2662
3089
  })),
2663
- ...rawModels.filter(isObjectModel).filter((model) => model.name === "Query").flatMap((model) => model.fields)
3090
+ ...objects.filter((model) => model.name === "Query").flatMap((model) => model.fields)
2664
3091
  ]),
2665
3092
  object("Mutation", [
2666
- ...(0, import_flatMap2.default)(
2667
- models.map((model) => {
2668
- const mutations = [];
3093
+ ...entities.flatMap((model) => {
3094
+ const mutations = [];
3095
+ if (!isRootModel(model)) {
2669
3096
  if (model.creatable) {
2670
3097
  mutations.push({
2671
3098
  name: `create${model.name}`,
@@ -2729,14 +3156,14 @@ var generateDefinitions = (rawModels) => {
2729
3156
  ]
2730
3157
  });
2731
3158
  }
2732
- return mutations;
2733
- })
2734
- ),
2735
- ...rawModels.filter(isObjectModel).filter((model) => model.name === "Mutation").flatMap((model) => model.fields)
3159
+ }
3160
+ return mutations;
3161
+ }),
3162
+ ...objects.filter((model) => model.name === "Mutation").flatMap((model) => model.fields)
2736
3163
  ])
2737
3164
  ];
2738
3165
  };
2739
- var generate = (rawModels) => document(generateDefinitions(rawModels));
3166
+ var generate = (models) => document(generateDefinitions(models));
2740
3167
  var printSchema = (schema) => [
2741
3168
  ...schema.getDirectives().map((d) => d.astNode && (0, import_graphql5.print)(d.astNode)),
2742
3169
  ...Object.values(schema.getTypeMap()).filter((t) => !t.name.match(/^__/)).sort((a, b) => a.name > b.name ? 1 : -1).map((t) => t.astNode && (0, import_graphql5.print)(t.astNode))
@@ -2747,13 +3174,27 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2747
3174
  // Annotate the CommonJS export names for ESM import in node:
2748
3175
  0 && (module.exports = {
2749
3176
  AliasGenerator,
3177
+ EntityModel,
3178
+ EnumModel,
2750
3179
  ForbiddenError,
2751
3180
  GraphQLError,
2752
3181
  ID_ALIAS,
3182
+ InputModel,
3183
+ InterfaceModel,
3184
+ ManyToManyRelation,
2753
3185
  MigrationGenerator,
3186
+ Model,
3187
+ Models,
3188
+ NormalRelation,
2754
3189
  NotFoundError,
3190
+ ObjectModel,
2755
3191
  PermissionError,
3192
+ RawEnumModel,
3193
+ Relation,
3194
+ ReverseRelation,
2756
3195
  SPECIAL_FILTERS,
3196
+ ScalarModel,
3197
+ TYPE_ALIAS,
2757
3198
  UserInputError,
2758
3199
  actionableRelations,
2759
3200
  addJoin,
@@ -2762,6 +3203,7 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2762
3203
  applyFilters,
2763
3204
  applyJoins,
2764
3205
  applyPermissions,
3206
+ applySelects,
2765
3207
  args,
2766
3208
  checkCanWrite,
2767
3209
  directive,
@@ -2779,6 +3221,8 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2779
3221
  generateMutations,
2780
3222
  generatePermissions,
2781
3223
  get,
3224
+ getColumn,
3225
+ getColumnName,
2782
3226
  getEditEntityRelationsQuery,
2783
3227
  getEntityListQuery,
2784
3228
  getEntityQuery,
@@ -2789,16 +3233,8 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2789
3233
  getInlineFragments,
2790
3234
  getJoins,
2791
3235
  getLabel,
2792
- getManyToManyRelation,
2793
- getManyToManyRelations,
2794
3236
  getManyToManyRelationsQuery,
2795
3237
  getMigrationDate,
2796
- getModelLabel,
2797
- getModelLabelPlural,
2798
- getModelPlural,
2799
- getModelPluralField,
2800
- getModelSlug,
2801
- getModels,
2802
3238
  getMutationQuery,
2803
3239
  getNameOrAlias,
2804
3240
  getPermissionStack,
@@ -2811,6 +3247,7 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2811
3247
  getTypeName,
2812
3248
  getUpdateEntityQuery,
2813
3249
  gql,
3250
+ hasName,
2814
3251
  hash,
2815
3252
  hydrate,
2816
3253
  iface,
@@ -2822,12 +3259,14 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2822
3259
  isCustomField,
2823
3260
  isEntityModel,
2824
3261
  isEnum,
2825
- isEnumList,
2826
3262
  isEnumModel,
2827
3263
  isFieldNode,
2828
3264
  isFragmentSpreadNode,
3265
+ isInTable,
3266
+ isInherited,
2829
3267
  isInlineFragmentNode,
2830
3268
  isInputModel,
3269
+ isInterfaceModel,
2831
3270
  isListType,
2832
3271
  isObjectModel,
2833
3272
  isPrimitive,
@@ -2835,16 +3274,20 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2835
3274
  isQueriableField,
2836
3275
  isRawEnumModel,
2837
3276
  isRelation,
3277
+ isRootModel,
2838
3278
  isScalarModel,
2839
3279
  isSimpleField,
2840
3280
  isToOneRelation,
2841
3281
  isUpdatable,
2842
3282
  isUpdatableBy,
3283
+ isUpdatableField,
3284
+ isUpdatableModel,
2843
3285
  isVisible,
2844
3286
  isVisibleRelation,
2845
3287
  it,
2846
3288
  list,
2847
3289
  merge,
3290
+ modelNeedsTable,
2848
3291
  mutationResolver,
2849
3292
  name,
2850
3293
  namedType,
@@ -2854,6 +3297,7 @@ var printSchemaFromModels = (models) => printSchema((0, import_graphql5.buildAST
2854
3297
  normalizeValueByTypeDefinition,
2855
3298
  not,
2856
3299
  object,
3300
+ or,
2857
3301
  ors,
2858
3302
  printSchema,
2859
3303
  printSchemaFromDocument,