Rails ActiveRecord 这样的链接接口是如何构建的?

How a chaining interface like Rails ActiveRecord is built?

我很好奇。 User.where(name: 'Foo').where(age: 20) 如何只调用一次数据库?

方法 where 是否知道它是否是链的最后一个并改变它的行为?如果可以,如何实现?

它 returns self 每次将查询添加到其内部查询构建器后。

where不一定知道它在哪里; ActiveRecord 在查询数据库之前等待自身被枚举。示例:

users = User.where(active: true)
users.loaded? # false 
users.each { }
users.loaded? # true 

eachmapfirstlast等都会触发查询加载。

这是一个超级简单的查询构建器的例子:

class FakeRecord
  include Enumerable
  def self.all_args
    @all_args ||= []
  end

  def self.where(*args)
    all_args << args 
    self
  end

  def self.each
    puts "Executing sql #{all_args.join(", ")}"
    yield [1, 2, 3]
  end
end

FakeRecord.where(potato: true).where(dinosaur: false).each do |thing|
  puts thing
end