Class: ForestAdminDatasourceToolkit::Components::Query::ConditionTree::ConditionTreeFactory

Inherits:
Object
  • Object
show all
Includes:
Nodes, Exceptions
Defined in:
lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb

Class Method Summary collapse

Class Method Details

.branch?(tree) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
125
126
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 122

def self.branch?(tree)
  return false unless tree.is_a?(Hash)

  tree.key?(:aggregator) && tree.key?(:conditions)
end

.from_plain_object(json) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 53

def self.from_plain_object(json)
  return nil if json.nil?

  if leaf?(json)
    ConditionTreeLeaf.new(json[:field], json[:operator], json[:value])
  elsif branch?(json)
    branch = ConditionTreeBranch.new(
      json[:aggregator],
      json[:conditions].map { |sub_tree| from_plain_object(sub_tree) }
    )

    branch.conditions.length == 1 ? branch.conditions[0] : branch
  else
    raise ForestException, 'Failed to instantiate condition tree from json'
  end
end

.group(aggregator, trees = nil) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 70

def self.group(aggregator, trees = nil)
  return nil if trees.nil? || trees.empty?

  conditions = trees
               .compact
               .reduce([]) do |current_conditions, tree|
    if tree.is_a?(ConditionTreeBranch) && tree.aggregator == aggregator
      current_conditions + tree.conditions
    else
      current_conditions + [tree]
    end
  end

  conditions.length == 1 ? conditions[0] : ConditionTreeBranch.new(aggregator, conditions)
end

.intersect(trees = nil) ⇒ Object



42
43
44
45
46
47
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 42

def self.intersect(trees = nil)
  result = group('And', trees)
  is_empty_and = result.is_a?(ConditionTreeBranch) && result.aggregator == 'And' && result.conditions.empty?

  is_empty_and ? nil : result
end

.leaf?(tree) ⇒ Boolean

Returns:

  • (Boolean)


116
117
118
119
120
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 116

def self.leaf?(tree)
  return false unless tree.is_a?(Hash)

  tree.key?(:field) && tree.key?(:operator) && (tree[:operator] == 'Present' || tree.key?(:value))
end

.match_fields(fields, values) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 86

def self.match_fields(fields, values)
  return ConditionTreeFactory.match_none if values.empty?

  if fields.length == 1
    field_values = values.map { |tuple| tuple[0] }

    return field_values.length > 1 ? ConditionTreeLeaf.new(fields[0], 'In', field_values) : ConditionTreeLeaf.new(fields[0], 'Equal', field_values[0])
  end

  first_field, *other_fields = fields
  groups = {}

  values.each do |first_value, *other_values|
    if groups.key?(first_value)
      groups[first_value].push(other_values)
    else
      groups[first_value] = [other_values]
    end
  end

  ConditionTreeFactory.union(
    groups.map do |first_value, sub_values|
      ConditionTreeFactory.intersect([
                                       ConditionTreeFactory.match_fields([first_field], [[first_value]]),
                                       ConditionTreeFactory.match_fields(other_fields, sub_values)
                                     ])
    end
  )
end

.match_ids(collection, ids) ⇒ Object

Raises:



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 19

def self.match_ids(collection, ids)
  primary_key_names = ForestAdminDatasourceToolkit::Utils::Schema.primary_keys(collection)

  raise ForestException, 'Collection must have at least one primary key' if primary_key_names.empty?

  primary_key_names.each do |name|
    operators = collection.schema[:fields][name].filter_operators
    unless operators.include?(Operators::EQUAL) || operators.include?(Operators::IN)
      raise ForestException, "Field '#{name}' must support operators: ['Equal', 'In']"
    end
  end

  normalized_ids = ids.map do |id|
    if id.is_a?(Hash)
      primary_key_names.map { |pk_name| id[pk_name] }
    else
      id
    end
  end

  match_fields(primary_key_names, normalized_ids)
end

.match_noneObject



9
10
11
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 9

def self.match_none
  ConditionTreeBranch.new('Or', [])
end

.match_records(collection, records) ⇒ Object



13
14
15
16
17
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 13

def self.match_records(collection, records)
  ids = records.map { |record| ForestAdminDatasourceToolkit::Utils::Record.primary_keys(collection, record) }

  match_ids(collection, ids)
end

.union(trees) ⇒ Object



49
50
51
# File 'lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb', line 49

def self.union(trees)
  group('Or', trees)
end