@constructive-io/graphql-query 3.31.0 → 3.31.2

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.
@@ -178,7 +178,7 @@ function buildCleanTable(entityName, entityType, typeMap, queryFields, mutationF
178
178
  const relations = inferRelations(entityType, entityToConnection, connectionToEntity);
179
179
  // Match query and mutation operations
180
180
  const queryOps = matchQueryOperations(entityName, queryFields, entityToConnection);
181
- const mutationOps = matchMutationOperations(entityName, mutationFields);
181
+ const mutationOps = matchMutationOperations(entityName, mutationFields, typeMap);
182
182
  // Check if we found at least one real operation (not a fallback)
183
183
  const hasRealOperation = !!(queryOps.all ||
184
184
  queryOps.one ||
@@ -485,6 +485,25 @@ function matchQueryOperations(entityName, queryFields, entityToConnection) {
485
485
  }
486
486
  return { all, one };
487
487
  }
488
+ /**
489
+ * Check whether a mutation field is a real PostGraphile CRUD mutation.
490
+ *
491
+ * CRUD mutation payloads always contain a field named lcFirst(entityName)
492
+ * whose type is the entity itself (e.g. DeleteUserPayload has `user: User`).
493
+ * Custom SQL-function mutations that happen to follow the same naming
494
+ * convention (e.g. `deletePrincipal`) return something else — typically
495
+ * `result: Boolean` or `result: UUID` — and must not be treated as CRUD.
496
+ */
497
+ function isCrudMutation(field, entityName, typeMap) {
498
+ const payloadTypeName = getBaseTypeName(field.type);
499
+ if (!payloadTypeName)
500
+ return false;
501
+ const payloadType = typeMap.get(payloadTypeName);
502
+ if (!payloadType || !payloadType.fields)
503
+ return false;
504
+ const entityFieldName = lcFirst(entityName);
505
+ return payloadType.fields.some((f) => f.name === entityFieldName && getBaseTypeName(f.type) === entityName);
506
+ }
488
507
  /**
489
508
  * Match mutation operations for an entity
490
509
  *
@@ -496,8 +515,12 @@ function matchQueryOperations(entityName, queryFields, entityToConnection) {
496
515
  * - bulkUpsert{PluralName} (bulk upsert)
497
516
  * - bulkUpdate{PluralName} (bulk update)
498
517
  * - bulkDelete{PluralName} (bulk delete)
518
+ *
519
+ * A candidate is only accepted if its payload type returns the entity
520
+ * (i.e. it is a real CRUD mutation, not a custom SQL function that
521
+ * happens to share the naming convention).
499
522
  */
500
- function matchMutationOperations(entityName, mutationFields) {
523
+ function matchMutationOperations(entityName, mutationFields, typeMap) {
501
524
  let create = null;
502
525
  let update = null;
503
526
  let del = null;
@@ -516,25 +539,27 @@ function matchMutationOperations(entityName, mutationFields) {
516
539
  const expectedBulkDelete = `bulkDelete${pluralName}`;
517
540
  for (const field of mutationFields) {
518
541
  // Exact match for create
519
- if (field.name === expectedCreate) {
542
+ if (field.name === expectedCreate && isCrudMutation(field, entityName, typeMap)) {
520
543
  create = field.name;
521
544
  }
522
545
  // Match update (could be updateUser, updateUserById, or updateUserByFooAndBar for composite PKs)
523
- if (field.name === expectedUpdate) {
546
+ if (field.name === expectedUpdate && isCrudMutation(field, entityName, typeMap)) {
524
547
  update = field.name;
525
548
  }
526
549
  else if (!update &&
527
550
  (field.name === `${expectedUpdate}ById` ||
528
- field.name.startsWith(`${expectedUpdate}By`))) {
551
+ field.name.startsWith(`${expectedUpdate}By`)) &&
552
+ isCrudMutation(field, entityName, typeMap)) {
529
553
  update = field.name;
530
554
  }
531
555
  // Match delete (could be deleteUser, deleteUserById, or deleteUserByFooAndBar for composite PKs)
532
- if (field.name === expectedDelete) {
556
+ if (field.name === expectedDelete && isCrudMutation(field, entityName, typeMap)) {
533
557
  del = field.name;
534
558
  }
535
559
  else if (!del &&
536
560
  (field.name === `${expectedDelete}ById` ||
537
- field.name.startsWith(`${expectedDelete}By`))) {
561
+ field.name.startsWith(`${expectedDelete}By`)) &&
562
+ isCrudMutation(field, entityName, typeMap)) {
538
563
  del = field.name;
539
564
  }
540
565
  // Bulk mutations
@@ -181,7 +181,7 @@ function buildCleanTable(entityName, entityType, typeMap, queryFields, mutationF
181
181
  const relations = inferRelations(entityType, entityToConnection, connectionToEntity);
182
182
  // Match query and mutation operations
183
183
  const queryOps = matchQueryOperations(entityName, queryFields, entityToConnection);
184
- const mutationOps = matchMutationOperations(entityName, mutationFields);
184
+ const mutationOps = matchMutationOperations(entityName, mutationFields, typeMap);
185
185
  // Check if we found at least one real operation (not a fallback)
186
186
  const hasRealOperation = !!(queryOps.all ||
187
187
  queryOps.one ||
@@ -488,6 +488,25 @@ function matchQueryOperations(entityName, queryFields, entityToConnection) {
488
488
  }
489
489
  return { all, one };
490
490
  }
491
+ /**
492
+ * Check whether a mutation field is a real PostGraphile CRUD mutation.
493
+ *
494
+ * CRUD mutation payloads always contain a field named lcFirst(entityName)
495
+ * whose type is the entity itself (e.g. DeleteUserPayload has `user: User`).
496
+ * Custom SQL-function mutations that happen to follow the same naming
497
+ * convention (e.g. `deletePrincipal`) return something else — typically
498
+ * `result: Boolean` or `result: UUID` — and must not be treated as CRUD.
499
+ */
500
+ function isCrudMutation(field, entityName, typeMap) {
501
+ const payloadTypeName = (0, introspection_1.getBaseTypeName)(field.type);
502
+ if (!payloadTypeName)
503
+ return false;
504
+ const payloadType = typeMap.get(payloadTypeName);
505
+ if (!payloadType || !payloadType.fields)
506
+ return false;
507
+ const entityFieldName = (0, inflekt_1.lcFirst)(entityName);
508
+ return payloadType.fields.some((f) => f.name === entityFieldName && (0, introspection_1.getBaseTypeName)(f.type) === entityName);
509
+ }
491
510
  /**
492
511
  * Match mutation operations for an entity
493
512
  *
@@ -499,8 +518,12 @@ function matchQueryOperations(entityName, queryFields, entityToConnection) {
499
518
  * - bulkUpsert{PluralName} (bulk upsert)
500
519
  * - bulkUpdate{PluralName} (bulk update)
501
520
  * - bulkDelete{PluralName} (bulk delete)
521
+ *
522
+ * A candidate is only accepted if its payload type returns the entity
523
+ * (i.e. it is a real CRUD mutation, not a custom SQL function that
524
+ * happens to share the naming convention).
502
525
  */
503
- function matchMutationOperations(entityName, mutationFields) {
526
+ function matchMutationOperations(entityName, mutationFields, typeMap) {
504
527
  let create = null;
505
528
  let update = null;
506
529
  let del = null;
@@ -519,25 +542,27 @@ function matchMutationOperations(entityName, mutationFields) {
519
542
  const expectedBulkDelete = `bulkDelete${pluralName}`;
520
543
  for (const field of mutationFields) {
521
544
  // Exact match for create
522
- if (field.name === expectedCreate) {
545
+ if (field.name === expectedCreate && isCrudMutation(field, entityName, typeMap)) {
523
546
  create = field.name;
524
547
  }
525
548
  // Match update (could be updateUser, updateUserById, or updateUserByFooAndBar for composite PKs)
526
- if (field.name === expectedUpdate) {
549
+ if (field.name === expectedUpdate && isCrudMutation(field, entityName, typeMap)) {
527
550
  update = field.name;
528
551
  }
529
552
  else if (!update &&
530
553
  (field.name === `${expectedUpdate}ById` ||
531
- field.name.startsWith(`${expectedUpdate}By`))) {
554
+ field.name.startsWith(`${expectedUpdate}By`)) &&
555
+ isCrudMutation(field, entityName, typeMap)) {
532
556
  update = field.name;
533
557
  }
534
558
  // Match delete (could be deleteUser, deleteUserById, or deleteUserByFooAndBar for composite PKs)
535
- if (field.name === expectedDelete) {
559
+ if (field.name === expectedDelete && isCrudMutation(field, entityName, typeMap)) {
536
560
  del = field.name;
537
561
  }
538
562
  else if (!del &&
539
563
  (field.name === `${expectedDelete}ById` ||
540
- field.name.startsWith(`${expectedDelete}By`))) {
564
+ field.name.startsWith(`${expectedDelete}By`)) &&
565
+ isCrudMutation(field, entityName, typeMap)) {
541
566
  del = field.name;
542
567
  }
543
568
  // Bulk mutations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-query",
3
- "version": "3.31.0",
3
+ "version": "3.31.2",
4
4
  "description": "Constructive GraphQL Query",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "main": "index.js",
@@ -37,7 +37,7 @@
37
37
  "grafast": "1.0.2",
38
38
  "graphile-build-pg": "5.0.2",
39
39
  "graphile-config": "1.0.1",
40
- "graphile-settings": "^5.12.0",
40
+ "graphile-settings": "^5.12.1",
41
41
  "graphql": "16.13.0",
42
42
  "inflection": "^3.0.0",
43
43
  "inflekt": "^0.7.1",
@@ -54,5 +54,5 @@
54
54
  "devDependencies": {
55
55
  "makage": "^0.3.0"
56
56
  },
57
- "gitHead": "b8bed95aa8adf93f13f7611ee10778214567eafe"
57
+ "gitHead": "ed31ed2aa63fcd2d42acec6f27e672dd300a3959"
58
58
  }