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

Commit 71b39a0

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

File tree

7 files changed

+525
-50
lines changed

7 files changed

+525
-50
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

+120-36
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,51 @@ 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+
-- XXX: we can pass tuple to update_tuple to save one get operation
1184+
local new_tuple = self.funcs.update_tuple(collection_name, key,
1185+
statements)
1186+
local new_object = self.funcs.unflatten_tuple(collection_name,
1187+
new_tuple, {use_tomap = self.collection_use_tomap[collection_name]},
1188+
self.default_unflatten_tuple[schema_name])
1189+
table.insert(new_objects, new_object)
1190+
end
1191+
1192+
return new_objects
1193+
end
1194+
11501195
--- Set of asserts to check the `funcs` argument of the @{accessor_general.new}
11511196
--- function.
11521197
--- @tparam table funcs set of function as defined in the
@@ -1170,9 +1215,15 @@ local function validate_funcs(funcs)
11701215
assert(type(funcs.flatten_object) == 'function',
11711216
'funcs.flatten_object must be a function, got ' ..
11721217
type(funcs.flatten_object))
1218+
assert(type(funcs.xflatten) == 'function',
1219+
'funcs.xflatten must be a function, got ' ..
1220+
type(funcs.xflatten))
11731221
assert(type(funcs.insert_tuple) == 'function',
11741222
'funcs.insert_tuple must be a function, got ' ..
11751223
type(funcs.insert_tuple))
1224+
assert(type(funcs.update_tuple) == 'function',
1225+
'funcs.update_tuple must be a function, got ' ..
1226+
type(funcs.update_tuple))
11761227
end
11771228

11781229
--- This function is called on first select related to a query. Its purpose is
@@ -1292,6 +1343,60 @@ local function get_pcre_argument_type(self, collection_name)
12921343
return pcre_type
12931344
end
12941345

1346+
--- Create default unflatten/flatten/xflatten functions, that can be called
1347+
--- from funcs.unflatten_tuple/funcs.flatten_object/funcs.xflatten when an
1348+
--- additional pre/postprocessing is not needed.
1349+
---
1350+
--- @tparam table models list of compiled schemas
1351+
---
1352+
--- @treturn table table with default_* fields with maps from schema name to
1353+
--- the corresponding default *flatten function
1354+
local function gen_default_object_tuple_map_funcs(models)
1355+
local default_unflatten_tuple = {}
1356+
local default_flatten_object = {}
1357+
local default_xflatten = {}
1358+
for schema_name, model in pairs(models) do
1359+
default_unflatten_tuple[schema_name] = function(_, tuple, opts)
1360+
local opts = opts or {}
1361+
check(opts, 'opts', 'table')
1362+
1363+
local ok, obj = model.unflatten(tuple)
1364+
assert(ok, ('cannot unflat tuple of schema "%s": %s'):format(
1365+
schema_name, tostring(obj)))
1366+
return obj
1367+
end
1368+
default_flatten_object[schema_name] = function(_, obj, opts)
1369+
local opts = opts or {}
1370+
check(opts, 'opts', 'table')
1371+
local sf_defaults = opts.service_fields_defaults or {}
1372+
check(sf_defaults, 'service_fields_defaults', 'table')
1373+
1374+
local ok, tuple = model.flatten(obj, unpack(sf_defaults))
1375+
assert(ok, ('cannot flat object of schema "%s": %s'):format(
1376+
schema_name, tostring(tuple)))
1377+
return tuple
1378+
end
1379+
default_xflatten[schema_name] = function(_, xobject, opts)
1380+
local opts = opts or {}
1381+
check(opts, 'opts', 'table')
1382+
1383+
-- it is not needed now, but maybe needed in custom xflatten
1384+
local sf_defaults = opts.service_fields_defaults or {}
1385+
check(sf_defaults, 'service_fields_defaults', 'table')
1386+
1387+
local ok, statements = model.xflatten(xobject)
1388+
assert(ok, ('cannot xflat xobject of schema "%s": %s'):format(
1389+
schema_name, tostring(xobject)))
1390+
return statements
1391+
end
1392+
end
1393+
return {
1394+
default_unflatten_tuple = default_unflatten_tuple,
1395+
default_flatten_object = default_flatten_object,
1396+
default_xflatten = default_xflatten,
1397+
}
1398+
end
1399+
12951400
--- Create a new data accessor.
12961401
---
12971402
--- Provided `funcs` argument determines certain functions for retrieving
@@ -1391,39 +1496,8 @@ function accessor_general.new(opts, funcs)
13911496
service_fields)
13921497
validate_collections(collections, schemas, indexes)
13931498
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
1499+
local default_object_tuple_map_funcs =
1500+
gen_default_object_tuple_map_funcs(models)
14271501

14281502
validate_funcs(funcs)
14291503

@@ -1433,8 +1507,12 @@ function accessor_general.new(opts, funcs)
14331507
service_fields = service_fields,
14341508
indexes = indexes,
14351509
models = models,
1436-
default_unflatten_tuple = default_unflatten_tuple,
1437-
default_flatten_object = default_flatten_object,
1510+
default_unflatten_tuple =
1511+
default_object_tuple_map_funcs.default_unflatten_tuple,
1512+
default_flatten_object =
1513+
default_object_tuple_map_funcs.default_flatten_object,
1514+
default_xflatten =
1515+
default_object_tuple_map_funcs.default_xflatten,
14381516
service_fields_defaults = service_fields_defaults,
14391517
collection_use_tomap = opts.collection_use_tomap or {},
14401518
index_cache = index_cache,
@@ -1461,8 +1539,14 @@ function accessor_general.new(opts, funcs)
14611539
filter, args, extra)
14621540
if inserted ~= nil then return inserted end
14631541

1464-
return select_internal(self, collection_name, from, filter,
1542+
local selected = select_internal(self, collection_name, from, filter,
14651543
args, extra)
1544+
1545+
local updated = update_internal(self, collection_name, from,
1546+
filter, args, extra, selected)
1547+
if updated ~= nil then return updated end
1548+
1549+
return selected
14661550
end,
14671551
list_args = function(self, collection_name)
14681552
local offset_type = get_primary_key_type(self, collection_name)

0 commit comments

Comments
 (0)