norikra 1.1.2-java → 1.2.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Changes.md +4 -0
- data/Gemfile +4 -0
- data/README.md +3 -6
- data/lib/norikra/cli.rb +54 -54
- data/lib/norikra/engine.rb +91 -44
- data/lib/norikra/field.rb +12 -7
- data/lib/norikra/fieldset.rb +26 -13
- data/lib/norikra/listener.rb +192 -61
- data/lib/norikra/logger.rb +34 -10
- data/lib/norikra/output_pool.rb +1 -1
- data/lib/norikra/query/ast.rb +240 -20
- data/lib/norikra/query.rb +103 -46
- data/lib/norikra/rpc/handler.rb +3 -3
- data/lib/norikra/rpc/http.rb +1 -1
- data/lib/norikra/server.rb +34 -28
- data/lib/norikra/stats.rb +3 -3
- data/lib/norikra/target.rb +1 -1
- data/lib/norikra/typedef.rb +22 -17
- data/lib/norikra/typedef_manager.rb +9 -6
- data/lib/norikra/udf.rb +6 -2
- data/lib/norikra/version.rb +1 -1
- data/lib/norikra/webui/api.rb +3 -3
- data/lib/norikra/webui/handler.rb +6 -6
- data/norikra.gemspec +0 -1
- data/script/{spec_server_pry → pry} +0 -24
- data/spec/field_spec.rb +14 -0
- data/spec/fieldset_spec.rb +111 -0
- data/spec/listener_spec.rb +64 -26
- data/spec/query_spec.rb +171 -25
- data/spec/spec_helper.rb +0 -46
- data/spec/typedef_manager_spec.rb +15 -9
- data/spec/typedef_spec.rb +11 -11
- metadata +3 -19
- data/lib/norikra/rpc/error.rb +0 -0
- data/lib/norikra/rubyudf.rb +0 -49
data/lib/norikra/query/ast.rb
CHANGED
@@ -717,6 +717,125 @@ module Norikra
|
|
717
717
|
# ")"]]]]]]]]],
|
718
718
|
# "<EOF>"]
|
719
719
|
|
720
|
+
#### SELECT a,NULLABLE(b),COUNT(DISTINCT NULLABLE(c)) FROM t GROUP BY a,NULLABLE(b)
|
721
|
+
|
722
|
+
# ["startEPLExpressionRule",
|
723
|
+
# ["eplExpression",
|
724
|
+
# ["selectExpr",
|
725
|
+
# "SELECT",
|
726
|
+
# ["selectClause",
|
727
|
+
# ["selectionList",
|
728
|
+
# ["selectionListElement",
|
729
|
+
# ["selectionListElementExpr",
|
730
|
+
# ["expression",
|
731
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",["negatedExpression",
|
732
|
+
# ["evalEqualsExpression",["evalRelationalExpression",["concatenationExpr",["additiveExpression",
|
733
|
+
# ["multiplyExpression",["unaryExpression",
|
734
|
+
# ["eventPropertyOrLibFunction",
|
735
|
+
# ["eventProperty",
|
736
|
+
# ["eventPropertyAtomic", ["eventPropertyIdent", ["keywordAllowedIdent", "a"]]]]]]]]]]]]]]]]]]],
|
737
|
+
# ",",
|
738
|
+
# ["selectionListElement",
|
739
|
+
# ["selectionListElementExpr",
|
740
|
+
# ["expression",
|
741
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",["negatedExpression",
|
742
|
+
# ["evalEqualsExpression",["evalRelationalExpression",["concatenationExpr",["additiveExpression",
|
743
|
+
# ["multiplyExpression",["unaryExpression",
|
744
|
+
# ["eventPropertyOrLibFunction",
|
745
|
+
# ["libFunction",
|
746
|
+
# ["libFunctionWithClass",
|
747
|
+
# ["funcIdentTop", ["escapableIdent", "NULLABLE"]],
|
748
|
+
# "(",
|
749
|
+
# ["libFunctionArgs",
|
750
|
+
# ["libFunctionArgItem",
|
751
|
+
# ["expressionWithTime",
|
752
|
+
# ["expressionQualifyable",
|
753
|
+
# ["expression",
|
754
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",
|
755
|
+
# ["negatedExpression",["evalEqualsExpression",["evalRelationalExpression",
|
756
|
+
# ["concatenationExpr",["additiveExpression",["multiplyExpression",["unaryExpression",
|
757
|
+
# ["eventPropertyOrLibFunction",
|
758
|
+
# ["eventProperty",
|
759
|
+
# ["eventPropertyAtomic",
|
760
|
+
# ["eventPropertyIdent", ["keywordAllowedIdent", "b"]]]]]]]]]]]]]]]]]]]]],
|
761
|
+
# ")"]]]]]]]]]]]]]]]]],
|
762
|
+
# ",",
|
763
|
+
# ["selectionListElement",
|
764
|
+
# ["selectionListElementExpr",
|
765
|
+
# ["expression",
|
766
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",["negatedExpression",
|
767
|
+
# ["evalEqualsExpression",["evalRelationalExpression",["concatenationExpr",["additiveExpression",
|
768
|
+
# ["multiplyExpression",["unaryExpression",
|
769
|
+
# ["builtinFunc",
|
770
|
+
# "COUNT",
|
771
|
+
# "(",
|
772
|
+
# "DISTINCT",
|
773
|
+
# ["expression",
|
774
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",
|
775
|
+
# ["negatedExpression",["evalEqualsExpression",["evalRelationalExpression",
|
776
|
+
# ["concatenationExpr",["additiveExpression",["multiplyExpression",["unaryExpression",
|
777
|
+
# ["eventPropertyOrLibFunction",
|
778
|
+
# ["libFunction",
|
779
|
+
# ["libFunctionWithClass",
|
780
|
+
# ["funcIdentTop", ["escapableIdent", "NULLABLE"]],
|
781
|
+
# "(",
|
782
|
+
# ["libFunctionArgs",
|
783
|
+
# ["libFunctionArgItem",
|
784
|
+
# ["expressionWithTime",
|
785
|
+
# ["expressionQualifyable",
|
786
|
+
# ["expression",
|
787
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",
|
788
|
+
# ["negatedExpression",["evalEqualsExpression",["evalRelationalExpression",
|
789
|
+
# ["concatenationExpr",["additiveExpression",["multiplyExpression",
|
790
|
+
# ["unaryExpression",
|
791
|
+
# ["eventPropertyOrLibFunction",
|
792
|
+
# ["eventProperty",
|
793
|
+
# ["eventPropertyAtomic",
|
794
|
+
# ["eventPropertyIdent",
|
795
|
+
# ["keywordAllowedIdent", "c"]]]]]]]]]]]]]]]]]]]]],
|
796
|
+
# ")"]]]]]]]]]]]]]]],
|
797
|
+
# ")"]]]]]]]]]]]]]]]]],
|
798
|
+
# "FROM",
|
799
|
+
# ["fromClause",
|
800
|
+
# ["streamExpression", ["eventFilterExpression", ["classIdentifier", ["escapableStr", "t"]]]],
|
801
|
+
# "regularJoin"],
|
802
|
+
# "GROUP",
|
803
|
+
# "BY",
|
804
|
+
# ["groupByListExpr",
|
805
|
+
# ["groupByListChoice",
|
806
|
+
# ["expression",
|
807
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",["negatedExpression",
|
808
|
+
# ["evalEqualsExpression",["evalRelationalExpression",["concatenationExpr",["additiveExpression",
|
809
|
+
# ["multiplyExpression",["unaryExpression",
|
810
|
+
# ["eventPropertyOrLibFunction",
|
811
|
+
# ["eventProperty",
|
812
|
+
# ["eventPropertyAtomic", ["eventPropertyIdent", ["keywordAllowedIdent", "a"]]]]]]]]]]]]]]]]]],
|
813
|
+
# ",",
|
814
|
+
# ["groupByListChoice",
|
815
|
+
# ["expression",
|
816
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",["negatedExpression",
|
817
|
+
# ["evalEqualsExpression",["evalRelationalExpression",["concatenationExpr",["additiveExpression",
|
818
|
+
# ["multiplyExpression",["unaryExpression",
|
819
|
+
# ["eventPropertyOrLibFunction",
|
820
|
+
# ["libFunction",
|
821
|
+
# ["libFunctionWithClass",
|
822
|
+
# ["funcIdentTop", ["escapableIdent", "NULLABLE"]],
|
823
|
+
# "(",
|
824
|
+
# ["libFunctionArgs",
|
825
|
+
# ["libFunctionArgItem",
|
826
|
+
# ["expressionWithTime",
|
827
|
+
# ["expressionQualifyable",
|
828
|
+
# ["expression",
|
829
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",
|
830
|
+
# ["negatedExpression",["evalEqualsExpression",["evalRelationalExpression",
|
831
|
+
# ["concatenationExpr",["additiveExpression",["multiplyExpression",["unaryExpression",
|
832
|
+
# ["eventPropertyOrLibFunction",
|
833
|
+
# ["eventProperty",
|
834
|
+
# ["eventPropertyAtomic",
|
835
|
+
# ["eventPropertyIdent", ["keywordAllowedIdent", "b"]]]]]]]]]]]]]]]]]]]]],
|
836
|
+
# ")"]]]]]]]]]]]]]]]]]]],
|
837
|
+
# "<EOF>"]
|
838
|
+
|
720
839
|
def astnode(tree)
|
721
840
|
# com.espertech.esper.epl.generated.EsperEPL2GrammarParser.ruleNames[ast.ruleIndex] #=> "startEPLExpressionRule"
|
722
841
|
# com.espertech.esper.epl.generated.EsperEPL2GrammarParser.ruleNames[ast.getChild(0).ruleIndex] #=> "eplExpression"
|
@@ -745,9 +864,11 @@ module Norikra
|
|
745
864
|
end
|
746
865
|
|
747
866
|
cls = case name
|
867
|
+
when 'expression' then ASTExpression
|
748
868
|
when 'eventProperty' then ASTEventPropNode
|
749
869
|
when 'selectionListElementExpr' then ASTSelectionElementNode
|
750
870
|
when 'libFunction' then ASTLibFunctionNode
|
871
|
+
when 'libFunctionArgItem' then ASTLibFunctionArgItemNode
|
751
872
|
when 'streamExpression', 'subSelectFilterExpr' then ASTStreamNode
|
752
873
|
when 'patternFilterExpression' then ASTPatternNode
|
753
874
|
when 'subQueryExpr' then ASTSubSelectNode
|
@@ -769,6 +890,14 @@ module Norikra
|
|
769
890
|
@tree = tree
|
770
891
|
end
|
771
892
|
|
893
|
+
def has_a?(name)
|
894
|
+
@children.size == 1 && (@children.first.name == name || @children.first.nodetype?(name))
|
895
|
+
end
|
896
|
+
|
897
|
+
def chain(*nodes)
|
898
|
+
nodes.reduce(self){|n, next_node| n && n.has_a?(next_node) ? n.child : nil }
|
899
|
+
end
|
900
|
+
|
772
901
|
def nodetype?(*sym)
|
773
902
|
false
|
774
903
|
end
|
@@ -813,6 +942,28 @@ module Norikra
|
|
813
942
|
end
|
814
943
|
end
|
815
944
|
|
945
|
+
class ASTExpression < ASTNode
|
946
|
+
# ["expression",
|
947
|
+
# ["caseExpression", ["evalOrExpression", ["evalAndExpression", ["bitWiseExpression", ["negatedExpression",
|
948
|
+
# ["evalEqualsExpression", ["evalRelationalExpression", ["concatenationExpr", ["additiveExpression",
|
949
|
+
# ["multiplyExpression", ["unaryExpression", ["eventPropertyOrLibFunction",
|
950
|
+
# ["eventProperty",
|
951
|
+
# ["eventPropertyAtomic", ["eventPropertyIdent", ["keywordAllowedIdent", "s"]]]]]]]]]]]]]]]]]]]
|
952
|
+
def nodetype?(*sym)
|
953
|
+
sym.include?(:expression)
|
954
|
+
end
|
955
|
+
|
956
|
+
SIMPLE_PROPERTY_REFERENCE_NODES = [
|
957
|
+
"caseExpression", "evalOrExpression", "evalAndExpression", "bitWiseExpression", "negatedExpression",
|
958
|
+
"evalEqualsExpression", "evalRelationalExpression", "concatenationExpr", "additiveExpression",
|
959
|
+
"multiplyExpression", "unaryExpression", "eventPropertyOrLibFunction", "eventProperty"
|
960
|
+
]
|
961
|
+
def propertyReference?
|
962
|
+
end_node = self.chain(*SIMPLE_PROPERTY_REFERENCE_NODES)
|
963
|
+
end_node && end_node.nodetype?(:property)
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
816
967
|
class ASTEventPropNode < ASTNode # eventProperty
|
817
968
|
### "a"
|
818
969
|
# ["eventProperty", ["eventPropertyAtomic", ["eventPropertyIdent", ["keywordAllowedIdent", "a"]]]
|
@@ -870,13 +1021,13 @@ module Norikra
|
|
870
1021
|
if props.size > 1 # alias.fieldname or container_fieldname.key.$1 or fieldname.method(...)
|
871
1022
|
non_calls = props.select{|p| p.children.size == 1 }.map{|p| p.find('eventPropertyIdent').find('keywordAllowedIdent').child.name }
|
872
1023
|
if known_targets_aliases.include?(leading_name)
|
873
|
-
[ {:
|
1024
|
+
[ {f: non_calls[1..-1].join("."), t: leading_name} ]
|
874
1025
|
else
|
875
|
-
[ {:
|
1026
|
+
[ {f: non_calls.join("."), t: default_target} ]
|
876
1027
|
end
|
877
1028
|
else # fieldname (default target)
|
878
1029
|
# ["eventProperty", ["eventPropertyAtomic", ["eventPropertyIdent", ["keywordAllowedIdent", "a"]]]
|
879
|
-
[ {:
|
1030
|
+
[ {f: leading_name, t: default_target } ]
|
880
1031
|
end
|
881
1032
|
end
|
882
1033
|
end
|
@@ -892,7 +1043,7 @@ module Norikra
|
|
892
1043
|
# ["eventProperty",
|
893
1044
|
# ["eventPropertyAtomic", ["eventPropertyIdent", ["keywordAllowedIdent", "s"]]]]]]]]]]]]]]]]]]]
|
894
1045
|
|
895
|
-
### "count(*) AS cnt"
|
1046
|
+
### "count(*) AS cnt"
|
896
1047
|
# ["selectionListElementExpr",
|
897
1048
|
# ["expression",
|
898
1049
|
# ["caseExpression", ["evalOrExpression", ["evalAndExpression", ["bitWiseExpression", ["negatedExpression",
|
@@ -925,6 +1076,22 @@ module Norikra
|
|
925
1076
|
end
|
926
1077
|
|
927
1078
|
class ASTLibFunctionNode < ASTNode # LIB_FUNCTION
|
1079
|
+
### NULLABLE field!
|
1080
|
+
# ["libFunction",
|
1081
|
+
# ["libFunctionWithClass",
|
1082
|
+
# ["funcIdentTop", ["escapableIdent", "NULLABLE"]],
|
1083
|
+
# "(",
|
1084
|
+
# ["libFunctionArgs",["libFunctionArgItem",["expressionWithTime",["expressionQualifyable",
|
1085
|
+
# ["expression",
|
1086
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",["negatedExpression",
|
1087
|
+
# ["evalEqualsExpression",["evalRelationalExpression",["concatenationExpr",["additiveExpression",
|
1088
|
+
# ["multiplyExpression",["unaryExpression",
|
1089
|
+
# ["eventPropertyOrLibFunction",
|
1090
|
+
# ["eventProperty",
|
1091
|
+
# ["eventPropertyAtomic",
|
1092
|
+
# ["eventPropertyIdent", ["keywordAllowedIdent", "b"]]]]]]]]]]]]]]]]]]]]],
|
1093
|
+
# ")"]]]
|
1094
|
+
|
928
1095
|
### foo is function
|
929
1096
|
# "foo()" => ["libFunction", ["libFunctionWithClass", ["funcIdentTop", ["escapableIdent", "foo"]], "(", ")"]]
|
930
1097
|
|
@@ -948,6 +1115,25 @@ module Norikra
|
|
948
1115
|
# ["libFunctionArgItem", ["expressionWithTime", ["expressionQualifyable", ["expression", EXPRESSION... ]]]]],
|
949
1116
|
# ")"]]
|
950
1117
|
|
1118
|
+
### foo(value)
|
1119
|
+
# ["libFunction",
|
1120
|
+
# ["libFunctionWithClass",
|
1121
|
+
# ["funcIdentTop", ["escapableIdent", "FOO"]],
|
1122
|
+
# "(",
|
1123
|
+
# ["libFunctionArgs",
|
1124
|
+
# ["libFunctionArgItem",
|
1125
|
+
# ["expressionWithTime",
|
1126
|
+
# ["expressionQualifyable",
|
1127
|
+
# ["expression",
|
1128
|
+
# ["caseExpression",["evalOrExpression",["evalAndExpression",["bitWiseExpression",["negatedExpression",
|
1129
|
+
# ["evalEqualsExpression",["evalRelationalExpression",["concatenationExpr",["additiveExpression",
|
1130
|
+
# ["multiplyExpression",["unaryExpression",
|
1131
|
+
# ["eventPropertyOrLibFunction",
|
1132
|
+
# ["eventProperty",
|
1133
|
+
# ["eventPropertyAtomic",
|
1134
|
+
# ["eventPropertyIdent", ["keywordAllowedIdent", "value"]]]]]]]]]]]]]]]]]]]]],
|
1135
|
+
# ")"]]
|
1136
|
+
|
951
1137
|
### foo is property
|
952
1138
|
### "foo.bar()"
|
953
1139
|
# ["libFunction",
|
@@ -1067,33 +1253,67 @@ module Norikra
|
|
1067
1253
|
# "(",
|
1068
1254
|
# ")"]]
|
1069
1255
|
|
1256
|
+
def function_name
|
1257
|
+
f = self.find("funcIdentTop")
|
1258
|
+
if e = f.find("escapableIdent")
|
1259
|
+
e.child.name
|
1260
|
+
else
|
1261
|
+
f.child.name
|
1262
|
+
end
|
1263
|
+
end
|
1264
|
+
|
1070
1265
|
def nodetype?(*sym)
|
1071
1266
|
sym.include?(:lib) || sym.include?(:libfunc)
|
1072
1267
|
end
|
1073
1268
|
|
1074
1269
|
def fields(default_target=nil, known_targets_aliases=[])
|
1270
|
+
# class identifier is receiver: "IDENT.func()"
|
1075
1271
|
identifier = self.find("classIdentifier")
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1272
|
+
if identifier
|
1273
|
+
if identifier.children.size == 1 && Norikra::Query.imported_java_class?(identifier.find("escapableStr").child.name)
|
1274
|
+
# Java imported class name (ex: 'Math.abs(-1)')
|
1275
|
+
self.listup(:prop).map{|c| c.fields(default_target, known_targets_aliases)}.reduce(&:+) || []
|
1276
|
+
else
|
1277
|
+
parts = identifier.listup('escapableStr').map{|node| node.child.name }
|
1278
|
+
target, fieldname = if parts.size == 1
|
1279
|
+
[ default_target, parts.first ]
|
1280
|
+
elsif known_targets_aliases.include?( parts.first )
|
1281
|
+
[ parts[0], parts[1..-1].join(".") ]
|
1282
|
+
else
|
1283
|
+
[ default_target, parts.join(".") ]
|
1284
|
+
end
|
1285
|
+
children_list = self.listup(:prop).map{|c| c.fields(default_target, known_targets_aliases)}.reduce(&:+) || []
|
1286
|
+
[{f: fieldname, t: target}] + children_list
|
1287
|
+
end
|
1082
1288
|
else
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
[{:f => fieldname, :t => target}] + children_list
|
1289
|
+
if self.function_name.upcase == 'NULLABLE'
|
1290
|
+
props = self.listup(:prop).map{|c| c.fields(default_target, known_targets_aliases)}.reduce(&:+) || []
|
1291
|
+
props.each do |def_item|
|
1292
|
+
def_item[:n] = true # nullable: true
|
1293
|
+
end
|
1294
|
+
props
|
1295
|
+
else
|
1296
|
+
self.listup(:prop).map{|c| c.fields(default_target, known_targets_aliases)}.reduce(&:+) || []
|
1297
|
+
end
|
1093
1298
|
end
|
1094
1299
|
end
|
1095
1300
|
end
|
1096
1301
|
|
1302
|
+
class ASTLibFunctionArgItemNode < ASTNode
|
1303
|
+
# ["libFunctionArgs",
|
1304
|
+
# ["libFunctionArgItem",
|
1305
|
+
# ["expressionWithTime",
|
1306
|
+
# ["expressionQualifyable",
|
1307
|
+
# ["expression", ... ]]]]
|
1308
|
+
def nodetype?(*sym)
|
1309
|
+
sym.include?(:libarg)
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
def expression
|
1313
|
+
self.chain("expressionWithTime", "expressionQualifyable", "expression")
|
1314
|
+
end
|
1315
|
+
end
|
1316
|
+
|
1097
1317
|
class ASTStreamNode < ASTNode # streamExpression, subSelectFilterExpr
|
1098
1318
|
def self.generate(name, children, tree)
|
1099
1319
|
if children.first.name == 'eventFilterExpression'
|
data/lib/norikra/query.rb
CHANGED
@@ -27,6 +27,12 @@ module Norikra
|
|
27
27
|
@aliases = nil
|
28
28
|
@subqueries = nil
|
29
29
|
@fields = nil
|
30
|
+
@nullable_fields = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
internal = ['name', 'group', 'expression', 'statement_name', 'targets', 'aliases', 'fields', 'nullable_fields', 'subqueries', 'fieldsets'].map{|x| "@#{x}=" + self.send(x.to_sym).inspect }.join(", ")
|
35
|
+
"<#Norikra::Query:#{self.object_id} #{internal}>"
|
30
36
|
end
|
31
37
|
|
32
38
|
def <=>(other)
|
@@ -45,16 +51,8 @@ module Norikra
|
|
45
51
|
end
|
46
52
|
end
|
47
53
|
|
48
|
-
def self.loopback(group)
|
49
|
-
group && group =~ /^LOOPBACK\((.+)\)$/ && $1
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.stdout?(group)
|
53
|
-
group && group == "STDOUT()"
|
54
|
-
end
|
55
|
-
|
56
54
|
def dup
|
57
|
-
self.class.new(:
|
55
|
+
self.class.new(name: @name, group: @group, expression: @expression.dup)
|
58
56
|
end
|
59
57
|
|
60
58
|
def to_hash
|
@@ -70,8 +68,26 @@ module Norikra
|
|
70
68
|
end
|
71
69
|
|
72
70
|
def invalid?
|
73
|
-
# check query is invalid as Norikra query or not
|
74
|
-
|
71
|
+
# check query is invalid as Norikra query or not, and return invalid reason (or nil for valid queries)
|
72
|
+
|
73
|
+
# "SELECT *" is prohibited because each Norikra targets does not have all fields users expect
|
74
|
+
if self.ast.listup('selectionListElement').any?{|node| node.children.map(&:name).any?{|name| name == '*' } }
|
75
|
+
# '*' is a direct child of selectionListElement, not selectionListElementExpr
|
76
|
+
return "'SELECT *' is prohibited in query"
|
77
|
+
end
|
78
|
+
|
79
|
+
# NULLABLE(...) can have "a" single field reference only
|
80
|
+
nullables = self.ast.listup(:libfunc).select{|node| node.function_name.upcase == "NULLABLE" }
|
81
|
+
if nullables.size > 0
|
82
|
+
unless nullables.all?{|node| args = node.find("libFunctionArgs"); args && args.has_a?(:libarg) }
|
83
|
+
return "NULLABLE(...) must have a field argument"
|
84
|
+
end
|
85
|
+
unless nullables.all?{|node| exp = node.find(:libarg).expression; exp && exp.propertyReference? }
|
86
|
+
return "NULLABLE(...) can get a field, not expression"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
nil
|
75
91
|
end
|
76
92
|
|
77
93
|
def targets
|
@@ -93,74 +109,85 @@ module Norikra
|
|
93
109
|
end
|
94
110
|
|
95
111
|
def explore(outer_targets=[], alias_overridden={})
|
96
|
-
fields = {
|
97
|
-
|
112
|
+
fields = {
|
113
|
+
defs: { all: [], unknown: [], target: {} },
|
114
|
+
nullables: { all: [], unknown: [], target: {} },
|
115
|
+
}
|
116
|
+
|
117
|
+
alias_map = alias_overridden.dup
|
98
118
|
|
99
|
-
all = []
|
100
|
-
unknowns = []
|
101
119
|
self.ast.listup(:stream).each do |node|
|
102
120
|
node.aliases.each do |alias_name, target|
|
103
121
|
alias_map[alias_name] = target
|
104
122
|
end
|
105
123
|
node.targets.each do |target|
|
106
|
-
fields[target]
|
124
|
+
fields[:defs][:target][target] = []
|
125
|
+
fields[:nullables][:target][target] = []
|
107
126
|
end
|
108
127
|
end
|
109
128
|
|
110
|
-
|
111
|
-
|
112
|
-
raise Norikra::ClientError, "Invalid alias '#{dup_aliases.join(',')}', same with target name"
|
113
|
-
end
|
114
|
-
|
115
|
-
default_target = fields.keys.size == 1 ? fields.keys.first : nil
|
129
|
+
# default target should be out of effect of outer_targets
|
130
|
+
default_target = fields[:defs][:target].keys.size == 1 ? fields[:defs][:target].keys.first : nil
|
116
131
|
|
117
132
|
outer_targets.each do |t|
|
118
|
-
fields[t] ||= []
|
133
|
+
fields[:defs][:target][t] ||= []
|
134
|
+
fields[:nullables][:target][t] ||= []
|
119
135
|
end
|
120
136
|
|
121
|
-
|
122
|
-
|
123
|
-
|
137
|
+
dup_aliases = (alias_map.keys & fields[:defs][:target].keys)
|
138
|
+
unless dup_aliases.empty?
|
139
|
+
raise Norikra::ClientError, "Invalid alias '#{dup_aliases.join(',')}', same with target name"
|
124
140
|
end
|
125
141
|
|
126
142
|
# names of 'AS'
|
127
143
|
field_aliases = self.ast.listup(:selection).map(&:alias).compact
|
128
144
|
|
129
|
-
known_targets_aliases = fields.keys + alias_map.keys
|
145
|
+
known_targets_aliases = fields[:defs][:target].keys + alias_map.keys
|
130
146
|
self.ast.fields(default_target, known_targets_aliases).each do |field_def|
|
131
147
|
f = field_def[:f]
|
132
148
|
next if field_aliases.include?(f)
|
133
149
|
|
134
|
-
all.push(f)
|
150
|
+
fields[:defs][:all].push(f)
|
151
|
+
fields[:nullables][:all].push(f) if field_def[:n]
|
135
152
|
|
136
153
|
if field_def[:t]
|
137
154
|
t = alias_map[field_def[:t]] || field_def[:t]
|
138
|
-
unless fields[t]
|
155
|
+
unless fields[:defs][:target][t]
|
139
156
|
raise Norikra::ClientError, "unknown target alias name for: #{field_def[:t]}.#{field_def[:f]}"
|
140
157
|
end
|
141
|
-
fields[t].push(f)
|
142
|
-
|
158
|
+
fields[:defs][:target][t].push(f)
|
159
|
+
fields[:nullables][:target][t].push(f) if field_def[:n]
|
143
160
|
else
|
144
|
-
|
161
|
+
fields[:defs][:unknown].push(f)
|
162
|
+
fields[:nullables][:unknown].push(f) if field_def[:n]
|
145
163
|
end
|
146
164
|
end
|
147
165
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
fields[
|
166
|
+
self.subqueries.each do |subquery|
|
167
|
+
sub = {}
|
168
|
+
sub[:defs], sub[:nullables] = subquery.explore(fields[:defs][:target].keys, alias_map)
|
169
|
+
|
170
|
+
[:defs, :nullables].each do |group|
|
171
|
+
fields[group][:all] += sub[group].delete('')
|
172
|
+
fields[group][:unknown] += sub[group].delete(nil)
|
173
|
+
sub[group].keys.each do |t|
|
174
|
+
fields[group][:target][t] ||= []
|
175
|
+
fields[group][:target][t] += sub[group][t]
|
176
|
+
end
|
154
177
|
end
|
155
178
|
end
|
156
179
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
180
|
+
compact = ->(data){
|
181
|
+
r = {}
|
182
|
+
data[:target].keys.each do |t|
|
183
|
+
r[t] = data[:target][t].sort.uniq
|
184
|
+
end
|
185
|
+
r[''] = data[:all].sort.uniq
|
186
|
+
r[nil] = data[:unknown].sort.uniq
|
187
|
+
r
|
188
|
+
}
|
162
189
|
|
163
|
-
fields
|
190
|
+
[ compact.(fields[:defs]), compact.(fields[:nullables]) ]
|
164
191
|
end
|
165
192
|
|
166
193
|
def fields(target='')
|
@@ -168,10 +195,18 @@ module Norikra
|
|
168
195
|
# target nil: fields for unknown targets
|
169
196
|
return @fields[target] if @fields
|
170
197
|
|
171
|
-
@fields = explore()
|
198
|
+
@fields, @nullable_fields = explore()
|
172
199
|
@fields[target]
|
173
200
|
end
|
174
201
|
|
202
|
+
def nullable_fields(target='')
|
203
|
+
# argument target is same with #fields
|
204
|
+
return @nullable_fields[target] if @nullable_fields
|
205
|
+
|
206
|
+
@fields, @nullable_fields = explore()
|
207
|
+
@nullable_fields[target]
|
208
|
+
end
|
209
|
+
|
175
210
|
class ParseRuleSelectorImpl
|
176
211
|
include Java::ComEspertechEsperEplParse::ParseRuleSelector
|
177
212
|
def invokeParseRule(parser)
|
@@ -218,10 +253,32 @@ module Norikra
|
|
218
253
|
end
|
219
254
|
|
220
255
|
def self.rewrite_query(statement_model, mapping)
|
256
|
+
rewrite_nullable_fields(statement_model)
|
221
257
|
rewrite_event_type_name(statement_model, mapping)
|
222
258
|
rewrite_event_field_name(statement_model, mapping)
|
223
259
|
end
|
224
260
|
|
261
|
+
def self.rewrite_nullable_fields(statement_model)
|
262
|
+
# NULLABLE(field) -> field
|
263
|
+
## NOTICE: NULLABLE(...) cannot be used in view parameters. ex: target.std:unique(NULLABLE(a)) -> x
|
264
|
+
rewriter = lambda {|node|
|
265
|
+
if node.respond_to?(:getExpression)
|
266
|
+
exp = node.getExpression
|
267
|
+
if exp && exp.is_a?(Java::ComEspertechEsperClientSoda::DotExpression) && exp.getChain.size == 1
|
268
|
+
# top-level lib function
|
269
|
+
# exp.getChain[0] #=> Java::ComEspertechEsperClientSoda::DotExpressionItem
|
270
|
+
if exp.getChain[0].name.upcase == 'NULLABLE'
|
271
|
+
node.setExpression(exp.getChain[0].getParameters[0])
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
}
|
276
|
+
recaller = lambda {|node|
|
277
|
+
Norikra::Query.rewrite_nullable_fields(node.getModel)
|
278
|
+
}
|
279
|
+
traverse_fields(rewriter, recaller, statement_model)
|
280
|
+
end
|
281
|
+
|
225
282
|
def self.rewrite_event_field_name(statement_model, mapping)
|
226
283
|
# mapping: {target_name => query_event_type_name}
|
227
284
|
# mapping is for target name rewriting of fully qualified field name access
|
@@ -235,7 +292,7 @@ module Norikra
|
|
235
292
|
# model.getWhereClause.getChildren[1].getChildren[0].getPropertyName #=> 'field.key1.$1'
|
236
293
|
# model.getWhereClause.getChildren[2].getChildren[0].getChain[0].getName #=> 'opts.num.$0' from opts.num.$0.length()
|
237
294
|
|
238
|
-
query = Norikra::Query.new(:
|
295
|
+
query = Norikra::Query.new(name: 'dummy name by .rewrite_event_field_name', expression: statement_model.toEPL)
|
239
296
|
targets = query.targets
|
240
297
|
fqfs_prefixes = targets + query.aliases
|
241
298
|
|
data/lib/norikra/rpc/handler.rb
CHANGED
@@ -13,9 +13,9 @@ class Norikra::RPC::Handler
|
|
13
13
|
|
14
14
|
def logging(type, handler, args=[])
|
15
15
|
if type == :manage
|
16
|
-
debug
|
16
|
+
debug("RPC"){ { handler: handler.to_s, args: args } }
|
17
17
|
else
|
18
|
-
trace
|
18
|
+
trace("RPC"){ { handler: handler.to_s, args: args } }
|
19
19
|
end
|
20
20
|
|
21
21
|
begin
|
@@ -67,7 +67,7 @@ class Norikra::RPC::Handler
|
|
67
67
|
|
68
68
|
def register(query_name, query_group, expression)
|
69
69
|
logging(:manage, :register, [query_name, query_group, expression]){
|
70
|
-
r = @engine.register(Norikra::Query.new(:
|
70
|
+
r = @engine.register(Norikra::Query.new(name: query_name, group: query_group, expression: expression))
|
71
71
|
!!r
|
72
72
|
}
|
73
73
|
end
|
data/lib/norikra/rpc/http.rb
CHANGED
@@ -35,7 +35,7 @@ module Norikra::RPC
|
|
35
35
|
info "RPC server #{@host}:#{@port}, #{@threads} threads"
|
36
36
|
@thread = Thread.new do
|
37
37
|
@mizuno = Mizuno::Server.new
|
38
|
-
@mizuno.run(@app, :
|
38
|
+
@mizuno.run(@app, embedded: true, threads: @threads, port: @port, host: @host)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|