Class: Expressir::Express::Builders::SubtypeConstraintBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/expressir/express/builders/subtype_constraint_builder.rb

Overview

Builds subtype constraint and supertype expression nodes.

Instance Method Summary collapse

Instance Method Details

#build_binary_supertype_expression(operands, operators) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 97

def build_binary_supertype_expression(operands, operators)
  result = Expressir::Model::SupertypeExpressions::BinarySupertypeExpression.new(
    operator: operators.first,
    operand1: operands.first,
    operand2: operands[1],
  )
  (2...operands.length).each do |i|
    result = Expressir::Model::SupertypeExpressions::BinarySupertypeExpression.new(
      operator: operators[i - 1],
      operand1: result,
      operand2: operands[i],
    )
  end
  result
end

#build_one_of(ast_data) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 125

def build_one_of(ast_data)
  list_data = ast_data[:list_of_supertype_expression]
  operands = if list_data.is_a?(Array)
               list_data.filter_map do |item|
                 next unless item.is_a?(Hash)

                 expr_data = item[:supertype_expression]
                 Builder.build({ supertype_expression: expr_data }) if expr_data
               end
             elsif list_data.is_a?(Hash)
               expr_data = list_data[:supertype_expression]
               [Builder.build({ supertype_expression: expr_data })] if expr_data
             else
               []
             end
  Expressir::Model::SupertypeExpressions::OneofSupertypeExpression.new(operands: operands.compact)
end

#build_subtype_constraint(ast_data) ⇒ Object



150
151
152
153
154
155
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 150

def build_subtype_constraint(ast_data)
  expr_data = ast_data[:supertype_expression]
  if expr_data.is_a?(Hash)
    Builder.build({ supertype_expression: expr_data })
  end
end

#build_subtype_constraint_decl(ast_data) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 8

def build_subtype_constraint_decl(ast_data)
  head = ast_data[:subtype_constraint_head]
  body = ast_data[:subtype_constraint_body]

  id = Builder.build_optional(head[:subtype_constraint_id]) if head
  applies_to = if head && head[:entity_ref]
                 Builder.build({ entity_ref: head[:entity_ref] })
               end

  abstract = false
  total_over = []
  supertype_expression = nil

  if body.is_a?(Hash)
    abstract = !body[:abstract_supertype].nil?
    if body[:total_over].is_a?(Hash)
      total_over = Builder.build_children(Builder.ensure_array(body[:total_over][:entity_ref]))
    end
    # Wrap supertype_expression in its node type so Builder.build dispatches correctly
    supertype_expression = if body[:supertype_expression]
                             Builder.build({ supertype_expression: body[:supertype_expression] })
                           end
  end

  Expressir::Model::Declarations::SubtypeConstraint.new(
    id: id,
    applies_to: applies_to,
    abstract: abstract,
    total_over: total_over,
    supertype_expression: supertype_expression,
  )
end

#build_subtype_declaration(ast_data) ⇒ Object



157
158
159
160
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 157

def build_subtype_declaration(ast_data)
  refs = ast_data[:entity_ref] || ast_data[:list_of_entity_ref]&.dig(:entity_ref)
  Builder.build_children(Builder.ensure_array(refs))
end

#build_supertype_expression(ast_data) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 45

def build_supertype_expression(ast_data)
  return nil unless ast_data

  base_factor = ast_data[:supertype_factor]
  return nil unless base_factor

  # Handle both formats:
  # - With item wrapper: {item: {operator: {...}, supertype_factor: {...}}}
  # - Without item wrapper: {operator: {...}, supertype_factor: {...}}
  factors = [base_factor] + Builder.ensure_array(ast_data[:rhs]).filter_map do |r|
    r[:item]&.dig(:supertype_factor) || r[:supertype_factor]
  end
  operators = Builder.ensure_array(ast_data[:rhs]).map do |r|
    (r[:item]&.dig(:operator) || r[:operator])&.values&.first
  end

  if factors.length == 1
    Builder.build({ supertype_factor: factors.first })
  elsif factors.length >= 2
    operands = factors.map do |f|
      Builder.build({ supertype_factor: f })
    end
    build_binary_supertype_expression(operands, operators.map do
      :ANDOR
    end)
  end
end

#build_supertype_factor(ast_data) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 73

def build_supertype_factor(ast_data)
  return nil unless ast_data

  base_term = ast_data[:supertype_term]
  return nil unless base_term

  # Handle both formats:
  # - With item wrapper: {item: {operator: {...}, supertype_term: {...}}}
  # - Without item wrapper: {operator: {...}, supertype_term: {...}}
  terms = [base_term] + Builder.ensure_array(ast_data[:rhs]).filter_map do |r|
    r[:item]&.dig(:supertype_term) || r[:supertype_term]
  end
  operators = Builder.ensure_array(ast_data[:rhs]).map do |r|
    (r[:item]&.dig(:operator) || r[:operator])&.values&.first
  end

  if terms.length == 1
    Builder.build({ supertype_term: terms.first })
  elsif terms.length >= 2
    operands = terms.map { |t| Builder.build({ supertype_term: t }) }
    build_binary_supertype_expression(operands, operators.map { :AND })
  end
end

#build_supertype_rule(ast_data) ⇒ Object



143
144
145
146
147
148
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 143

def build_supertype_rule(ast_data)
  subtype_constraint = ast_data[:subtype_constraint]
  if subtype_constraint.is_a?(Hash)
    Builder.build({ subtype_constraint: subtype_constraint })
  end
end

#build_supertype_term(ast_data) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 113

def build_supertype_term(ast_data)
  return nil unless ast_data.is_a?(Hash)

  if ast_data[:entity_ref]
    Builder.build({ entity_ref: ast_data[:entity_ref] })
  elsif ast_data[:one_of]
    Builder.build({ one_of: ast_data[:one_of] })
  elsif ast_data[:supertype_expression]
    Builder.build({ supertype_expression: ast_data[:supertype_expression] })
  end
end

#build_total_over(ast_data) ⇒ Object



41
42
43
# File 'lib/expressir/express/builders/subtype_constraint_builder.rb', line 41

def build_total_over(ast_data)
  Builder.build_children(ast_data[:entity_ref])
end