lib/ddql/agg_operator.rb in ddql-1.0.0 vs lib/ddql/agg_operator.rb in ddql-1.0.1

- old
+ new

@@ -1,6 +1,8 @@ module DDQL + using StringRefinements + # +AggOperators+ return a Hash structure describing the type of aggregation, an optional # expression (filter) to apply, an optional factor (field) against which the aggregation # is applied, and the entity type for which the aggregation is applicable. # # ==== Examples @@ -11,11 +13,11 @@ # sub_query_expression: "[OtherFactor] == 'Value'", # sub_query_fields: 'SomeFactor', # sub_query_type: 'IssuerPerson', # } # - # +CNT{type:Issuer, expression: [SomeFactor]} / CNT{type:Issuer, expression: [OtherFactor]}+ + # +CNT{type:Issuer, fields: [SomeFactor]} / CNT{type:Issuer, fields: [OtherFactor]}+ # # { # left: { # agg: {op_cnt: 'CNT'}, # sub_query_fields: 'SomeFactor', @@ -27,22 +29,33 @@ # sub_query_fields: 'OtherFactor', # sub_query_type: 'Issuer', # }, # } # - # +MAX{type:Case, expression: [SomeFactor]} > 5+ + # +MAX{type:Case, fields: [SomeFactor]} > 5+ # # { # left: { # agg: {op_max: 'MAX'}, # sub_query_fields: 'SomeFactor', # sub_query_type: 'Case', # }, # op: {op_gt: '>'}, # right: {int: 5}, # } + # + # +ALIAS{type:Issuer, expression: [SomeFactor] > 5} AS [ThatFactor:That Factor]+ + # + # { + # agg: {op_max: 'ALIAS'}, + # sub_query_type: 'Issuer', + # sub_query_expression: '[SomeFactor] > 5', + # sub_query_alias: {factor: 'ThatFactor', desc: 'That Factor'}, + # } class AggOperator < Operator + using BlankRefinements + def initialize(symbol, name, return_type:, type: :prefix, precedence: 8, right: false) super(symbol, name, type, precedence, right, return_type) end def parse(parser, token, expression: nil) @@ -50,27 +63,72 @@ if expression expression = expression.merge(new_expression) else expression = new_expression end + expression.merge!(agg: {:"op_#{symbol.downcase}" => symbol}) + if parser.peek&.supports_post_processing? + token, expression = parser.peek.post_process(parser: parser, expression: expression) + end + as_agg(expression) + end - if expression.key?(:op) && expression.key?(:right) - if expression[:left]&.empty? - expression.delete :left + def as_left_op_right(expression) + new_expression = { + agg: expression.delete(:agg), + sub_query_type: expression.delete(:sub_query_type), + sub_query_fields: expression.delete(:sub_query_fields), + sub_query_expression: expression.delete(:sub_query_expression), + }.compact + + if expression[:lstatement].key?(:op) && expression[:lstatement][:left].blank? + { + left: new_expression, + op: expression[:lstatement][:op], + right: expression[:lstatement][:right], + } + elsif expression[:lstatement].key?(:lstatement) + if expression[:lstatement][:lstatement].empty? + expression[:lstatement][:lstatement] = new_expression + expression[:lstatement] + else + final_expression = expression[:lstatement] + final_expression[:lstatement][:left] = new_expression + final_expression end - op = expression.delete :op - right = expression.delete :right + else + new_expression + end + end + + def as_agg(expr) + expression = expr.dup + if expression.key?(:yes_no_op) + # AGG Y/N + yes_no_op = expression.delete(:yes_no_op) { left: expression, + yes_no_op: yes_no_op, + } + elsif expression.key?(:op) + # AGG COMP LIT + expression.delete(:left) + op = expression.delete(:op) + right = expression.delete(:right) + { + left: expression, op: op, right: right, } - elsif expression.key?(:yes_no_op) - yes_no = expression.delete :yes_no_op + elsif expression.key?(:boolean_operator) + # AGG BOOL STMT + bool_op = expression.delete(:boolean_operator) + rstatement = expression.delete(:rstatement) { - left: expression, - yes_no_op: yes_no, + lstatement: as_left_op_right(expression), + boolean_operator: bool_op, + rstatement: rstatement, } else expression end end