@@ -8,6 +8,12 @@ local json = require('json')
8
8
local avro_schema = require (' avro_schema' )
9
9
local utils = require (' graphql.utils' )
10
10
local clock = require (' clock' )
11
+ local rex = utils .optional_require (' rex_pcre' )
12
+
13
+ -- XXX: consider using [1] when it will be mature enough;
14
+ -- look into [2] for the status.
15
+ -- [1]: https://github.com/igormunkin/lua-re
16
+ -- [2]: https://github.com/tarantool/tarantool/issues/2764
11
17
12
18
local accessor_general = {}
13
19
local DEF_RESULTING_OBJECT_CNT_MAX = 10000
@@ -696,6 +702,28 @@ local function validate_collections(collections, schemas)
696
702
end
697
703
end
698
704
705
+ --- XXX
706
+ local function match_using_re (obj , pcre )
707
+ if pcre == nil then return true end
708
+
709
+ for field_name , re in pairs (pcre ) do
710
+ -- skip an object with null in a string* field
711
+ if obj [field_name ] == nil then
712
+ return false
713
+ end
714
+ assert (rex ~= nil , ' we should not pass over :compile() ' ..
715
+ ' with a query contains PCRE matching when there are ' ..
716
+ ' no lrexlib-pcre (rex_pcre) module present' )
717
+ -- XXX: compile re once
718
+ local re = rex .new (re )
719
+ if not re :match (obj [field_name ]) then
720
+ return false
721
+ end
722
+ end
723
+
724
+ return true
725
+ end
726
+
699
727
--- Perform unflatten, skipping, filtering, limiting of objects. This is the
700
728
--- core of the `select_internal` function.
701
729
---
@@ -741,9 +769,11 @@ local function process_tuple(state, tuple, opts)
741
769
qstats .fetched_object_cnt , fetched_object_cnt_max ))
742
770
assert (qcontext .deadline_clock > clock .monotonic64 (),
743
771
' query execution timeout exceeded, use `timeout_ms` to increase it' )
772
+ local collection_name = opts .collection_name
773
+ local pcre = opts .pcre
744
774
745
775
-- convert tuple -> object
746
- local obj = opts .unflatten_tuple (opts . collection_name , tuple ,
776
+ local obj = opts .unflatten_tuple (collection_name , tuple ,
747
777
opts .default_unflatten_tuple )
748
778
749
779
-- skip all items before pivot (the item pointed by offset)
@@ -755,7 +785,8 @@ local function process_tuple(state, tuple, opts)
755
785
end
756
786
757
787
-- filter out non-matching objects
758
- local match = utils .is_subtable (obj , filter )
788
+ local match = utils .is_subtable (obj , filter ) and
789
+ match_using_re (obj , pcre )
759
790
if do_filter then
760
791
if not match then return true end
761
792
else
@@ -828,6 +859,8 @@ local function select_internal(self, collection_name, from, filter, args, extra)
828
859
-- XXX: save type at parsing and check here
829
860
-- assert(args.offset == nil or type(args.offset) == 'number',
830
861
-- 'args.offset must be a number of nil, got ' .. type(args.offset))
862
+ assert (args .pcre == nil or type (args .pcre ) == ' table' ,
863
+ ' args.pcre must be nil or a table, got ' .. type (args .pcre ))
831
864
832
865
local collection = self .collections [collection_name ]
833
866
assert (collection ~= nil ,
@@ -876,6 +909,7 @@ local function select_internal(self, collection_name, from, filter, args, extra)
876
909
collection_name = collection_name ,
877
910
unflatten_tuple = self .funcs .unflatten_tuple ,
878
911
default_unflatten_tuple = default_unflatten_tuple ,
912
+ pcre = args .pcre ,
879
913
}
880
914
881
915
if index == nil then
@@ -976,6 +1010,87 @@ local function init_qcontext(accessor, qcontext)
976
1010
settings .timeout_ms * 1000 * 1000
977
1011
end
978
1012
1013
+ --- XXX
1014
+ local function get_primary_key_type (self , collection_name )
1015
+ -- get name of field of primary key
1016
+ local _ , index_meta = get_primary_index_meta (
1017
+ self , collection_name )
1018
+
1019
+ local offset_fields = {}
1020
+
1021
+ for _ , field_name in ipairs (index_meta .fields ) do
1022
+ local field_type
1023
+ local collection = self .collections [collection_name ]
1024
+ local schema = self .schemas [collection .schema_name ]
1025
+ for _ , field in ipairs (schema .fields ) do
1026
+ if field .name == field_name then
1027
+ field_type = field .type
1028
+ end
1029
+ end
1030
+ assert (field_type ~= nil ,
1031
+ (' cannot find type for primary index field "%s" ' ..
1032
+ ' for collection "%s"' ):format (field_name ,
1033
+ collection_name ))
1034
+ assert (type (field_type ) == ' string' ,
1035
+ ' field type must be a string, got ' ..
1036
+ type (field_type ))
1037
+ offset_fields [# offset_fields + 1 ] = {
1038
+ name = field_name ,
1039
+ type = field_type ,
1040
+ }
1041
+ end
1042
+
1043
+ local offset_type
1044
+ assert (# offset_fields > 0 ,
1045
+ ' offset must contain at least one field' )
1046
+ if # offset_fields == 1 then
1047
+ -- use a scalar type
1048
+ offset_type = offset_fields [1 ].type
1049
+ else
1050
+ -- construct an input type
1051
+ offset_type = {
1052
+ name = collection_name .. ' _offset' ,
1053
+ type = ' record' ,
1054
+ fields = offset_fields ,
1055
+ }
1056
+ end
1057
+
1058
+ return offset_type
1059
+ end
1060
+
1061
+ -- XXX: add string fields of a nested record / 1:1 connection
1062
+
1063
+ --- XXX
1064
+ --- Note: it is only for list of objects and is not for destination of 1:1
1065
+ --- connection
1066
+ local function get_pcre_argument_type (self , collection_name )
1067
+ local collection = self .collections [collection_name ]
1068
+ assert (collection ~= nil , ' cannot found collection ' ..
1069
+ tostring (collection_name ))
1070
+ local schema = self .schemas [collection .schema_name ]
1071
+ assert (schema ~= nil , ' cannot found schema ' ..
1072
+ tostring (collection .schema_name ))
1073
+
1074
+ assert (schema .type == ' record' ,
1075
+ ' top-level object expected to be a record, got ' ..
1076
+ tostring (schema .type ))
1077
+
1078
+ local string_fields = {}
1079
+
1080
+ for _ , field in ipairs (schema .fields ) do
1081
+ if field .type == ' string' or field .type == ' string*' then
1082
+ string_fields [# string_fields + 1 ] = table .copy (field )
1083
+ end
1084
+ end
1085
+
1086
+ local pcre_type = {
1087
+ name = collection_name .. ' _pcre' ,
1088
+ type = ' record' ,
1089
+ fields = string_fields ,
1090
+ }
1091
+ return pcre_type
1092
+ end
1093
+
979
1094
--- Create a new data accessor.
980
1095
---
981
1096
--- Provided `funcs` argument determines certain functions for retrieving
@@ -1114,53 +1229,20 @@ function accessor_general.new(opts, funcs)
1114
1229
args , extra )
1115
1230
end ,
1116
1231
list_args = function (self , collection_name )
1117
- -- get name of field of primary key
1118
- local _ , index_meta = get_primary_index_meta (
1119
- self , collection_name )
1120
-
1121
- local offset_fields = {}
1122
-
1123
- for _ , field_name in ipairs (index_meta .fields ) do
1124
- local field_type
1125
- local collection = self .collections [collection_name ]
1126
- local schema = self .schemas [collection .schema_name ]
1127
- for _ , field in ipairs (schema .fields ) do
1128
- if field .name == field_name then
1129
- field_type = field .type
1130
- end
1131
- end
1132
- assert (field_type ~= nil ,
1133
- (' cannot find type for primary index field "%s" ' ..
1134
- ' for collection "%s"' ):format (field_name ,
1135
- collection_name ))
1136
- assert (type (field_type ) == ' string' ,
1137
- ' field type must be a string, got ' ..
1138
- type (field_type ))
1139
- offset_fields [# offset_fields + 1 ] = {
1140
- name = field_name ,
1141
- type = field_type ,
1142
- }
1143
- end
1232
+ local offset_type = get_primary_key_type (self , collection_name )
1144
1233
1145
- local offset_type
1146
- assert (# offset_fields > 0 ,
1147
- ' offset must contain at least one field' )
1148
- if # offset_fields == 1 then
1149
- -- use a scalar type
1150
- offset_type = offset_fields [1 ].type
1151
- else
1152
- -- construct an input type
1153
- offset_type = {
1154
- name = collection_name .. ' _offset' ,
1155
- type = ' record' ,
1156
- fields = offset_fields ,
1157
- }
1234
+ -- add `pcre` argument only if lrexlib-pcre was found
1235
+ local pcre_field
1236
+ if rex ~= nil then
1237
+ local pcre_type = get_pcre_argument_type (self , collection_name )
1238
+ pcre_field = {name = ' pcre' , type = pcre_type }
1158
1239
end
1159
1240
1160
1241
return {
1161
1242
{name = ' limit' , type = ' int' },
1162
1243
{name = ' offset' , type = offset_type },
1163
1244
-- {name = 'filter', type = ...},
1245
+ pcre_field ,
1164
1246
}
1165
1247
end ,
1166
1248
}
0 commit comments