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

Commit 61a8ac0

Browse files
committed
enable calling tarantool_graphql.new() with expanded config (indexes
and service_fields) and accessor type to create tarantool_graphql with default accessor
1 parent d67ddf8 commit 61a8ac0

7 files changed

+1111
-1
lines changed

graphql/tarantool_graphql.lua

Lines changed: 204 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ local types = require('graphql.core.types')
3939
local validate = require('graphql.core.validate')
4040
local execute = require('graphql.core.execute')
4141
local query_to_avro = require('graphql.query_to_avro')
42+
local accessor_space = require('graphql.accessor_space')
43+
local accessor_shard = require('graphql.accessor_shard')
4244

4345
local utils = require('graphql.utils')
4446

@@ -1029,6 +1031,195 @@ local function gql_compile(state, query)
10291031
return gql_query
10301032
end
10311033

1034+
--- The function creates an accessor of desired type with default configuration
1035+
---
1036+
--- @tparam table cfg general tarantool_graphql config (contains schemas,
1037+
--- collections, service_fields and indexes
1038+
--- @tparam string accessorType type of desired accessor (space or shard)
1039+
--- @tparam table accessorFuncs set of functions to overwrite accessor
1040+
--- inner functions (`is_collection_exists`, `get_index`, `get_primary_index`,
1041+
--- `unflatten_tuple`, For more devitalised description see @{accessor_general.new})
1042+
--- These function allow this abstract data accessor behaves in the certain way.
1043+
--- Note that accessor_space and accessor_shard have their own set of these functions
1044+
--- and accessorFuncs argument (if passed) will be used to overwrite them
1045+
local function createAccessor(cfg, accessorType, accessorFuncs)
1046+
assert(type(accessorType) == 'string', 'accessorType must be a ' ..
1047+
'string, got ' .. type(accessorType))
1048+
assert(accessorType == 'space' or accessorType == 'shard',
1049+
'accessorType must be shard or space, got ' .. accessorType)
1050+
1051+
assert(accessorFuncs == nil or type(accessorFuncs) == 'table',
1052+
'accessorFuncs must be nil or a table, got ' .. type(accessorFuncs))
1053+
1054+
assert(type(cfg.service_fields) == 'table', 'cfg.service_fields must be ' ..
1055+
'a table, got ' .. type(cfg.service_fields))
1056+
assert(type(cfg.indexes) == 'table', 'cfg.indexes must be ' ..
1057+
'a table, got ' .. type(cfg.indexes))
1058+
1059+
if accessorType == 'space' then
1060+
return accessor_space.new({
1061+
schemas = cfg.schemas,
1062+
collections = cfg.collections,
1063+
service_fields = cfg.service_fields,
1064+
indexes = cfg.indexes
1065+
})
1066+
end
1067+
1068+
if accessorType == 'shard' then
1069+
return accessor_shard.new({
1070+
schemas = cfg.schemas,
1071+
collections = cfg.collections,
1072+
service_fields = cfg.service_fields,
1073+
indexes = cfg.indexes
1074+
});
1075+
end
1076+
end
1077+
1078+
1079+
local function is_system_space(space)
1080+
local BOX_SYSTEM_ID_MIN = 256
1081+
local BOX_SYSTEM_ID_MAX = 511
1082+
local space_id = space[1]
1083+
return (BOX_SYSTEM_ID_MIN < space_id and space_id < BOX_SYSTEM_ID_MAX)
1084+
end
1085+
1086+
--- XXX should add types compatibility check (to avoid overflow and errors)
1087+
local function convert_index_type_to_avro(index_type)
1088+
-- unsigned | string | integer | number | boolean | array | scalar
1089+
assert(type(index_type) == 'string', 'index_type must be a string, got ' ..
1090+
type(index_type))
1091+
1092+
local t = index_type
1093+
1094+
if t == 'unsigned' then
1095+
return 'long'
1096+
end
1097+
1098+
if t == 'string' then
1099+
return 'string'
1100+
end
1101+
1102+
if t == 'integer' then
1103+
return 'long'
1104+
end
1105+
1106+
if t == 'number' then
1107+
return 'double'
1108+
end
1109+
1110+
if t == 'boolean' then
1111+
return 'boolean'
1112+
end
1113+
1114+
if t == 'array' then
1115+
return {['type'] = 'array', items = {['type'] = 'int', name = 'point'}}
1116+
end
1117+
1118+
if t == 'scalar' then
1119+
error('scalar type conversion (tarantool types -> avro) is not ' ..
1120+
'implemented yet')
1121+
end
1122+
1123+
error('unrecognized index_type: ' .. json.encode(index_type))
1124+
end
1125+
1126+
--todo explain
1127+
--- XXX no nested fields (no nested records) because of ...
1128+
local function generate_avro_scheme(space_format, schema_name)
1129+
assert(type(space_format) == 'table', 'space_format must be a table, ' ..
1130+
'got ' .. type(space_format))
1131+
assert(type(schema_name) == 'string', 'schema_name must be a table, ' ..
1132+
'got ' .. type(schema_name))
1133+
1134+
local avro_schema = {['type'] = 'record', name = schema_name, fields = {}}
1135+
for i, f in ipairs(space_format) do
1136+
assert(type(f.name) == 'string', 'field format name must be a ' ..
1137+
'string, got ' .. type(f.name))
1138+
assert(type(f.type) == 'string', 'field format type must be a ' ..
1139+
'string, got ' .. type(f.type))
1140+
1141+
avro_schema.fields[i] = {f.name, convert_index_type_to_avro(f.type)}
1142+
end
1143+
return avro_schema
1144+
end
1145+
1146+
1147+
local function convert_index_type(index_type)
1148+
1149+
if index_type == 'TREE' then
1150+
return 'tree'
1151+
end
1152+
1153+
1154+
end
1155+
1156+
--- The function creates a graphql config
1157+
---
1158+
--- @treturn table cfg with `schemas`, `service_fields`,
1159+
--- `indexes`
1160+
---
1161+
--- XXX service_fields collection is not implemented yet
1162+
local function graphql_cfg_from_tarantool()
1163+
local cfg = {}
1164+
cfg.schemas = {}
1165+
for _, s in box.space._space:pairs() do
1166+
if not is_system_space(s) then
1167+
local format = s[7]
1168+
local space_title = s[3]
1169+
cfg.schemas[space_title] = generate_avro_scheme(format, space_title)
1170+
1171+
--require('pl.pretty').dump(box.space[s[3]].index[0].type)
1172+
1173+
local collection_indexes = {}
1174+
local i = 0
1175+
local index = box.space[space_title].index[i]
1176+
while index ~= nil do
1177+
local collection_index = {}
1178+
collection_index.index_type = convert_index_type(index.type)
1179+
collection_index.unique = index.unique
1180+
--todo primary
1181+
1182+
if index.name == box.space[space_title].primary then
1183+
collection_index.primary = true
1184+
else
1185+
collection_index.primary = false
1186+
end
1187+
collection_index.primary = index.primary
1188+
collection_index.fields = {}
1189+
--todo service_fields
1190+
--collection_index.service_fields =
1191+
--todo convert from TREE to tree
1192+
--todo titles
1193+
1194+
-- get names
1195+
1196+
for _, part in pairs(index.parts) do
1197+
collection_index.fields[#collection_index.fields + 1] = format[part.fieldno].name
1198+
end
1199+
1200+
--require('pl.pretty').dump(index.parts)
1201+
--print(index.type)
1202+
----?
1203+
--print(index.primary)
1204+
--print(index.unique)
1205+
1206+
collection_indexes[index.name] = collection_index
1207+
require('pl.pretty').dump(collection_index)
1208+
1209+
i = i + 1
1210+
index = box.space[space_title].index[i]
1211+
end
1212+
cfg.indexes[space_title] = collection_indexes
1213+
end
1214+
end
1215+
1216+
--service_fields
1217+
-- indexes
1218+
-- transform it into graphql terms
1219+
-- build objects
1220+
return cfg
1221+
end
1222+
10321223
--- Create a tarantool_graphql library instance.
10331224
---
10341225
--- Usage:
@@ -1101,7 +1292,19 @@ end
11011292
--- }
11021293
--- }),
11031294
--- })
1104-
function tarantool_graphql.new(cfg)
1295+
function tarantool_graphql.new(cfg, accessorType, accessorFuncs)
1296+
1297+
local cfg = cfg
1298+
if cfg == nil then
1299+
cfg = graphql_cfg_from_tarantool()
1300+
end
1301+
if accessorType ~= nil then
1302+
assert(cfg.accessor == nil, 'cfg.accessor (custom accessor) and ' ..
1303+
'accessorType (type of desired default accessor) both are not ' ..
1304+
'nil. It is an ambiguous call')
1305+
cfg.accessor = createAccessor(cfg, accessorType, accessorFuncs)
1306+
end
1307+
11051308
local state = parse_cfg(cfg)
11061309
return setmetatable(state, {
11071310
__index = {

0 commit comments

Comments
 (0)