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

Commit cbfde2a

Browse files
committed
Support custom unflattener & redefine accessor funcs
Closes #52 (moves responsibility to an user of the library).
1 parent a4be6ee commit cbfde2a

File tree

6 files changed

+399
-30
lines changed

6 files changed

+399
-30
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ default:
44
.PHONY: lint
55
lint:
66
luacheck graphql/*.lua test/local/*.lua test/testdata/*.lua \
7-
test/common/*test.lua test/common/lua/*.lua \
7+
test/common/*.test.lua test/common/lua/*.lua \
88
--no-redefined --no-unused-args
99

1010
.PHONY: test

graphql/accessor_general.lua

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -574,13 +574,12 @@ end
574574
--- Nothing returned, but after necessary count of invokes `state.objs` will
575575
--- hold list of resulting objects.
576576
local function process_tuple(state, tuple, opts)
577-
local function maybe_unflatten(model, tuple, obj)
578-
local ok, obj = model.unflatten(tuple)
579-
assert(ok, 'cannot unflat tuple: ' .. tostring(obj))
580-
return obj
577+
local function maybe_unflatten(tuple, obj, opts)
578+
if obj ~= nil then return obj end
579+
local default = opts.default_unflatten_tuple
580+
return opts.unflatten_tuple(opts.collection_name, tuple, default)
581581
end
582582

583-
local model = opts.model
584583
local limit = opts.limit
585584
local filter = opts.filter
586585
local do_filter = opts.do_filter
@@ -597,15 +596,15 @@ local function process_tuple(state, tuple, opts)
597596
-- skip all items before pivot (the item pointed by offset)
598597
local obj = nil
599598
if not state.pivot_found and pivot_filter then
600-
obj = maybe_unflatten(model, tuple, obj)
599+
obj = maybe_unflatten(tuple, obj, opts)
601600
local match = utils.is_subtable(obj, pivot_filter)
602601
if not match then return true end
603602
state.pivot_found = true
604603
return true -- skip pivot item too
605604
end
606605

607606
-- convert tuple -> object, then filter out or continue
608-
obj = maybe_unflatten(model, tuple, obj)
607+
obj = maybe_unflatten(tuple, obj, opts)
609608
local match = utils.is_subtable(obj, filter)
610609
if do_filter then
611610
if not match then return true end
@@ -698,13 +697,13 @@ local function select_internal(self, collection_name, from, filter, args, extra)
698697
index_name, collection_name))
699698
end
700699

701-
-- lookup compiled schema for unflattening (model)
700+
-- lookup functions for unflattening
702701
local schema_name = collection.schema_name
703702
assert(type(schema_name) == 'string',
704703
'schema_name must be a string, got ' .. type(schema_name))
705-
local model = self.models[schema_name]
706-
assert(model ~= nil,
707-
('cannot find model for collection "%s"'):format(
704+
local default_unflatten_tuple = self.default_unflatten_tuple[schema_name]
705+
assert(default_unflatten_tuple ~= nil,
706+
('cannot find default_unflatten_tuple for collection "%s"'):format(
708707
collection_name))
709708

710709
-- read-write variables for process_tuple
@@ -717,13 +716,15 @@ local function select_internal(self, collection_name, from, filter, args, extra)
717716

718717
-- read only process_tuple options
719718
local select_opts = {
720-
model = model,
721719
limit = args.limit,
722720
filter = filter,
723721
do_filter = not full_match,
724722
pivot_filter = nil, -- filled later if needed
725723
resulting_object_cnt_max = self.settings.resulting_object_cnt_max,
726-
fetched_object_cnt_max = self.settings.fetched_object_cnt_max
724+
fetched_object_cnt_max = self.settings.fetched_object_cnt_max,
725+
collection_name = collection_name,
726+
unflatten_tuple = self.funcs.unflatten_tuple,
727+
default_unflatten_tuple = default_unflatten_tuple,
727728
}
728729

729730
if index == nil then
@@ -803,6 +804,9 @@ local function validate_funcs(funcs)
803804
assert(type(funcs.get_primary_index) == 'function',
804805
'funcs.get_primary_index must be a function, got ' ..
805806
type(funcs.get_primary_index))
807+
assert(type(funcs.unflatten_tuple) == 'function',
808+
'funcs.unflatten_tuple must be a function, got ' ..
809+
type(funcs.unflatten_tuple))
806810
end
807811

808812
--- Create a new data accessor.
@@ -818,10 +822,10 @@ end
818822
--- value is 10,000)_
819823
---
820824
--- @tparam table funcs set of functions (`is_collection_exists`, `get_index`,
821-
--- `get_primary_index`) allows this abstract data accessor behaves in the
822-
--- certain way (say, like space data accessor or shard data accessor);
823-
--- consider the `accessor_space` and the `accessor_shard` modules documentation
824-
--- for this functions description
825+
--- `get_primary_index`, `unflatten_tuple`) allows this abstract data accessor
826+
--- behaves in the certain way (say, like space data accessor or shard data
827+
--- accessor); consider the `accessor_space` and the `accessor_shard` modules
828+
--- documentation for this functions description
825829
---
826830
--- For examples of `opts.schemas` and `opts.collections` consider the
827831
--- @{tarantool_graphql.new} function description.
@@ -885,6 +889,19 @@ function accessor_general.new(opts, funcs)
885889
validate_collections(collections, schemas, indexes)
886890
local index_cache = build_index_cache(indexes, collections)
887891

892+
-- create default unflatten functions, that can be called from
893+
-- funcs.unflatten_tuple when an additional pre/postprocessing is not
894+
-- needed
895+
local default_unflatten_tuple = {}
896+
for schema_name, model in pairs(models) do
897+
default_unflatten_tuple[schema_name] =
898+
function(_, tuple)
899+
local ok, obj = model.unflatten(tuple)
900+
assert(ok, 'cannot unflat tuple: ' .. tostring(obj))
901+
return obj
902+
end
903+
end
904+
888905
validate_funcs(funcs)
889906

890907
return setmetatable({
@@ -893,6 +910,7 @@ function accessor_general.new(opts, funcs)
893910
service_fields = service_fields,
894911
indexes = indexes,
895912
models = models,
913+
default_unflatten_tuple = default_unflatten_tuple,
896914
index_cache = index_cache,
897915
funcs = funcs,
898916
settings = {

graphql/accessor_shard.lua

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,41 @@ local function get_primary_index(collection_name)
8080
return get_index(collection_name, 0)
8181
end
8282

83+
--- Convert a tuple to an object.
84+
---
85+
--- @tparam string collection_name
86+
--- @tparam cdata/table tuple
87+
--- @tparam function default unflatten action, call it in the following way:
88+
---
89+
--- ```
90+
--- return default(collection_name, tuple)
91+
--- ```
92+
local function unflatten_tuple(collection_name, tuple, default)
93+
return default(collection_name, tuple)
94+
end
95+
8396
--- Create a new shard data accessor instance.
84-
function accessor_shard.new(opts)
85-
local funcs = {
86-
is_collection_exists = is_collection_exists,
87-
get_index = get_index,
88-
get_primary_index = get_primary_index,
97+
function accessor_shard.new(opts, funcs)
98+
local funcs = funcs or {}
99+
assert(type(funcs) == 'table',
100+
'funcs must be nil or a table, got ' .. type(funcs))
101+
102+
for k, v in pairs(funcs) do
103+
assert(type(k) == 'string',
104+
'funcs keys must be strings, got ' .. type(k))
105+
assert(type(v) == 'table',
106+
'funcs values must be functions, got ' .. type(v))
107+
end
108+
109+
local res_funcs = {
110+
is_collection_exists = funcs.is_collection_exists or
111+
is_collection_exists,
112+
get_index = funcs.get_index or get_index,
113+
get_primary_index = funcs.get_primary_index or get_primary_index,
114+
unflatten_tuple = funcs.unflatten_tuple or unflatten_tuple,
89115
}
90-
return accessor_general.new(opts, funcs)
116+
117+
return accessor_general.new(opts, res_funcs)
91118
end
92119

93120
return accessor_shard

graphql/accessor_space.lua

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,41 @@ local function get_primary_index(collection_name)
2222
return box.space[collection_name].index[0]
2323
end
2424

25+
--- Convert a tuple to an object.
26+
---
27+
--- @tparam string collection_name
28+
--- @tparam cdata/table tuple
29+
--- @tparam function default unflatten action, call it in the following way:
30+
---
31+
--- ```
32+
--- return default(collection_name, tuple)
33+
--- ```
34+
local function unflatten_tuple(collection_name, tuple, default)
35+
return default(collection_name, tuple)
36+
end
37+
2538
--- Create a new space data accessor instance.
26-
function accessor_space.new(opts)
27-
local funcs = {
28-
is_collection_exists = is_collection_exists,
29-
get_index = get_index,
30-
get_primary_index = get_primary_index,
39+
function accessor_space.new(opts, funcs)
40+
local funcs = funcs or {}
41+
assert(type(funcs) == 'table',
42+
'funcs must be nil or a table, got ' .. type(funcs))
43+
44+
for k, v in pairs(funcs) do
45+
assert(type(k) == 'string',
46+
'funcs keys must be strings, got ' .. type(k))
47+
assert(type(v) == 'function',
48+
'funcs values must be functions, got ' .. type(v))
49+
end
50+
51+
local res_funcs = {
52+
is_collection_exists = funcs.is_collection_exists or
53+
is_collection_exists,
54+
get_index = funcs.get_index or get_index,
55+
get_primary_index = funcs.get_primary_index or get_primary_index,
56+
unflatten_tuple = funcs.unflatten_tuple or unflatten_tuple,
3157
}
32-
return accessor_general.new(opts, funcs)
58+
59+
return accessor_general.new(opts, res_funcs)
3360
end
3461

3562
return accessor_space

0 commit comments

Comments
 (0)