Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Commit 5de1fe3

Browse files
authored
Merge pull request #145 from tarantool/gh-142-mutations
Mutations PoC
2 parents 3afb10b + 090eb18 commit 5de1fe3

16 files changed

+2510
-224
lines changed

README.md

+219-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,225 @@ local compiled_query = graphql_lib.compile(query)
124124
local result = compiled_query:execute(variables)
125125
```
126126

127-
# GraphiQL
127+
### Mutations
128+
129+
Mutations are disabled for avro-schema-2\*, because it can work incorrectly for
130+
schemas with nullable types (ones whose marked with asterisk). Mutations still
131+
can be enabled with the `enable_mutations = true` option, but use it with
132+
caution. Don't enable this option with schemas involve nullable types.
133+
134+
#### Mutations with space accessor
135+
136+
TBD: Describe which changes are transactional and which views are guaranteed to
137+
be consistent.
138+
139+
#### Mutations with shard accessor
140+
141+
Mutations are disabled in the resharding state of a shard cluster.
142+
143+
There are three types of modifications: insert, update and delete. Several
144+
modifications are allowed in an one GraphQL request, but they will be processed
145+
in non-transactional way.
146+
147+
In the case of shard accessor the following constraints can guarantee that data
148+
will be changed in atomic way or, in other words, in an one shard request (but
149+
foregoing and upcoming selects can see other data):
150+
151+
* One insert / update / delete argument over the entire GraphQL request.
152+
* For update / delete: either the argument is for 1:1 connection or `limit: 1`
153+
is used for a collection (a topmost field) or 1:N connection (a nested
154+
field).
155+
* No update of a first field of a **tuple** (shard key is calculated by it). It
156+
is the first field of upmost record in the schema for a collection in case
157+
when there are no service fields. If there are service fields, the first
158+
field of a tuple cannot be changed by a mutation GraphQL request.
159+
160+
Data can be changed between shard requests which are part of the one GraphQL
161+
request, so the result can observe inconsistent state. We'll don't show all
162+
possible cases, but give an idea what going on in the following paragraph.
163+
164+
Filters are applied for an object(s) (several requests in case of filters by
165+
connections, one request otherwise), then each object updated/deleted by its
166+
primary key (one request per object), then all connected objects are resolved
167+
in the same way.
168+
169+
#### Insert
170+
171+
Example with an object passed from a variable:
172+
173+
```
174+
mutation insert_user_and_order($user: user_collection_insert,
175+
$order: order_collection_insert) {
176+
user_collection(insert: $user) {
177+
user_id
178+
first_name
179+
last_name
180+
}
181+
order_collection(insert: $order) {
182+
order_id
183+
description
184+
in_stock
185+
}
186+
}
187+
```
188+
189+
Example with immediate argument for an object:
190+
191+
```
192+
mutation insert_user_and_order {
193+
user_collection(insert: {
194+
user_id: "user_id_new_1"
195+
first_name: "Peter"
196+
last_name: "Petrov"
197+
}) {
198+
user_id
199+
first_name
200+
last_name
201+
}
202+
order_collection(insert: {
203+
order_id: "order_id_new_1"
204+
user_id: "user_id_new_1"
205+
description: "Peter's order"
206+
price: 0.0
207+
discount: 0.0
208+
# in_stock: true should be set as default value
209+
}) {
210+
order_id
211+
description
212+
in_stock
213+
}
214+
}
215+
```
216+
217+
Consider the following details:
218+
219+
* `${collection_name}_insert` is the name of the type whose value intended to
220+
pass to the `insert` argument. This type / argument requires a user to set
221+
all fields of an inserting object.
222+
* Inserting cannot be used on connection fields, it is allowed only for
223+
top-level fields (named as well as collections).
224+
* It is forbidden to use `insert` argument with any other argument.
225+
* A mutation with an `insert` argument always return the object that was just
226+
inserted.
227+
* Of course `insert` argument is forbidden in `query` requests.
228+
229+
#### Update
230+
231+
Example with an update statement passed from a variable. Note that here we
232+
update an object given by a connection (inside an one of nested fields of a
233+
request):
234+
235+
```
236+
mutation update_user_and_order(
237+
$user_id: String
238+
$order_id: String
239+
$xuser: user_collection_update
240+
$xorder: order_collection_update
241+
) {
242+
# update nested user
243+
order_collection(order_id: $order_id) {
244+
order_id
245+
description
246+
user_connection(update: $xuser) {
247+
user_id
248+
first_name
249+
last_name
250+
}
251+
}
252+
# update nested order (only the first, because of limit)
253+
user_collection(user_id: $user_id) {
254+
user_id
255+
first_name
256+
last_name
257+
order_connection(limit: 1, update: $xorder) {
258+
order_id
259+
description
260+
in_stock
261+
}
262+
}
263+
}
264+
```
265+
266+
Example with immediate argument for an update statement:
267+
268+
```
269+
mutation update_user_and_order {
270+
user_collection(user_id: "user_id_1", update: {
271+
first_name: "Peter"
272+
last_name: "Petrov"
273+
}) {
274+
user_id
275+
first_name
276+
last_name
277+
}
278+
order_collection(order_id: "order_id_1", update: {
279+
description: "Peter's order"
280+
price: 0.0
281+
discount: 0.0
282+
in_stock: false
283+
}) {
284+
order_id
285+
description
286+
in_stock
287+
}
288+
}
289+
```
290+
291+
Consider the following details:
292+
293+
* `${collection_name}_update` is the name of the type whose value intended to
294+
pass to the `update` argument. This type / argument requires a user to set
295+
subset of fields of an updating object except primary key parts.
296+
* A mutation with an `update` argument always return the updated object.
297+
* The `update` argument is forbidden with `insert` or `delete` arguments.
298+
* The `update` argument is forbidden in `query` requests.
299+
* Objects are selected by filters first, then updated using a statement in the
300+
`update` argument, then connected objects are selected.
301+
* The `limit` and `offset` arguments applied before update, so a user can use
302+
`limit: 1` to update only first match.
303+
* Objects traversed in deep-first up-first order as it written in a mutation
304+
request. So an `update` argument potentially changes those fields that are
305+
follows the updated object in this order.
306+
* Filters by connected objects are performed before update. Resulting connected
307+
objects given after the update (it is matter when a field(s) of the parent
308+
objects by whose the connection is made is subject to change).
309+
310+
#### Delete
311+
312+
Example:
313+
314+
```
315+
mutation delete_user_and_order(
316+
$user_id: String,
317+
$order_id: String,
318+
) {
319+
user_collection(user_id: $user_id, delete: true) {
320+
user_id
321+
first_name
322+
last_name
323+
}
324+
order_collection(order_id: $order_id, delete: true) {
325+
order_id
326+
description
327+
in_stock
328+
}
329+
}
330+
```
331+
332+
Consider the following details:
333+
334+
* There are no special type name for a `delete` argument, it is just Boolean.
335+
* A mutation with a `delete: true` argument always return the deleted object.
336+
* The `delete` argument is forbidden with `insert` or `update` arguments.
337+
* The `delete` argument is forbidden in `query` requests.
338+
* The same fields traversal order and 'select -> change -> select connected'
339+
order of operations for an one field are applied likewise for the `update`
340+
argument.
341+
* The `limit` argument can be used to define how many objects are subject to
342+
deletion and `offset` can help with adjusting start point of multi-object
343+
delete operation.
344+
345+
## GraphiQL
128346
```
129347
local graphql = require('graphql').new({
130348
schemas = schemas,

0 commit comments

Comments
 (0)