Skip to content

Commit d8acd73

Browse files
authored
Don't create update mutation if no patch type (#871)
* Create test reproducing issue * Don't try and create update without patch type
1 parent a6b2f33 commit d8acd73

4 files changed

Lines changed: 264 additions & 3 deletions

File tree

packages/graphile-build-pg/src/plugins/PgMutationUpdateDeletePlugin.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ returning *`;
196196
const TablePatch = getTypeByName(
197197
inflection.patchType(Table.name)
198198
);
199+
if (mode === "update" && !TablePatch) {
200+
return memo;
201+
}
199202
const PayloadType = newWithHooks(
200203
GraphQLObjectType,
201204
{
@@ -329,7 +332,7 @@ returning *`;
329332
type: new GraphQLNonNull(GraphQLID),
330333
},
331334
},
332-
mode === "update"
335+
mode === "update" && TablePatch
333336
? {
334337
[inflection.patchField(
335338
inflection.tableFieldName(table)
@@ -482,7 +485,7 @@ returning *`;
482485
type: GraphQLString,
483486
},
484487
},
485-
mode === "update"
488+
mode === "update" && TablePatch
486489
? {
487490
[inflection.patchField(
488491
inflection.tableFieldName(table)

packages/postgraphile-core/__tests__/kitchen-sink-schema.sql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ drop schema if exists
1515
named_query_builder,
1616
enum_tables,
1717
geometry,
18-
function_returning_enum
18+
function_returning_enum,
19+
no_fields
1920
cascade;
2021
drop extension if exists tablefunc;
2122
drop extension if exists intarray;
@@ -1361,3 +1362,10 @@ as $$
13611362
end)::function_returning_enum.transportation;
13621363
$$ language sql stable;
13631364
comment on function function_returning_enum.applicants_favorite_pet_transportation is E'@filterable';
1365+
1366+
--------------------------------------------------------------------------------
1367+
1368+
create schema no_fields;
1369+
create table no_fields.citation (
1370+
id integer primary key generated always as identity
1371+
);
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
type Citation implements Node {
2+
id: Int!
3+
4+
"""
5+
A globally unique identifier. Can be used in various places throughout the system to identify this single value.
6+
"""
7+
nodeId: ID!
8+
}
9+
10+
"""
11+
A condition to be used against `Citation` object types. All fields are tested
12+
for equality and combined with a logical ‘and.’
13+
"""
14+
input CitationCondition {
15+
"""Checks for equality with the object’s `id` field."""
16+
id: Int
17+
}
18+
19+
"""A connection to a list of `Citation` values."""
20+
type CitationsConnection {
21+
"""
22+
A list of edges which contains the `Citation` and cursor to aid in pagination.
23+
"""
24+
edges: [CitationsEdge!]!
25+
26+
"""A list of `Citation` objects."""
27+
nodes: [Citation]!
28+
29+
"""Information to aid in pagination."""
30+
pageInfo: PageInfo!
31+
32+
"""The count of *all* `Citation` you could get from the connection."""
33+
totalCount: Int!
34+
}
35+
36+
"""A `Citation` edge in the connection."""
37+
type CitationsEdge {
38+
"""A cursor for use in pagination."""
39+
cursor: Cursor
40+
41+
"""The `Citation` at the end of the edge."""
42+
node: Citation
43+
}
44+
45+
"""Methods to use when ordering `Citation`."""
46+
enum CitationsOrderBy {
47+
ID_ASC
48+
ID_DESC
49+
NATURAL
50+
PRIMARY_KEY_ASC
51+
PRIMARY_KEY_DESC
52+
}
53+
54+
"""All input for the create `Citation` mutation."""
55+
input CreateCitationInput {
56+
"""
57+
An arbitrary string value with no semantic meaning. Will be included in the
58+
payload verbatim. May be used to track mutations by the client.
59+
"""
60+
clientMutationId: String
61+
}
62+
63+
"""The output of our create `Citation` mutation."""
64+
type CreateCitationPayload {
65+
"""The `Citation` that was created by this mutation."""
66+
citation: Citation
67+
68+
"""An edge for our `Citation`. May be used by Relay 1."""
69+
citationEdge(
70+
"""The method to use when ordering `Citation`."""
71+
orderBy: [CitationsOrderBy!] = [PRIMARY_KEY_ASC]
72+
): CitationsEdge
73+
74+
"""
75+
The exact same `clientMutationId` that was provided in the mutation input,
76+
unchanged and unused. May be used by a client to track mutations.
77+
"""
78+
clientMutationId: String
79+
80+
"""
81+
Our root query field type. Allows us to run any query from our mutation payload.
82+
"""
83+
query: Query
84+
}
85+
86+
"""A location in a connection that can be used for resuming pagination."""
87+
scalar Cursor
88+
89+
"""All input for the `deleteCitationById` mutation."""
90+
input DeleteCitationByIdInput {
91+
"""
92+
An arbitrary string value with no semantic meaning. Will be included in the
93+
payload verbatim. May be used to track mutations by the client.
94+
"""
95+
clientMutationId: String
96+
id: Int!
97+
}
98+
99+
"""All input for the `deleteCitation` mutation."""
100+
input DeleteCitationInput {
101+
"""
102+
An arbitrary string value with no semantic meaning. Will be included in the
103+
payload verbatim. May be used to track mutations by the client.
104+
"""
105+
clientMutationId: String
106+
107+
"""
108+
The globally unique `ID` which will identify a single `Citation` to be deleted.
109+
"""
110+
nodeId: ID!
111+
}
112+
113+
"""The output of our delete `Citation` mutation."""
114+
type DeleteCitationPayload {
115+
"""The `Citation` that was deleted by this mutation."""
116+
citation: Citation
117+
118+
"""An edge for our `Citation`. May be used by Relay 1."""
119+
citationEdge(
120+
"""The method to use when ordering `Citation`."""
121+
orderBy: [CitationsOrderBy!] = [PRIMARY_KEY_ASC]
122+
): CitationsEdge
123+
124+
"""
125+
The exact same `clientMutationId` that was provided in the mutation input,
126+
unchanged and unused. May be used by a client to track mutations.
127+
"""
128+
clientMutationId: String
129+
deletedCitationId: ID
130+
131+
"""
132+
Our root query field type. Allows us to run any query from our mutation payload.
133+
"""
134+
query: Query
135+
}
136+
137+
"""
138+
The root mutation type which contains root level fields which mutate data.
139+
"""
140+
type Mutation {
141+
"""Creates a single `Citation`."""
142+
createCitation(
143+
"""
144+
The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.
145+
"""
146+
input: CreateCitationInput!
147+
): CreateCitationPayload
148+
149+
"""Deletes a single `Citation` using its globally unique id."""
150+
deleteCitation(
151+
"""
152+
The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.
153+
"""
154+
input: DeleteCitationInput!
155+
): DeleteCitationPayload
156+
157+
"""Deletes a single `Citation` using a unique key."""
158+
deleteCitationById(
159+
"""
160+
The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.
161+
"""
162+
input: DeleteCitationByIdInput!
163+
): DeleteCitationPayload
164+
}
165+
166+
"""An object with a globally unique `ID`."""
167+
interface Node {
168+
"""
169+
A globally unique identifier. Can be used in various places throughout the system to identify this single value.
170+
"""
171+
nodeId: ID!
172+
}
173+
174+
"""Information about pagination in a connection."""
175+
type PageInfo {
176+
"""When paginating forwards, the cursor to continue."""
177+
endCursor: Cursor
178+
179+
"""When paginating forwards, are there more items?"""
180+
hasNextPage: Boolean!
181+
182+
"""When paginating backwards, are there more items?"""
183+
hasPreviousPage: Boolean!
184+
185+
"""When paginating backwards, the cursor to continue."""
186+
startCursor: Cursor
187+
}
188+
189+
"""The root query type which gives access points into the data universe."""
190+
type Query implements Node {
191+
"""Reads and enables pagination through a set of `Citation`."""
192+
allCitations(
193+
"""Read all values in the set after (below) this cursor."""
194+
after: Cursor
195+
196+
"""Read all values in the set before (above) this cursor."""
197+
before: Cursor
198+
199+
"""
200+
A condition to be used in determining which values should be returned by the collection.
201+
"""
202+
condition: CitationCondition
203+
204+
"""Only read the first `n` values of the set."""
205+
first: Int
206+
207+
"""Only read the last `n` values of the set."""
208+
last: Int
209+
210+
"""
211+
Skip the first `n` values from our `after` cursor, an alternative to cursor
212+
based pagination. May not be used with `last`.
213+
"""
214+
offset: Int
215+
216+
"""The method to use when ordering `Citation`."""
217+
orderBy: [CitationsOrderBy!] = [PRIMARY_KEY_ASC]
218+
): CitationsConnection
219+
220+
"""Reads a single `Citation` using its globally unique `ID`."""
221+
citation(
222+
"""The globally unique `ID` to be used in selecting a single `Citation`."""
223+
nodeId: ID!
224+
): Citation
225+
citationById(id: Int!): Citation
226+
extended: Boolean
227+
228+
"""Fetches an object given its globally unique `ID`."""
229+
node(
230+
"""The globally unique `ID`."""
231+
nodeId: ID!
232+
): Node
233+
234+
"""
235+
The root query type must be a `Node` to work well with Relay 1 mutations. This just resolves to `query`.
236+
"""
237+
nodeId: ID!
238+
239+
"""
240+
Exposes the root query type nested one level down. This is helpful for Relay 1
241+
which can only query top level fields if they are in a particular form.
242+
"""
243+
query: Query!
244+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { testSchema } from "../helpers-v5";
2+
3+
it("prints a schema from a table with no mutable fields", () =>
4+
testSchema(__filename, {
5+
schema: "no_fields",
6+
}));

0 commit comments

Comments
 (0)