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