Module: Card::Query::AbstractQuery::Tie

Included in:
Card::Query::AbstractQuery
Defined in:
lib/card/query/abstract_query/tie.rb

Overview

The “Tie” methods support tying two queries (CardQuery, ReferenceQuery, etc) together. The “subquery_type” variable determines which tying strategy is used.

We currently support three values for “subquery_type”: :join, :exist, and :in

In concept, here’s how the different strategies would tie table A to table B in SQL assuming A.id = B.a_id

  • :join … FROM A JOIN B ON A.id = B.a_id

  • :exist … FROM A WHERE EXISTS (SELECT * FROM B WHERE A.id = B.a_id …)

  • :in … FROM A WHERE A.id IN (SELECT B.a_id FROM B WHERE …)

The different strategies will return the same values but the relative speed is context dependent.

Instance Method Summary collapse

Instance Method Details

#fastenObject



52
53
54
# File 'lib/card/query/abstract_query/tie.rb', line 52

def fasten
  @fasten ||= root? ? :join : inherit_fasten
end

#fasten_tie(subquery, fields = {}) ⇒ Object



31
32
33
34
35
# File 'lib/card/query/abstract_query/tie.rb', line 31

def fasten_tie subquery, fields={}
  method = "tie_with_#{subquery.fasten}"
  send method, subquery, fields
  subquery
end

#id_from_val(val) ⇒ Object



94
95
96
97
98
99
# File 'lib/card/query/abstract_query/tie.rb', line 94

def id_from_val val
  case val
  when Integer         then val
  when String, Symbol  then val.card_id || -999
  end
end

#inherit_fastenObject



73
74
75
76
# File 'lib/card/query/abstract_query/tie.rb', line 73

def inherit_fasten
  superfasten = superquery.fasten
  superfasten == :direct ? superquery.inherit_fasten : superfasten
end

#left_join?(subquery) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
66
# File 'lib/card/query/abstract_query/tie.rb', line 63

def left_join? subquery
  current_conjunction == "or" || subquery.negate
  # reverse conjunction if negated?
end

#list_of_ids?(val) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
112
113
# File 'lib/card/query/abstract_query/tie.rb', line 109

def list_of_ids? val
  return unless val.is_a? Array

  !val.find { |v| !id_from_val v }
end

#negate_join(subquery, join, fields) ⇒ Object



68
69
70
71
# File 'lib/card/query/abstract_query/tie.rb', line 68

def negate_join subquery, join, fields
  subquery.conditions_on_join = join
  add_condition "#{subquery.fld fields[:to]} is null"
end

#op_and_id_or_ids_from_val(val) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/card/query/abstract_query/tie.rb', line 101

def op_and_id_or_ids_from_val val
  if (single_id = id_from_val val)
    "= #{single_id}"
  elsif list_of_ids? val
    "in (#{val.map { |v| id_from_val v }.join ', '})"
  end
end

#restrict(id_field, val) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/card/query/abstract_query/tie.rb', line 86

def restrict id_field, val
  if (id = id_from_val val)
    interpret id_field => id
  else
    tie :card, val, from: id_field
  end
end

#super_conditions(fields) ⇒ Object



78
79
80
# File 'lib/card/query/abstract_query/tie.rb', line 78

def super_conditions fields
  superfield fields[:to], fields[:from]
end

#superfield(myfield, superfield) ⇒ Object



82
83
84
# File 'lib/card/query/abstract_query/tie.rb', line 82

def superfield myfield, superfield
  add_condition "#{fld myfield} = #{superquery.fld superfield}"
end

#tie(subquery_type, val, fields = {}, subquery_args = {}) ⇒ Object



19
20
21
22
23
24
# File 'lib/card/query/abstract_query/tie.rb', line 19

def tie subquery_type, val, fields={}, subquery_args={}
  subquery = tie_subquery subquery_type, subquery_args
  subquery.interpret val
  fields = { from: :id, to: :id }.merge fields
  fasten_tie subquery, fields
end

#tie_subquery(subquery_type, subquery_args) ⇒ Object



26
27
28
29
# File 'lib/card/query/abstract_query/tie.rb', line 26

def tie_subquery subquery_type, subquery_args
  subquery_args[:class] = Query.class_for subquery_type
  subquery(subquery_args)
end

#tie_with_exist(subquery, fields) ⇒ Object



48
49
50
# File 'lib/card/query/abstract_query/tie.rb', line 48

def tie_with_exist subquery, fields
  subquery.super_conditions fields if fields.present?
end

#tie_with_in(subquery, fields) ⇒ Object



43
44
45
46
# File 'lib/card/query/abstract_query/tie.rb', line 43

def tie_with_in subquery, fields
  subquery.mods[:return] = fields[:to]
  subquery.mods[:in_field] = fld(fields[:from])
end

#tie_with_join(subquery, fields = {}) ⇒ Object



37
38
39
40
41
# File 'lib/card/query/abstract_query/tie.rb', line 37

def tie_with_join subquery, fields={}
  join = Join.new tie_with_join_args(subquery, fields)
  negate_join(subquery, join, fields) if subquery.negate
  joins << join
end

#tie_with_join_args(subquery, fields) ⇒ Object



56
57
58
59
60
61
# File 'lib/card/query/abstract_query/tie.rb', line 56

def tie_with_join_args subquery, fields
  args = { from: self, from_field: fields[:from],
           to: subquery, to_field: fields[:to] }
  args[:side] = :left if left_join? subquery
  args
end