@@ -39,6 +39,8 @@ local types = require('graphql.core.types')
39
39
local validate = require (' graphql.core.validate' )
40
40
local execute = require (' graphql.core.execute' )
41
41
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' )
42
44
43
45
local utils = require (' graphql.utils' )
44
46
@@ -1029,6 +1031,195 @@ local function gql_compile(state, query)
1029
1031
return gql_query
1030
1032
end
1031
1033
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
+
1032
1223
--- Create a tarantool_graphql library instance.
1033
1224
---
1034
1225
--- Usage:
@@ -1101,7 +1292,19 @@ end
1101
1292
--- }
1102
1293
--- }),
1103
1294
--- })
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
+
1105
1308
local state = parse_cfg (cfg )
1106
1309
return setmetatable (state , {
1107
1310
__index = {
0 commit comments