Query objects and delayed execution
Published over 5 years ago
So this morning I got up after sleeping 3-4 hours and all I can somehow think of is having Query objects for ActiveRecord finders and delayed query execution. If done well, this could open pandora’s box of neat ways to extend ActiveRecord. So talk stops here.
Here’s the very basic first draft done under influence ( coffee ;-) ) :
module ActiveRecord class AbstractRecords attr_reader :records, :klass, :query
module ActiveRecord
class AbstractRecords
attr_reader :records, :klass, :query delegate :connection, :instantiate, :name, :to => :klass delegate :sql, :options, :to => :query def initialize(query, klass) @query = query @klass = klass @loaded = false end def method_missing(method_id, *args, &block) load_records records.send(method_id, *args, &block) end def loaded? @loaded end private def load_records return if @loaded @records = connection.select_all(sql, "#{name} Load").collect! { |record| instantiate(record) } @records.each { |record| record.readonly! } if options[:readonly] @loaded = true end end class AbstractQuery < DelegateClass(AbstractRecords) attr_reader :sql, :options def initialize(klass, sql, options = {}) @sql = sql @options = options super(AbstractRecords.new(self, klass)) end endend
So after this, a session from console would look something like :
>> i = Item.find :all, :limit => 10 => #<ActiveRecord::AbstractRecords:0x19520e4 @klass=Item(id: integer, name: string, created_at: datetime, updated_at: datetime), @loaded=false, @query=#<ActiveRecord::AbstractRecords:0x19520e4 ...>> >> i.first Item Load (0.000361) SELECT * FROM `items` LIMIT 10 => #<Item id: 1, name: "wtf", created_at: "2007-12-12 13:28:56", updated_at: "2007-12-12 13:28:56">Notice when the query gets executed. Experimental patch can be found here