Skip to content

Commit ea62c5a

Browse files
committed
[MODEL] Added an ActiveRecord specific adapter for Elasticsearch::Model::Response::Records
Example: > response.records.class => Elasticsearch::Model::Response::Records > response.records.records.class => ActiveRecord::Relation::ActiveRecord_Relation_Article > response.records.to_a Article Load (0.2ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" IN (3, 1) => [#<Article id: 3, title: "Foo Foo", published_at: nil, created_at: "2013-11-07 15:09:23", updated_at: "2013-11-07 15:09:23">, #<Article id: 1, title: "Foo", published_at: nil, created_at: "2013-11-07 15:09:23", updated_at: "2013-11-07 15:09:23">] > response.records.order(id: :desc).to_a Article Load (0.3ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" IN (3, 1) ORDER BY "articles"."id" DESC => [#<Article id: 3, title: "Foo Foo", published_at: nil, created_at: "2013-11-07 15:09:23", updated_at: "2013-11-07 15:09:23">, #<Article id: 1, title: "Foo", published_at: nil, created_at: "2013-11-07 15:09:23", updated_at: "2013-11-07 15:09:23">]
1 parent f39949d commit ea62c5a

File tree

4 files changed

+81
-3
lines changed

4 files changed

+81
-3
lines changed

elasticsearch-model/lib/elasticsearch/model.rb

+4
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44

55
require 'hashie'
66

7+
require 'elasticsearch/model/adapter'
8+
require 'elasticsearch/model/adapters/active_record'
9+
710
require 'elasticsearch/model/response'
811
require 'elasticsearch/model/response/base'
912
require 'elasticsearch/model/response/result'
1013
require 'elasticsearch/model/response/results'
1114
require 'elasticsearch/model/response/records'
1215
require 'elasticsearch/model/searching'
16+
1317
require 'elasticsearch/model/version'
1418

1519
module Elasticsearch
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module Elasticsearch
2+
module Model
3+
module Adapter
4+
def from_class(klass)
5+
Adapter.new(klass)
6+
end
7+
module_function :from_class
8+
9+
class Adapter
10+
11+
def initialize(klass)
12+
end
13+
14+
def response
15+
Elasticsearch::Model::Adapter::ActiveRecord::Records
16+
end
17+
18+
end
19+
end
20+
end
21+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
module Elasticsearch
2+
module Model
3+
module Adapter
4+
module ActiveRecord
5+
6+
module Records
7+
8+
# Return the `ActiveRecord::Relation` instance
9+
#
10+
def records
11+
sql_records = klass.where(id: @ids)
12+
13+
# Re-order records based on the order from Elasticsearch hits
14+
# by redefining `to_a`, unless the user has called `order()`
15+
#
16+
sql_records.instance_exec(response['hits']['hits']) do |hits|
17+
define_singleton_method :to_a do
18+
self.load
19+
@records.sort_by { |record| hits.index { |hit| hit['_id'] == record.id.to_s } }
20+
end
21+
end
22+
23+
sql_records
24+
end
25+
26+
# Prevent clash with `ActiveSupport::Dependencies::Loadable`
27+
#
28+
def load
29+
records.load
30+
end
31+
32+
# Intercept call to order, so we can ignore the order from Elasticsearch
33+
#
34+
def order(*args)
35+
sql_records = records.__send__ :order, *args
36+
37+
# Redefine the `to_a` method to the original one
38+
#
39+
sql_records.instance_exec do
40+
define_singleton_method(:to_a) { self.load; @records }
41+
end
42+
43+
sql_records
44+
end
45+
end
46+
end
47+
48+
end
49+
end
50+
end

elasticsearch-model/lib/elasticsearch/model/response/records.rb

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ class Records
77
def initialize(klass, response)
88
super
99
@ids = response['hits']['hits'].map { |hit| hit['_id'] }
10-
end
1110

12-
def records
13-
@records = klass.find(@ids)
11+
# Include module provided by the adapter in the singleton class ("metaclass")
12+
#
13+
adapter = Adapter.from_class(klass)
14+
metaclass = class << self; self; end
15+
metaclass.__send__ :include, adapter.response
16+
self
1417
end
1518

1619
# Delegate methods to `@records`

0 commit comments

Comments
 (0)