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

Commit 74542d1

Browse files
committed
WIP: Implement update mutation
Part of #142.
1 parent 373d9ef commit 74542d1

File tree

7 files changed

+589
-52
lines changed

7 files changed

+589
-52
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, then connected objects are selected.
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
@@ -1146,6 +1146,50 @@ local function insert_internal(self, collection_name, from, filter, args, extra)
11461146
return {new_object}
11471147
end
11481148

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

11771227
--- This function is called on first select related to a query. Its purpose is
@@ -1294,6 +1344,60 @@ local function get_pcre_argument_type(self, collection_name)
12941344
return pcre_type
12951345
end
12961346

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

14301503
validate_funcs(funcs)
14311504

@@ -1435,8 +1508,12 @@ function accessor_general.new(opts, funcs)
14351508
service_fields = service_fields,
14361509
indexes = indexes,
14371510
models = models,
1438-
default_unflatten_tuple = default_unflatten_tuple,
1439-
default_flatten_object = default_flatten_object,
1511+
default_unflatten_tuple =
1512+
default_object_tuple_map_funcs.default_unflatten_tuple,
1513+
default_flatten_object =
1514+
default_object_tuple_map_funcs.default_flatten_object,
1515+
default_xflatten =
1516+
default_object_tuple_map_funcs.default_xflatten,
14401517
service_fields_defaults = service_fields_defaults,
14411518
collection_use_tomap = opts.collection_use_tomap or {},
14421519
index_cache = index_cache,
@@ -1463,8 +1540,14 @@ function accessor_general.new(opts, funcs)
14631540
filter, args, extra)
14641541
if inserted ~= nil then return inserted end
14651542

1466-
return select_internal(self, collection_name, from, filter,
1543+
local selected = select_internal(self, collection_name, from, filter,
14671544
args, extra)
1545+
1546+
local updated = update_internal(self, collection_name, from,
1547+
filter, args, extra, selected)
1548+
if updated ~= nil then return updated end
1549+
1550+
return selected
14681551
end,
14691552
list_args = function(self, collection_name)
14701553
local offset_type = get_primary_key_type(self, collection_name)

0 commit comments

Comments
 (0)