Module: CompositePrimaryKeys::Predicates

Extended by:
Predicates
Included in:
Predicates
Defined in:
lib/composite_primary_keys/composite_predicates.rb

Instance Method Summary collapse

Instance Method Details

#cpk_and_predicate(predicates) ⇒ Object



7
8
9
10
11
12
13
# File 'lib/composite_primary_keys/composite_predicates.rb', line 7

def cpk_and_predicate(predicates)
  if predicates.length == 1
    predicates.first
  else
    Arel::Nodes::And.new(predicates)
  end
end

#cpk_id_predicate(table, keys, values) ⇒ Object



34
35
36
37
38
39
40
# File 'lib/composite_primary_keys/composite_predicates.rb', line 34

def cpk_id_predicate(table, keys, values)
  # We zip on values then keys in case values are not provided for each key field
  eq_predicates = values.zip(keys).map do |value, key|
    table[key].eq(value)
  end
  cpk_and_predicate(eq_predicates)
end

#cpk_in_predicate(table, primary_keys, ids) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/composite_primary_keys/composite_predicates.rb', line 53

def cpk_in_predicate(table, primary_keys, ids)
  if primary_keys.length == 2
    cpk_in_predicate_with_grouped_keys(table, primary_keys, ids)
  else
    cpk_in_predicate_with_non_grouped_keys(table, primary_keys, ids)
  end
end

#cpk_in_predicate_with_grouped_keys(table, primary_keys, ids) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/composite_primary_keys/composite_predicates.rb', line 69

def cpk_in_predicate_with_grouped_keys(table, primary_keys, ids)
  keys_by_first_column_name = Hash.new { |hash, key| hash[key] = [] }
  keys_by_second_column_name = Hash.new { |hash, key| hash[key] = [] }

  ids.map.each do |first_key_part, second_key_part|
    keys_by_first_column_name[first_key_part] << second_key_part
    keys_by_second_column_name[second_key_part] << first_key_part
  end

  low_cardinality_column_name, high_cardinality_column_name, groups = \
    if keys_by_first_column_name.size <= keys_by_second_column_name.size
      [primary_keys.first, primary_keys.second, keys_by_first_column_name]
    else
      [primary_keys.second, primary_keys.first, keys_by_second_column_name]
    end

  and_predicates = groups.map do |low_cardinality_value, high_cardinality_values|
    non_nil_high_cardinality_values = high_cardinality_values.compact
    in_clause = table[high_cardinality_column_name].in(non_nil_high_cardinality_values)
    inclusion_clauses = if non_nil_high_cardinality_values.size != high_cardinality_values.size
                          Arel::Nodes::Grouping.new(
                            Arel::Nodes::Or.new(
                              in_clause,
                              table[high_cardinality_column_name].eq(nil)
                            )
                          )
                        else
                          in_clause
                        end

    Arel::Nodes::And.new(
      [
        table[low_cardinality_column_name].eq(low_cardinality_value),
        inclusion_clauses
      ]
    )
  end

  cpk_or_predicate(and_predicates)
end

#cpk_in_predicate_with_non_grouped_keys(table, primary_keys, ids) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/composite_primary_keys/composite_predicates.rb', line 61

def cpk_in_predicate_with_non_grouped_keys(table, primary_keys, ids)
  and_predicates = ids.map do |id|
    cpk_id_predicate(table, primary_keys, id)
  end

  cpk_or_predicate(and_predicates)
end

#cpk_join_predicate(table1, key1, table2, key2) ⇒ Object



42
43
44
45
46
47
48
49
50
51
# File 'lib/composite_primary_keys/composite_predicates.rb', line 42

def cpk_join_predicate(table1, key1, table2, key2)
  key1_fields = Array(key1).map {|key| table1[key]}
  key2_fields = Array(key2).map {|key| table2[key]}

  eq_predicates = key1_fields.zip(key2_fields).map do |key_field1, key_field2|
    key_field2 = Arel::Nodes::Quoted.new(key_field2) unless Arel::Attributes::Attribute === key_field2
    key_field1.eq(key_field2)
  end
  cpk_and_predicate(eq_predicates)
end

#cpk_or_predicate(predicates, group = true) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/composite_primary_keys/composite_predicates.rb', line 15

def cpk_or_predicate(predicates, group = true)
  if predicates.length <= 1
    predicates.first
  else
    split_point = predicates.length / 2
    predicates_first_half = predicates[0...split_point]
    predicates_second_half = predicates[split_point..-1]

    or_predicate = ::Arel::Nodes::Or.new(cpk_or_predicate(predicates_first_half, false),
                                         cpk_or_predicate(predicates_second_half, false))

    if group
      ::Arel::Nodes::Grouping.new(or_predicate)
    else
      or_predicate
    end
  end
end