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.
@@ -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
- [ {:f => non_calls[1..-1].join("."), :t => leading_name} ]
1024
+ [ {f: non_calls[1..-1].join("."), t: leading_name} ]
874
1025
  else
875
- [ {:f => non_calls.join("."), :t => default_target} ]
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
- [ {:f => leading_name, :t => default_target } ]
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" => ["SELECTION_ELEMENT_EXPR", "count", "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
- return [] if identifier.nil? # built-in function call (no receivers exists)
1078
-
1079
- if identifier.children.size == 1 && Norikra::Query.imported_java_class?(identifier.find("escapableStr").child.name)
1080
- # Java imported class name (ex: 'Math.abs(-1)')
1081
- self.listup(:prop).map{|c| c.fields(default_target, known_targets_aliases)}.reduce(&:+) || []
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
- parts = identifier.listup('escapableStr').map{|node| node.child.name }
1084
- target, fieldname = if parts.size == 1
1085
- [ default_target, parts.first ]
1086
- elsif known_targets_aliases.include?( parts.first )
1087
- [ parts[0], parts[1..-1].join(".") ]
1088
- else
1089
- [ default_target, parts.join(".") ]
1090
- end
1091
- children_list = self.listup(:prop).map{|c| c.fields(default_target, known_targets_aliases)}.reduce(&:+) || []
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(:name => @name, :group => @group, :expression => @expression.dup)
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
- self.ast.listup('selectionListElement').any?{|node| node.children.map(&:name).any?{|name| name == '*' } }
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
- alias_map = {}.merge(alias_overridden)
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
- dup_aliases = (alias_map.keys & fields.keys)
111
- unless dup_aliases.empty?
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
- field_bag = []
122
- self.subqueries.each do |subquery|
123
- field_bag.push(subquery.explore(fields.keys, alias_map))
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
- unknowns.push(f)
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
- field_bag.each do |bag|
149
- all += bag['']
150
- unknowns += bag[nil]
151
- bag.keys.each do |t|
152
- fields[t] ||= []
153
- fields[t] += bag[t]
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
- fields.keys.each do |target|
158
- fields[target] = fields[target].sort.uniq
159
- end
160
- fields[''] = all.sort.uniq
161
- fields[nil] = unknowns.sort.uniq
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(:name => 'dummy name by .rewrite_event_field_name', :expression => statement_model.toEPL)
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
 
@@ -13,9 +13,9 @@ class Norikra::RPC::Handler
13
13
 
14
14
  def logging(type, handler, args=[])
15
15
  if type == :manage
16
- debug "RPC", :handler => handler.to_s, :args => args
16
+ debug("RPC"){ { handler: handler.to_s, args: args } }
17
17
  else
18
- trace "RPC", :handler => handler.to_s, :args => args
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(:name => query_name, :group => query_group, :expression => expression))
70
+ r = @engine.register(Norikra::Query.new(name: query_name, group: query_group, expression: expression))
71
71
  !!r
72
72
  }
73
73
  end
@@ -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, :embedded => true, :threads => @threads, :port => @port, :host => @host)
38
+ @mizuno.run(@app, embedded: true, threads: @threads, port: @port, host: @host)
39
39
  end
40
40
  end
41
41