Class: QueryBuilder::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/query_builder/query.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(processor_class) ⇒ Query

Returns a new instance of Query.



15
16
17
18
19
20
21
22
23
24
# File 'lib/query_builder/query.rb', line 15

def initialize(processor_class)
  @processor_class = processor_class
  @tables = []
  @table_alias = {}
  @join_tables = {}
  @needed_join_tables = {}
  @attributes_alias   = {}
  @key_value_tables   = {}
  @where = []
end

Instance Attribute Details

#attributes_aliasObject

Returns the value of attribute attributes_alias.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def attributes_alias
  @attributes_alias
end

#contextObject

Returns the value of attribute context.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def context
  @context
end

#distinctObject

Returns the value of attribute distinct.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def distinct
  @distinct
end

#errorObject

Returns the value of attribute error.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def error
  @error
end

#groupObject

Returns the value of attribute group.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def group
  @group
end

#havingObject

Returns the value of attribute having.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def having
  @having
end

#key_value_tablesObject

Returns the value of attribute key_value_tables.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def key_value_tables
  @key_value_tables
end

#limitObject

Returns the value of attribute limit.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def limit
  @limit
end

#main_classObject

Return the class of resulting objects (different from default_class if the value has been changed by the query building process).



33
34
35
# File 'lib/query_builder/query.rb', line 33

def main_class
  @main_class
end

#offsetObject

Returns the value of attribute offset.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def offset
  @offset
end

#orderObject

Returns the value of attribute order.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def order
  @order
end

#page_sizeObject

Returns the value of attribute page_size.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def page_size
  @page_size
end

#pagination_keyObject

Returns the value of attribute pagination_key.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def pagination_key
  @pagination_key
end

#processor_classObject

Returns the value of attribute processor_class.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def processor_class
  @processor_class
end

#selectObject

Returns the value of attribute select.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def select
  @select
end

#table_aliasObject

Returns the value of attribute table_alias.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def table_alias
  @table_alias
end

#tablesObject

Returns the value of attribute tables.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def tables
  @tables
end

#whereObject

Returns the value of attribute where.



5
6
7
# File 'lib/query_builder/query.rb', line 5

def where
  @where
end

Class Method Details

.adapterObject



10
11
12
# File 'lib/query_builder/query.rb', line 10

def adapter
  @adapter ||= ActiveRecord::Base.connection.class.name.split('::').last[/(.+)Adapter/,1].downcase
end

Instance Method Details

#add_filter(filter) ⇒ Object



55
56
57
# File 'lib/query_builder/query.rb', line 55

def add_filter(filter)
  @where << filter
end

#add_key_value_table(use_name, index_table, key, &block) ⇒ Object

Add a table to ‘import’ a key/value based field. This method ensures that a given field is only included once for each context.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/query_builder/query.rb', line 118

def add_key_value_table(use_name, index_table, key, &block)
  key_tables = (@key_value_tables[table] ||= {})
  key_table = (key_tables[use_name] ||= {})
  if alias_table = key_table[key]
    # done, the index_table has been used for the given key in the current context
  else
    # insert the new table
    add_table(use_name, index_table, false)
    alias_table = key_table[key] = table(use_name)
    # Let caller configure the filter (join).
    block.call(alias_table)
  end
  alias_table
end

#add_select(field, fname) ⇒ Object



133
134
135
136
137
# File 'lib/query_builder/query.rb', line 133

def add_select(field, fname)
  @select ||= ["#{main_table}.*"]
  @select << "#{field} AS #{quote_column_name(fname)}"
  @attributes_alias[fname] = field
end

#add_table(use_name, table_name = nil, avoid_alias = true) ⇒ Object

‘avoid_alias’ is used when parsing the last element so that it takes the real table name (nodes, not no1). We need this because we can use ‘OR’ between parts and we thus need the same table reference.



111
112
113
114
# File 'lib/query_builder/query.rb', line 111

def add_table(use_name, table_name = nil, avoid_alias = true)
  alias_name = get_alias(use_name, table_name, avoid_alias)
  add_alias_to_tables(table_name || use_name, alias_name)
end

#default_classObject

Return the default class of resulting objects (usually the base class).



48
49
50
51
52
53
# File 'lib/query_builder/query.rb', line 48

def default_class
  @default_class ||= begin
    klass = @processor_class.main_class
    QueryBuilder.resolve_const(klass)
  end
end

#dupObject

Duplicate query, avoiding sharing some arrays and hash



165
166
167
168
169
170
171
# File 'lib/query_builder/query.rb', line 165

def dup
  other = super
  %w{tables table_alias where tables key_value_tables}.each do |k|
    other.send("#{k}=", other.send(k).dup)
  end
  other
end

#filterObject



206
207
208
# File 'lib/query_builder/query.rb', line 206

def filter
  @where.reverse.join(' AND ')
end

#main_tableObject



26
27
28
29
# File 'lib/query_builder/query.rb', line 26

def main_table
  # @main_table is only used in custom queries
  @main_table || processor_class.main_table
end

#master_class(after_class = ActiveRecord::Base) ⇒ Object



37
38
39
40
41
42
43
44
45
# File 'lib/query_builder/query.rb', line 37

def master_class(after_class = ActiveRecord::Base)
  klass = main_class
  klass = klass.first if klass.kind_of?(Array)
  begin
    up = klass.superclass
    return klass if up == after_class
  end while klass = up
  return main_class
end

#needs_join_table(table_name1, type, table_name2, clause, join_name = nil) ⇒ Object

Use this method to add a join to another table (added only once for each join name). nodes JOIN idx_nodes_string AS id1 ON … FIXME: can we remove this ? It seems buggy (JOIN in or clauses)



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/query_builder/query.rb', line 146

def needs_join_table(table_name1, type, table_name2, clause, join_name = nil)
  join_name ||= "#{table_name1}=#{type}=#{table_name2}"
  @needed_join_tables[join_name] ||= {}
  @needed_join_tables[join_name][table] ||= begin
    # define join for this part ('table' = unique for each part)

    # don't add to list of tables, just get unique alias name
    second_table = get_alias(table_name2)

    # create join
    first_table = table(table_name1)

    @join_tables[first_table] ||= []
    @join_tables[first_table] << "#{type} JOIN #{second_table} ON #{clause.gsub('TABLE1',first_table).gsub('TABLE2',second_table)}"
    second_table
  end
end

#quote_column_name(name) ⇒ Object



210
211
212
# File 'lib/query_builder/query.rb', line 210

def quote_column_name(name)
  connection.quote_column_name(name)
end

#rebuild_attributes_hash!Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/query_builder/query.rb', line 187

def rebuild_attributes_hash!
  @attributes_alias = {}
  (@select || []).each do |field|
    if field =~ %r{\A(.*)\s+AS\s+(.+)\Z}i
      key, value = $2, $1
      if key =~ /('|"|`)(.*)\1/
        # TODO: is this clean enough unquoting ?
        key = $2
      end
      @attributes_alias[key] = value
    elsif field =~ %r{^(\w+\.|)([^\*]+)$}
      @attributes_alias[$2] = field
    end
  end
  # Force rebuild
  @select_keys = nil
end

#rebuild_tables!Object

Used after setting @tables from custom query.



174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/query_builder/query.rb', line 174

def rebuild_tables!
  @table_alias = {}
  @tables.each do |t|
    if t =~ /\A(.+)\s+AS\s+(.+)\Z/
      base, use_name = $1, $2
    else
      base = use_name = t
    end
    @table_alias[base] ||= []
    @table_alias[base] << use_name
  end
end

#select_keysObject

Return all explicit selected keys (currently selection is only available in custom queries) For example, sql such as “SELECT form.*, MAX(form.date) AS last_date” would provice ‘last_date’ key.



61
62
63
# File 'lib/query_builder/query.rb', line 61

def select_keys
  @select_keys ||= @attributes_alias.keys.compact
end

#sql(bindings, type = :find) ⇒ Object

Convert the query object into an SQL query.

Parameters

bindings<Binding>

Binding context in which to evaluate bind clauses (query arguments).

type<Symbol>

Type of SQL query (:find or :count)

Returns

NilClass

If the query is not valid and “ignore_warnings” was not set to true during initialize.

String

An SQL query, ready for execution (no more bind variables).

Examples

query.sql(binding)

> “SELECT objects.* FROM objects WHERE objects.project_id = 12489”

query.sql(bindings, :count)

> “SELECT COUNT(*) FROM objects WHERE objects.project_id = 12489”



104
105
106
107
# File 'lib/query_builder/query.rb', line 104

def sql(bindings, type = :find)
  statement, bind_values = build_statement(type)
  statement.gsub('?') { eval_bound_value(bind_values.shift, connection, bindings) }
end

#table(table_name = main_table, index = 0) ⇒ Object



139
140
141
# File 'lib/query_builder/query.rb', line 139

def table(table_name = main_table, index = 0)
  @table_alias[table_name] ? @table_alias[table_name][index - 1] : nil
end

#to_s(type = :find) ⇒ Object

Convert query object to a string. This string should then be evaluated.

Parameters

type<Symbol>

Type of query to build (:find or :count).

Returns

NilClass

If the query is not valid and “ignore_warnings” was not set to true during initialize.

String

A string representing the query with its bind parameters.

Examples

query.to_s

> “[%Qobjects.* FROM objects WHERE objects.project_id = ?, project_id]”

DummyQuery.new(“nodes in site”).to_s

> “%Qobjects.* FROM objects”

query.to_s(:count)

> “[%QCOUNT(*) FROM objects WHERE objects.project_id = ?, project_id]”



83
84
85
86
# File 'lib/query_builder/query.rb', line 83

def to_s(type = :find)
  statement, bind_values = build_statement(type)
  bind_values.empty? ? "%Q{#{statement}}" : "[#{[["%Q{#{statement}}"] + bind_values].join(', ')}]"
end