Class: DataMapper::Adapters::Sql::Commands::LoadCommand

Inherits:
Object
  • Object
show all
Defined in:
lib/data_mapper/adapters/sql/commands/load_command.rb

Defined Under Namespace

Classes: ConditionsError, Loader

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(adapter, database_context, primary_class, options = {}) ⇒ LoadCommand

Returns a new instance of LoadCommand.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 123

def initialize(adapter, database_context, primary_class, options = {})
  @adapter, @database_context, @primary_class = adapter, database_context, primary_class
  
  # BEGIN: Partion out the options hash into general options,
  # and conditions.
  standard_find_options = @adapter.class::FIND_OPTIONS
  conditions_hash = {}
  @options = {}
  
  options.each do |key,value|
    if standard_find_options.include?(key) && key != :conditions
      @options[key] = value
    else
      conditions_hash[key] = value
    end
  end
  # END
  
  @order = @options[:order]
  @limit = @options[:limit]
  @offset = @options[:offset]
  @reload = @options[:reload]
  @instance_id = conditions_hash[:id]
  @conditions = parse_conditions(conditions_hash)
  @loaders = Hash.new { |h,k| h[k] = Loader.new(self, k) }
end

Instance Attribute Details

#conditionsObject (readonly)

Access the Conditions instance



164
165
166
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 164

def conditions
  @conditions
end

#database_contextObject (readonly)

Returns the value of attribute database_context.



121
122
123
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 121

def database_context
  @database_context
end

#optionsObject (readonly)

Returns the value of attribute options.



121
122
123
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 121

def options
  @options
end

Class Method Details

.qualify_columns?Boolean

Returns:

  • (Boolean)


313
314
315
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 313

def self.qualify_columns?
  @qualify_columns
end

Instance Method Details

#callObject



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 188

def call
  
  # Check to see if the query is for a specific id and return if found
  #
  # NOTE: If the :id option is an Array:
  # We could search for loaded instance ids and reject from
  # the Array for already loaded instances, but working under the
  # assumption that we'll probably have to issue a query to find
  # at-least some of the instances we're looking for, it's faster to
  # just skip that and go straight for the query.
  unless reload? || @instance_id.blank? || @instance_id.is_a?(Array)
    # If the id is for only a single record, attempt to find it.
    if instance = @database_context.identity_map.get(@primary_class, @instance_id)
      return [instance]
    end
  end
  
  results = []
  
  # Execute the statement and load the objects.
  @adapter.connection do |db|
    sql, *parameters = to_parameterized_sql
    command = db.create_command(sql)
    command.execute_reader(*parameters) do |reader|
      if @options.has_key?(:intercept_load)
        load(reader, &@options[:intercept_load])
      else
        load(reader)
      end
    end
  end
  
  results += @loaders[@primary_class].loaded_set
  
  return results
end

#conditions_empty?Boolean

Are any conditions present?

Returns:

  • (Boolean)


247
248
249
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 247

def conditions_empty?
  @conditions.empty?
end

#expression_to_sql(clause, value, collector) ⇒ Object

expression_to_sql takes a set of arguments, and turns them into a an Array of generated SQL, followed by optional Values to interpolate as SQL-Parameters.

Parameters: clause The name of the column as a Symbol, a raw-SQL String, a Mappings::Column instance, or a Symbol::Operator. value The Value for the condition. collector An Array representing all conditions that is appended to by expression_to_sql

Returns: Undefined Output. The work performed is added to the collector argument. Example:

conditions = []
expression_to_sql(:name, 'Bob', conditions)
=> +undefined return value+
conditions.inspect
=> ["name = ?", 'Bob']


335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 335

def expression_to_sql(clause, value, collector)
  qualify_columns = qualify_columns?

  case clause
  when Symbol::Operator then
    operator = case clause.type
    when :gt then '>'
    when :gte then '>='
    when :lt then '<'
    when :lte then '<='
    when :not then inequality_operator(value)
    when :eql then equality_operator(value)
    when :like then equality_operator(value, 'LIKE')
    when :in then equality_operator(value)
    else raise ArgumentError.new('Operator type not supported')
    end
    collector << ["#{primary_class_table[clause].to_sql(qualify_columns)} #{operator} ?", value]
  when Symbol then
    collector << ["#{primary_class_table[clause].to_sql(qualify_columns)} #{equality_operator(value)} ?", value]
  when String then
    collector << [clause, *value]
  when Mappings::Column then
    collector << ["#{clause.to_sql(qualify_columns)} #{equality_operator(value)} ?", value]
  else raise "CAN HAS CRASH? #{clause.inspect}"
  end
rescue => e
  raise ConditionsError.new(clause, value, e)
end

#inspectObject

Display an overview of load options at a glance.



151
152
153
154
155
156
157
158
159
160
161
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 151

def inspect
  <<-EOS.compress_lines % (object_id * 2)
    #<#{self.class.name}:0x%x
      @database=#{@adapter.name}
      @reload=#{@reload.inspect}
      @order=#{@order.inspect}
      @limit=#{@limit.inspect}
      @offset=#{@offset.inspect}
      @options=#{@options.inspect}>
  EOS
end

#limitObject

Determine if there is a limitation on the number of instances returned in the results. If nil, no limit is set. Can be used in conjunction with #offset for paging through a set of results.



178
179
180
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 178

def limit
  @limit
end

#load(reader) ⇒ Object



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 225

def load(reader)          
  # The following blocks are identical aside from the yield.
  # It's written this way to avoid a conditional within each
  # iterator, and to take advantage of the performance of
  # yield vs. Proc#call.
  if block_given?
    reader.each do
      @loaders.each_pair do |klass,loader|
        row = reader.current_row
        yield(loader.materialize(row), @columns, row)
      end
    end
  else
    reader.each do
      @loaders.each_pair do |klass,loader|
        loader.materialize(reader.current_row)
      end
    end
  end
end

#offsetObject

Used in conjunction with #limit to page through a set of results.



184
185
186
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 184

def offset
  @offset
end

#qualify_columns?Boolean

If more than one table is involved in the query, the column definitions should be qualified by the table name. ie: people.name This method determines wether that needs to happen or not. Note: After the first call, the calculations are avoided by overwriting this method with a simple getter.

Returns:

  • (Boolean)


311
312
313
314
315
316
317
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 311

def qualify_columns?
  @qualify_columns = !(included_associations.empty? && shallow_included_associations.empty?)
  def self.qualify_columns?
    @qualify_columns
  end
  @qualify_columns
end

#reload?Boolean

If true then force the command to reload any objects already existing in the IdentityMap when executing.

Returns:

  • (Boolean)


170
171
172
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 170

def reload?
  @reload
end

#to_parameterized_sqlObject

Generate a select statement based on the initialization arguments.



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/data_mapper/adapters/sql/commands/load_command.rb', line 253

def to_parameterized_sql
  parameters = []
  
  sql = 'SELECT ' << columns_for_select.join(', ')
  sql << ' FROM ' << from_table_name            
  
  included_associations.each do |association|
    sql << ' ' << association.to_sql
  end
  
  shallow_included_associations.each do |association|
    sql << ' ' << association.to_shallow_sql
  end
  
  unless conditions_empty?
    sql << ' WHERE ('
    
    last_index = @conditions.size
    current_index = 0
    
    @conditions.each do |condition|
      case condition
      when String then sql << condition
      when Array then
          sql << condition.shift
          parameters += condition
      else
        raise "Unable to parse condition: #{condition.inspect}" if condition
      end
      
      if (current_index += 1) == last_index
        sql << ')'
      else
        sql << ') AND ('
      end
    end
  end # unless conditions_empty?
  
  unless @order.nil?
    sql << ' ORDER BY ' << @order.to_s
  end
        
  unless @limit.nil?
    sql << ' LIMIT ' << @limit.to_s
  end
  
  unless @offset.nil?
    sql << ' OFFSET ' << @offset.to_s
  end
  
  parameters.unshift(sql)
end