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

Commit 30ef57a

Browse files
committed
WIP: Implement update mutation
Part of #142.
1 parent ea859f9 commit 30ef57a

File tree

7 files changed

+381
-49
lines changed

7 files changed

+381
-49
lines changed

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ local result = compiled_query:execute(variables)
126126

127127
### Mutations
128128

129+
#### Insert
130+
129131
Example with an object passed from a variable:
130132

131133
```
@@ -184,6 +186,19 @@ Consider the following details:
184186
inserted.
185187
* Of course `insert` argument is forbidden in `query` requests.
186188

189+
#### Update
190+
191+
TBD
192+
193+
Points:
194+
195+
* Objects selected by filters first, then updated using a statement in the
196+
`update` argument.
197+
198+
#### Delete
199+
200+
TBD
201+
187202
## GraphiQL
188203
```
189204
local graphql = require('graphql').new({

graphql/accessor_general.lua

+119-36
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,50 @@ local function insert_internal(self, collection_name, from, filter, args, extra)
11471147
return {new_object}
11481148
end
11491149

1150+
--- XXX
1151+
local function update_internal(self, collection_name, from, filter, args,
1152+
extra, selected)
1153+
local xobject = extra.extra_args.update
1154+
if xobject == nil then return nil end
1155+
1156+
-- convert xobject -> update statements
1157+
local collection = self.collections[collection_name]
1158+
assert(collection ~= nil,
1159+
('cannot find the collection "%s"'):format(collection_name))
1160+
local schema_name = collection.schema_name
1161+
assert(type(schema_name) == 'string',
1162+
'schema_name must be a string, got ' .. type(schema_name))
1163+
1164+
local default_xflatten = self.default_xflatten[schema_name]
1165+
assert(default_xflatten ~= nil,
1166+
('cannot find default_xflatten ' ..
1167+
'for collection "%s"'):format(collection_name))
1168+
1169+
local statements = self.funcs.xflatten(collection_name, xobject, {
1170+
service_fields_defaults =
1171+
self.service_fields_defaults[schema_name],
1172+
}, default_xflatten)
1173+
1174+
-- XXX: remove connection fields from the selected objects in process_tuple
1175+
-- apply update statements & tuples -> objects
1176+
local _, primary_index_meta = get_primary_index_meta(self, collection_name)
1177+
local new_objects = {}
1178+
for _, object in ipairs(selected) do
1179+
local key = {}
1180+
for _, field_name in ipairs(primary_index_meta.fields) do
1181+
table.insert(key, object[field_name])
1182+
end
1183+
local new_tuple = self.funcs.update_tuple(collection_name, key,
1184+
statements)
1185+
local new_object = self.funcs.unflatten_tuple(collection_name,
1186+
new_tuple, {use_tomap = self.collection_use_tomap[collection_name]},
1187+
self.default_unflatten_tuple[schema_name])
1188+
table.insert(new_objects, new_object)
1189+
end
1190+
1191+
return new_objects
1192+
end
1193+
11501194
--- Set of asserts to check the `funcs` argument of the @{accessor_general.new}
11511195
--- function.
11521196
--- @tparam table funcs set of function as defined in the
@@ -1170,9 +1214,15 @@ local function validate_funcs(funcs)
11701214
assert(type(funcs.flatten_object) == 'function',
11711215
'funcs.flatten_object must be a function, got ' ..
11721216
type(funcs.flatten_object))
1217+
assert(type(funcs.xflatten) == 'function',
1218+
'funcs.xflatten must be a function, got ' ..
1219+
type(funcs.xflatten))
11731220
assert(type(funcs.insert_tuple) == 'function',
11741221
'funcs.insert_tuple must be a function, got ' ..
11751222
type(funcs.insert_tuple))
1223+
assert(type(funcs.update_tuple) == 'function',
1224+
'funcs.update_tuple must be a function, got ' ..
1225+
type(funcs.update_tuple))
11761226
end
11771227

11781228
--- This function is called on first select related to a query. Its purpose is
@@ -1292,6 +1342,60 @@ local function get_pcre_argument_type(self, collection_name)
12921342
return pcre_type
12931343
end
12941344

1345+
--- Create default unflatten/flatten/xflatten functions, that can be called
1346+
--- from funcs.unflatten_tuple/funcs.flatten_object/funcs.xflatten when an
1347+
--- additional pre/postprocessing is not needed.
1348+
---
1349+
--- @tparam table models list of compiled schemas
1350+
---
1351+
--- @treturn table table with default_* fields with maps from schema name to
1352+
--- the corresponding default *flatten function
1353+
local function gen_default_object_tuple_map_funcs(models)
1354+
local default_unflatten_tuple = {}
1355+
local default_flatten_object = {}
1356+
local default_xflatten = {}
1357+
for schema_name, model in pairs(models) do
1358+
default_unflatten_tuple[schema_name] = function(_, tuple, opts)
1359+
local opts = opts or {}
1360+
check(opts, 'opts', 'table')
1361+
1362+
local ok, obj = model.unflatten(tuple)
1363+
assert(ok, ('cannot unflat tuple of schema "%s": %s'):format(
1364+
schema_name, tostring(obj)))
1365+
return obj
1366+
end
1367+
default_flatten_object[schema_name] = function(_, obj, opts)
1368+
local opts = opts or {}
1369+
check(opts, 'opts', 'table')
1370+
local sf_defaults = opts.service_fields_defaults or {}
1371+
check(sf_defaults, 'service_fields_defaults', 'table')
1372+
1373+
local ok, tuple = model.flatten(obj, unpack(sf_defaults))
1374+
assert(ok, ('cannot flat object of schema "%s": %s'):format(
1375+
schema_name, tostring(tuple)))
1376+
return tuple
1377+
end
1378+
default_xflatten[schema_name] = function(_, xobject, opts)
1379+
local opts = opts or {}
1380+
check(opts, 'opts', 'table')
1381+
1382+
-- it is not needed now, but maybe needed in custom xflatten
1383+
local sf_defaults = opts.service_fields_defaults or {}
1384+
check(sf_defaults, 'service_fields_defaults', 'table')
1385+
1386+
local ok, statements = model.xflatten(xobject)
1387+
assert(ok, ('cannot xflat xobject of schema "%s": %s'):format(
1388+
schema_name, tostring(xobject)))
1389+
return statements
1390+
end
1391+
end
1392+
return {
1393+
default_unflatten_tuple = default_unflatten_tuple,
1394+
default_flatten_object = default_flatten_object,
1395+
default_xflatten = default_xflatten,
1396+
}
1397+
end
1398+
12951399
--- Create a new data accessor.
12961400
---
12971401
--- Provided `funcs` argument determines certain functions for retrieving
@@ -1391,39 +1495,8 @@ function accessor_general.new(opts, funcs)
13911495
service_fields)
13921496
validate_collections(collections, schemas, indexes)
13931497
local index_cache = build_index_cache(indexes, collections)
1394-
1395-
-- create default unflatten/flatten functions, that can be called from
1396-
-- funcs.unflatten_tuple/funcs.flatten_object when an additional
1397-
-- pre/postprocessing is not needed
1398-
local default_unflatten_tuple = {}
1399-
local default_flatten_object = {}
1400-
for schema_name, model in pairs(models) do
1401-
default_unflatten_tuple[schema_name] =
1402-
function(_, tuple, opts)
1403-
local opts = opts or {}
1404-
check(opts, 'opts', 'table')
1405-
1406-
local ok, obj = model.unflatten(tuple)
1407-
assert(ok, ('cannot unflat tuple of schema "%s": %s'):format(
1408-
schema_name, tostring(obj)))
1409-
return obj
1410-
end
1411-
default_flatten_object[schema_name] =
1412-
function(_, obj, opts)
1413-
local opts = opts or {}
1414-
check(opts, 'opts', 'table')
1415-
local service_fields_defaults = opts.service_fields_defaults or
1416-
{}
1417-
check(service_fields_defaults, 'service_fields_defaults',
1418-
'table')
1419-
1420-
local ok, tuple = model.flatten(obj,
1421-
unpack(service_fields_defaults))
1422-
assert(ok, ('cannot flat object of schema "%s": %s'):format(
1423-
schema_name, tostring(tuple)))
1424-
return tuple
1425-
end
1426-
end
1498+
local default_object_tuple_map_funcs =
1499+
gen_default_object_tuple_map_funcs(models)
14271500

14281501
validate_funcs(funcs)
14291502

@@ -1433,8 +1506,12 @@ function accessor_general.new(opts, funcs)
14331506
service_fields = service_fields,
14341507
indexes = indexes,
14351508
models = models,
1436-
default_unflatten_tuple = default_unflatten_tuple,
1437-
default_flatten_object = default_flatten_object,
1509+
default_unflatten_tuple =
1510+
default_object_tuple_map_funcs.default_unflatten_tuple,
1511+
default_flatten_object =
1512+
default_object_tuple_map_funcs.default_flatten_object,
1513+
default_xflatten =
1514+
default_object_tuple_map_funcs.default_xflatten,
14381515
service_fields_defaults = service_fields_defaults,
14391516
collection_use_tomap = opts.collection_use_tomap or {},
14401517
index_cache = index_cache,
@@ -1461,8 +1538,14 @@ function accessor_general.new(opts, funcs)
14611538
filter, args, extra)
14621539
if inserted ~= nil then return inserted end
14631540

1464-
return select_internal(self, collection_name, from, filter,
1541+
local selected = select_internal(self, collection_name, from, filter,
14651542
args, extra)
1543+
1544+
local updated = update_internal(self, collection_name, from,
1545+
filter, args, extra, selected)
1546+
if updated ~= nil then return updated end
1547+
1548+
return selected
14661549
end,
14671550
list_args = function(self, collection_name)
14681551
local offset_type = get_primary_key_type(self, collection_name)

graphql/accessor_shard.lua

+36
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,26 @@ local function flatten_object(collection_name, obj, opts, default)
136136
return default(collection_name, obj, opts)
137137
end
138138

139+
--- Generate update statements for tarantool from xflatten input.
140+
---
141+
--- @tparam string collection_name
142+
--- @tparam table xobject xflatten input
143+
--- @tparam table opts
144+
--- * `service_fields_defaults` (list (Lua table), default: empty list; list of
145+
--- values to set service fields)
146+
--- @tparam function default xflatten action, call it in the following way:
147+
---
148+
--- return default(collection_name, xobject, opts)
149+
---
150+
--- @treturn cdata/table `tuple`
151+
local function xflatten(collection_name, xobject, opts, default)
152+
local opts = opts or {}
153+
check(opts, 'opts', 'table')
154+
local service_fields_defaults = opts.service_fields_defaults or {}
155+
check(service_fields_defaults, 'service_fields_defaults', 'table')
156+
return default(collection_name, xobject, opts)
157+
end
158+
139159
--- Insert a tuple into a collection.
140160
---
141161
--- @tparam string collection_name
@@ -151,6 +171,20 @@ local function insert_tuple(collection_name, tuple)
151171
return tuples[1]
152172
end
153173

174+
--- Update a tuple with an update statements.
175+
---
176+
--- @tparam string collection_name
177+
---
178+
--- @param key primary key
179+
---
180+
--- @tparam table statements
181+
---
182+
--- @treturn cdata/table `tuple`
183+
local function update_tuple(collection_name, key, statements)
184+
-- XXX
185+
error('NIY')
186+
end
187+
154188
--- Create a new shard data accessor instance.
155189
function accessor_shard.new(opts, funcs)
156190
local funcs = funcs or {}
@@ -173,7 +207,9 @@ function accessor_shard.new(opts, funcs)
173207
get_primary_index = funcs.get_primary_index or get_primary_index,
174208
unflatten_tuple = funcs.unflatten_tuple or unflatten_tuple,
175209
flatten_object = funcs.flatten_object or flatten_object,
210+
xflatten = funcs.xflatten or xflatten,
176211
insert_tuple = funcs.insert_tuple or insert_tuple,
212+
update_tuple = funcs.update_tuple or update_tuple,
177213
}
178214

179215
return accessor_general.new(opts, res_funcs)

graphql/accessor_space.lua

+35
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,26 @@ local function flatten_object(collection_name, obj, opts, default)
6767
return default(collection_name, obj, opts)
6868
end
6969

70+
--- Generate update statements for tarantool from xflatten input.
71+
---
72+
--- @tparam string collection_name
73+
--- @tparam table xobject xflatten input
74+
--- @tparam table opts
75+
--- * `service_fields_defaults` (list (Lua table), default: empty list; list of
76+
--- values to set service fields)
77+
--- @tparam function default xflatten action, call it in the following way:
78+
---
79+
--- return default(collection_name, xobject, opts)
80+
---
81+
--- @treturn cdata/table `tuple`
82+
local function xflatten(collection_name, xobject, opts, default)
83+
local opts = opts or {}
84+
check(opts, 'opts', 'table')
85+
local service_fields_defaults = opts.service_fields_defaults or {}
86+
check(service_fields_defaults, 'service_fields_defaults', 'table')
87+
return default(collection_name, xobject, opts)
88+
end
89+
7090
--- Insert a tuple into a collection.
7191
---
7292
--- @tparam string collection_name
@@ -78,6 +98,19 @@ local function insert_tuple(collection_name, tuple)
7898
return box.space[collection_name]:insert(tuple)
7999
end
80100

101+
--- Update a tuple with an update statements.
102+
---
103+
--- @tparam string collection_name
104+
---
105+
--- @param key primary key
106+
---
107+
--- @tparam table statements
108+
---
109+
--- @treturn cdata/table `tuple`
110+
local function update_tuple(collection_name, key, statements)
111+
return box.space[collection_name]:update(key, statements)
112+
end
113+
81114
--- Create a new space data accessor instance.
82115
function accessor_space.new(opts, funcs)
83116
local funcs = funcs or {}
@@ -98,7 +131,9 @@ function accessor_space.new(opts, funcs)
98131
get_primary_index = funcs.get_primary_index or get_primary_index,
99132
unflatten_tuple = funcs.unflatten_tuple or unflatten_tuple,
100133
flatten_object = funcs.flatten_object or flatten_object,
134+
xflatten = funcs.xflatten or xflatten,
101135
insert_tuple = funcs.insert_tuple or insert_tuple,
136+
update_tuple = funcs.update_tuple or update_tuple,
102137
}
103138

104139
return accessor_general.new(opts, res_funcs)

0 commit comments

Comments
 (0)