elasticsearch-model 0.0.1 → 0.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/LICENSE.txt +1 -1
- data/README.md +669 -8
- data/Rakefile +52 -0
- data/elasticsearch-model.gemspec +48 -17
- data/examples/activerecord_article.rb +77 -0
- data/examples/activerecord_associations.rb +153 -0
- data/examples/couchbase_article.rb +66 -0
- data/examples/datamapper_article.rb +71 -0
- data/examples/mongoid_article.rb +68 -0
- data/examples/ohm_article.rb +70 -0
- data/examples/riak_article.rb +52 -0
- data/gemfiles/3.gemfile +11 -0
- data/gemfiles/4.gemfile +11 -0
- data/lib/elasticsearch/model.rb +151 -1
- data/lib/elasticsearch/model/adapter.rb +145 -0
- data/lib/elasticsearch/model/adapters/active_record.rb +97 -0
- data/lib/elasticsearch/model/adapters/default.rb +44 -0
- data/lib/elasticsearch/model/adapters/mongoid.rb +90 -0
- data/lib/elasticsearch/model/callbacks.rb +35 -0
- data/lib/elasticsearch/model/client.rb +61 -0
- data/lib/elasticsearch/model/importing.rb +94 -0
- data/lib/elasticsearch/model/indexing.rb +332 -0
- data/lib/elasticsearch/model/naming.rb +101 -0
- data/lib/elasticsearch/model/proxy.rb +127 -0
- data/lib/elasticsearch/model/response.rb +70 -0
- data/lib/elasticsearch/model/response/base.rb +44 -0
- data/lib/elasticsearch/model/response/pagination.rb +96 -0
- data/lib/elasticsearch/model/response/records.rb +71 -0
- data/lib/elasticsearch/model/response/result.rb +50 -0
- data/lib/elasticsearch/model/response/results.rb +32 -0
- data/lib/elasticsearch/model/searching.rb +107 -0
- data/lib/elasticsearch/model/serializing.rb +35 -0
- data/lib/elasticsearch/model/support/forwardable.rb +44 -0
- data/lib/elasticsearch/model/version.rb +1 -1
- data/test/integration/active_record_associations_parent_child.rb +138 -0
- data/test/integration/active_record_associations_test.rb +306 -0
- data/test/integration/active_record_basic_test.rb +139 -0
- data/test/integration/active_record_import_test.rb +74 -0
- data/test/integration/active_record_namespaced_model_test.rb +49 -0
- data/test/integration/active_record_pagination_test.rb +109 -0
- data/test/integration/mongoid_basic_test.rb +178 -0
- data/test/test_helper.rb +57 -0
- data/test/unit/adapter_active_record_test.rb +93 -0
- data/test/unit/adapter_default_test.rb +31 -0
- data/test/unit/adapter_mongoid_test.rb +87 -0
- data/test/unit/adapter_test.rb +69 -0
- data/test/unit/callbacks_test.rb +30 -0
- data/test/unit/client_test.rb +27 -0
- data/test/unit/importing_test.rb +97 -0
- data/test/unit/indexing_test.rb +364 -0
- data/test/unit/module_test.rb +46 -0
- data/test/unit/naming_test.rb +76 -0
- data/test/unit/proxy_test.rb +88 -0
- data/test/unit/response_base_test.rb +40 -0
- data/test/unit/response_pagination_test.rb +159 -0
- data/test/unit/response_records_test.rb +87 -0
- data/test/unit/response_result_test.rb +52 -0
- data/test/unit/response_results_test.rb +31 -0
- data/test/unit/response_test.rb +57 -0
- data/test/unit/searching_search_request_test.rb +73 -0
- data/test/unit/searching_test.rb +39 -0
- data/test/unit/serializing_test.rb +17 -0
- metadata +418 -11
@@ -0,0 +1,68 @@
|
|
1
|
+
# Mongoid and Elasticsearch
|
2
|
+
# =========================
|
3
|
+
#
|
4
|
+
# http://mongoid.org/en/mongoid/index.html
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
7
|
+
|
8
|
+
require 'pry'
|
9
|
+
Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
|
10
|
+
|
11
|
+
require 'benchmark'
|
12
|
+
require 'logger'
|
13
|
+
require 'ansi/core'
|
14
|
+
require 'mongoid'
|
15
|
+
|
16
|
+
require 'elasticsearch/model'
|
17
|
+
require 'elasticsearch/model/callbacks'
|
18
|
+
|
19
|
+
Mongoid.logger.level = Logger::DEBUG
|
20
|
+
Moped.logger.level = Logger::DEBUG
|
21
|
+
|
22
|
+
Mongoid.connect_to 'articles'
|
23
|
+
|
24
|
+
Elasticsearch::Model.client = Elasticsearch::Client.new host: 'localhost:9250', log: true
|
25
|
+
|
26
|
+
class Article
|
27
|
+
include Mongoid::Document
|
28
|
+
field :id, type: String
|
29
|
+
field :title, type: String
|
30
|
+
field :published_at, type: DateTime
|
31
|
+
attr_accessible :id, :title, :published_at if respond_to? :attr_accessible
|
32
|
+
|
33
|
+
def as_indexed_json(options={})
|
34
|
+
as_json(except: [:id, :_id])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Extend the model with Elasticsearch support
|
39
|
+
#
|
40
|
+
Article.__send__ :include, Elasticsearch::Model
|
41
|
+
# Article.__send__ :include, Elasticsearch::Model::Callbacks
|
42
|
+
|
43
|
+
# Store data
|
44
|
+
#
|
45
|
+
Article.delete_all
|
46
|
+
Article.create id: '1', title: 'Foo'
|
47
|
+
Article.create id: '2', title: 'Bar'
|
48
|
+
Article.create id: '3', title: 'Foo Foo'
|
49
|
+
|
50
|
+
# Index data
|
51
|
+
#
|
52
|
+
client = Elasticsearch::Client.new host:'localhost:9250', log:true
|
53
|
+
|
54
|
+
client.indices.delete index: 'articles' rescue nil
|
55
|
+
client.bulk index: 'articles',
|
56
|
+
type: 'article',
|
57
|
+
body: Article.all.map { |a| { index: { _id: a.id, data: a.attributes } } },
|
58
|
+
refresh: true
|
59
|
+
|
60
|
+
# puts Benchmark.realtime { 9_875.times { |i| Article.create title: "Foo #{i}" } }
|
61
|
+
|
62
|
+
puts '', '-'*Pry::Terminal.width!
|
63
|
+
|
64
|
+
response = Article.search 'foo';
|
65
|
+
|
66
|
+
Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
|
67
|
+
input: StringIO.new('response.records.to_a'),
|
68
|
+
quiet: true)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Ohm for Redis and Elasticsearch
|
2
|
+
# ===============================
|
3
|
+
#
|
4
|
+
# https://github.com/soveran/ohm#example
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
7
|
+
|
8
|
+
require 'pry'
|
9
|
+
Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
|
10
|
+
|
11
|
+
require 'logger'
|
12
|
+
require 'ansi/core'
|
13
|
+
require 'active_model'
|
14
|
+
require 'ohm'
|
15
|
+
|
16
|
+
require 'elasticsearch/model'
|
17
|
+
|
18
|
+
class Article < Ohm::Model
|
19
|
+
# Include JSON serialization from ActiveModel
|
20
|
+
include ActiveModel::Serializers::JSON
|
21
|
+
|
22
|
+
attribute :title
|
23
|
+
attribute :published_at
|
24
|
+
end
|
25
|
+
|
26
|
+
# Extend the model with Elasticsearch support
|
27
|
+
#
|
28
|
+
Article.__send__ :include, Elasticsearch::Model
|
29
|
+
|
30
|
+
# Register a custom adapter
|
31
|
+
#
|
32
|
+
module Elasticsearch
|
33
|
+
module Model
|
34
|
+
module Adapter
|
35
|
+
module Ohm
|
36
|
+
Adapter.register self,
|
37
|
+
lambda { |klass| defined?(::Ohm::Model) and klass.ancestors.include?(::Ohm::Model) }
|
38
|
+
module Records
|
39
|
+
def records
|
40
|
+
klass.fetch(@ids)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Configure the Elasticsearch client to log operations
|
49
|
+
#
|
50
|
+
Elasticsearch::Model.client = Elasticsearch::Client.new log: true
|
51
|
+
|
52
|
+
puts '', '-'*Pry::Terminal.width!
|
53
|
+
|
54
|
+
Article.all.map { |a| a.delete }
|
55
|
+
Article.create id: '1', title: 'Foo'
|
56
|
+
Article.create id: '2', title: 'Bar'
|
57
|
+
Article.create id: '3', title: 'Foo Foo'
|
58
|
+
|
59
|
+
Article.__elasticsearch__.client.indices.delete index: 'articles' rescue nil
|
60
|
+
Article.__elasticsearch__.client.bulk index: 'articles',
|
61
|
+
type: 'article',
|
62
|
+
body: Article.all.map { |a| { index: { _id: a.id, data: a.attributes } } },
|
63
|
+
refresh: true
|
64
|
+
|
65
|
+
|
66
|
+
response = Article.search 'foo', index: 'articles', type: 'article';
|
67
|
+
|
68
|
+
Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
|
69
|
+
input: StringIO.new('response.records.to_a'),
|
70
|
+
quiet: true)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Riak and Elasticsearch
|
2
|
+
# ======================
|
3
|
+
#
|
4
|
+
# https://github.com/basho-labs/ripple
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
7
|
+
|
8
|
+
require 'pry'
|
9
|
+
Pry.config.history.file = File.expand_path('../../tmp/elasticsearch_development.pry', __FILE__)
|
10
|
+
|
11
|
+
require 'logger'
|
12
|
+
require 'ripple'
|
13
|
+
|
14
|
+
require 'elasticsearch/model'
|
15
|
+
|
16
|
+
# Documents are stored as JSON objects in Riak but have rich
|
17
|
+
# semantics, including validations and associations.
|
18
|
+
class Article
|
19
|
+
include Ripple::Document
|
20
|
+
|
21
|
+
property :title, String
|
22
|
+
property :published_at, Time, :default => proc { Time.now }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Extend the model with Elasticsearch support
|
26
|
+
#
|
27
|
+
Article.__send__ :include, Elasticsearch::Model
|
28
|
+
|
29
|
+
# Create documents in Riak
|
30
|
+
#
|
31
|
+
Article.destroy_all
|
32
|
+
Article.create id: '1', title: 'Foo'
|
33
|
+
Article.create id: '2', title: 'Bar'
|
34
|
+
Article.create id: '3', title: 'Foo Foo'
|
35
|
+
|
36
|
+
# Index data into Elasticsearch
|
37
|
+
#
|
38
|
+
client = Elasticsearch::Client.new log:true
|
39
|
+
|
40
|
+
client.indices.delete index: 'articles' rescue nil
|
41
|
+
client.bulk index: 'articles',
|
42
|
+
type: 'article',
|
43
|
+
body: Article.all.map { |a|
|
44
|
+
{ index: { _id: a.key, data: JSON.parse(a.robject.raw_data) } }
|
45
|
+
}.as_json,
|
46
|
+
refresh: true
|
47
|
+
|
48
|
+
response = Article.search 'foo';
|
49
|
+
|
50
|
+
Pry.start(binding, prompt: lambda { |obj, nest_level, _| '> ' },
|
51
|
+
input: StringIO.new('response.records.to_a'),
|
52
|
+
quiet: true)
|
data/gemfiles/3.gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Usage:
|
2
|
+
#
|
3
|
+
# $ BUNDLE_GEMFILE=./gemfiles/3.gemfile bundle install
|
4
|
+
# $ BUNDLE_GEMFILE=./gemfiles/3.gemfile bundle exec rake test:integration
|
5
|
+
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
|
8
|
+
gem 'activerecord', '~> 3.2'
|
9
|
+
gem 'mongoid', '>= 3.0'
|
10
|
+
|
11
|
+
gemspec path: '../'
|
data/gemfiles/4.gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# Usage:
|
2
|
+
#
|
3
|
+
# $ BUNDLE_GEMFILE=./gemfiles/4.gemfile bundle install
|
4
|
+
# $ BUNDLE_GEMFILE=./gemfiles/4.gemfile bundle exec rake test:integration
|
5
|
+
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
|
8
|
+
gem 'activerecord', '~> 4'
|
9
|
+
gem 'mongoid', '~> 4.0.0.alpha1'
|
10
|
+
|
11
|
+
gemspec path: '../'
|
data/lib/elasticsearch/model.rb
CHANGED
@@ -1,6 +1,156 @@
|
|
1
|
-
require
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
require 'elasticsearch'
|
4
|
+
|
5
|
+
require 'hashie'
|
6
|
+
|
7
|
+
require 'elasticsearch/model/support/forwardable'
|
8
|
+
|
9
|
+
require 'elasticsearch/model/client'
|
10
|
+
|
11
|
+
require 'elasticsearch/model/adapter'
|
12
|
+
require 'elasticsearch/model/adapters/default'
|
13
|
+
require 'elasticsearch/model/adapters/active_record'
|
14
|
+
require 'elasticsearch/model/adapters/mongoid'
|
15
|
+
|
16
|
+
require 'elasticsearch/model/importing'
|
17
|
+
require 'elasticsearch/model/indexing'
|
18
|
+
require 'elasticsearch/model/naming'
|
19
|
+
require 'elasticsearch/model/serializing'
|
20
|
+
require 'elasticsearch/model/searching'
|
21
|
+
require 'elasticsearch/model/callbacks'
|
22
|
+
|
23
|
+
require 'elasticsearch/model/proxy'
|
24
|
+
|
25
|
+
require 'elasticsearch/model/response'
|
26
|
+
require 'elasticsearch/model/response/base'
|
27
|
+
require 'elasticsearch/model/response/result'
|
28
|
+
require 'elasticsearch/model/response/results'
|
29
|
+
require 'elasticsearch/model/response/records'
|
30
|
+
require 'elasticsearch/model/response/pagination'
|
31
|
+
|
32
|
+
require 'elasticsearch/model/version'
|
33
|
+
|
34
|
+
if defined?(::Kaminari)
|
35
|
+
Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari
|
36
|
+
end
|
2
37
|
|
3
38
|
module Elasticsearch
|
39
|
+
|
40
|
+
# Elasticsearch integration for Ruby models
|
41
|
+
# =========================================
|
42
|
+
#
|
43
|
+
# `Elasticsearch::Model` contains modules for integrating the Elasticsearch search and analytical engine
|
44
|
+
# with ActiveModel-based classes, or models, for the Ruby programming language.
|
45
|
+
#
|
46
|
+
# It facilitates importing your data into an index, automatically updating it when a record changes,
|
47
|
+
# searching the specific index, setting up the index mapping or the model JSON serialization.
|
48
|
+
#
|
49
|
+
# When the `Elasticsearch::Model` module is included in your class, it automatically extends it
|
50
|
+
# with the functionality; see {Elasticsearch::Model.included}. Most methods are available via
|
51
|
+
# the `__elasticsearch__` class and instance method proxies.
|
52
|
+
#
|
53
|
+
# It is possible to include/extend the model with the corresponding
|
54
|
+
# modules directly, if that is desired:
|
55
|
+
#
|
56
|
+
# MyModel.__send__ :extend, Elasticsearch::Model::Client::ClassMethods
|
57
|
+
# MyModel.__send__ :include, Elasticsearch::Model::Client::InstanceMethods
|
58
|
+
# MyModel.__send__ :extend, Elasticsearch::Model::Searching::ClassMethods
|
59
|
+
# # ...
|
60
|
+
#
|
4
61
|
module Model
|
62
|
+
|
63
|
+
# Adds the `Elasticsearch::Model` functionality to the including class.
|
64
|
+
#
|
65
|
+
# * Creates the `__elasticsearch__` class and instance methods, pointing to the proxy object
|
66
|
+
# * Includes the necessary modules in the proxy classes
|
67
|
+
# * Sets up delegation for crucial methods such as `search`, etc.
|
68
|
+
#
|
69
|
+
# @example Include the module in the `Article` model definition
|
70
|
+
#
|
71
|
+
# class Article < ActiveRecord::Base
|
72
|
+
# include Elasticsearch::Model
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# @example Inject the module into the `Article` model during run time
|
76
|
+
#
|
77
|
+
# Article.__send__ :include, Elasticsearch::Model
|
78
|
+
#
|
79
|
+
#
|
80
|
+
def self.included(base)
|
81
|
+
base.class_eval do
|
82
|
+
include Elasticsearch::Model::Proxy
|
83
|
+
|
84
|
+
Elasticsearch::Model::Proxy::ClassMethodsProxy.class_eval do
|
85
|
+
include Elasticsearch::Model::Client::ClassMethods
|
86
|
+
include Elasticsearch::Model::Naming::ClassMethods
|
87
|
+
include Elasticsearch::Model::Indexing::ClassMethods
|
88
|
+
include Elasticsearch::Model::Searching::ClassMethods
|
89
|
+
end
|
90
|
+
|
91
|
+
Elasticsearch::Model::Proxy::InstanceMethodsProxy.class_eval do
|
92
|
+
include Elasticsearch::Model::Client::InstanceMethods
|
93
|
+
include Elasticsearch::Model::Naming::InstanceMethods
|
94
|
+
include Elasticsearch::Model::Indexing::InstanceMethods
|
95
|
+
include Elasticsearch::Model::Serializing::InstanceMethods
|
96
|
+
end
|
97
|
+
|
98
|
+
Elasticsearch::Model::Proxy::InstanceMethodsProxy.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
99
|
+
def as_indexed_json(options={})
|
100
|
+
target.respond_to?(:as_indexed_json) ? target.__send__(:as_indexed_json, options) : super
|
101
|
+
end
|
102
|
+
CODE
|
103
|
+
|
104
|
+
# Delegate important methods to the `__elasticsearch__` proxy, unless they are defined already
|
105
|
+
#
|
106
|
+
extend Support::Forwardable
|
107
|
+
forward :'self.__elasticsearch__', :search unless respond_to?(:search)
|
108
|
+
forward :'self.__elasticsearch__', :mapping unless respond_to?(:mapping)
|
109
|
+
forward :'self.__elasticsearch__', :mappings unless respond_to?(:mappings)
|
110
|
+
forward :'self.__elasticsearch__', :settings unless respond_to?(:settings)
|
111
|
+
forward :'self.__elasticsearch__', :index_name unless respond_to?(:index_name)
|
112
|
+
forward :'self.__elasticsearch__', :document_type unless respond_to?(:document_type)
|
113
|
+
forward :'self.__elasticsearch__', :import unless respond_to?(:import)
|
114
|
+
|
115
|
+
# Mix the importing module into the proxy
|
116
|
+
#
|
117
|
+
self.__elasticsearch__.class_eval do
|
118
|
+
include Elasticsearch::Model::Importing::ClassMethods
|
119
|
+
include Adapter.from_class(base).importing_mixin
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
module ClassMethods
|
125
|
+
|
126
|
+
# Get the client common for all models
|
127
|
+
#
|
128
|
+
# @example Get the client
|
129
|
+
#
|
130
|
+
# Elasticsearch::Model.client
|
131
|
+
# => #<Elasticsearch::Transport::Client:0x007f96a7d0d000 @transport=... >
|
132
|
+
#
|
133
|
+
def client
|
134
|
+
@client ||= Elasticsearch::Client.new
|
135
|
+
end
|
136
|
+
|
137
|
+
# Set the client for all models
|
138
|
+
#
|
139
|
+
# @example Configure (set) the client for all models
|
140
|
+
#
|
141
|
+
# Elasticsearch::Model.client Elasticsearch::Client.new host: 'http://localhost:9200', tracer: true
|
142
|
+
# => #<Elasticsearch::Transport::Client:0x007f96a6dd0d80 @transport=... >
|
143
|
+
#
|
144
|
+
# @note You have to set the client before you call Elasticsearch methods on the model,
|
145
|
+
# or set it directly on the model; see {Elasticsearch::Model::Client::ClassMethods#client}
|
146
|
+
#
|
147
|
+
def client=(client)
|
148
|
+
@client = client
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
extend ClassMethods
|
153
|
+
|
154
|
+
class NotImplemented < NoMethodError; end
|
5
155
|
end
|
6
156
|
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# Contains an adapter which provides OxM-specific implementations for common behaviour:
|
5
|
+
#
|
6
|
+
# * {Adapter::Adapter#records_mixin Fetching records from the database}
|
7
|
+
# * {Adapter::Adapter#callbacks_mixin Model callbacks for automatic index updates}
|
8
|
+
# * {Adapter::Adapter#importing_mixin Efficient bulk loading from the database}
|
9
|
+
#
|
10
|
+
# @see Elasticsearch::Model::Adapter::Default
|
11
|
+
# @see Elasticsearch::Model::Adapter::ActiveRecord
|
12
|
+
# @see Elasticsearch::Model::Adapter::Mongoid
|
13
|
+
#
|
14
|
+
module Adapter
|
15
|
+
|
16
|
+
# Returns an adapter based on the Ruby class passed
|
17
|
+
#
|
18
|
+
# @example Create an adapter for an ActiveRecord-based model
|
19
|
+
#
|
20
|
+
# class Article < ActiveRecord::Base; end
|
21
|
+
#
|
22
|
+
# myadapter = Elasticsearch::Model::Adapter.from_class(Article)
|
23
|
+
# myadapter.adapter
|
24
|
+
# # => Elasticsearch::Model::Adapter::ActiveRecord
|
25
|
+
#
|
26
|
+
# @see Adapter.adapters The list of included adapters
|
27
|
+
# @see Adapter.register Register a custom adapter
|
28
|
+
#
|
29
|
+
def from_class(klass)
|
30
|
+
Adapter.new(klass)
|
31
|
+
end; module_function :from_class
|
32
|
+
|
33
|
+
# Returns registered adapters
|
34
|
+
#
|
35
|
+
# @see ::Elasticsearch::Model::Adapter::Adapter.adapters
|
36
|
+
#
|
37
|
+
def adapters
|
38
|
+
Adapter.adapters
|
39
|
+
end; module_function :adapters
|
40
|
+
|
41
|
+
# Registers an adapter
|
42
|
+
#
|
43
|
+
# @see ::Elasticsearch::Model::Adapter::Adapter.register
|
44
|
+
#
|
45
|
+
def register(name, condition)
|
46
|
+
Adapter.register(name, condition)
|
47
|
+
end; module_function :register
|
48
|
+
|
49
|
+
# Contains an adapter for specific OxM or architecture.
|
50
|
+
#
|
51
|
+
class Adapter
|
52
|
+
attr_reader :klass
|
53
|
+
|
54
|
+
def initialize(klass)
|
55
|
+
@klass = klass
|
56
|
+
end
|
57
|
+
|
58
|
+
# Registers an adapter for specific condition
|
59
|
+
#
|
60
|
+
# @param name [Module] The module containing the implemented interface
|
61
|
+
# @param condition [Proc] An object with a `call` method which is evaluated in {.adapter}
|
62
|
+
#
|
63
|
+
# @example Register an adapter for DataMapper
|
64
|
+
#
|
65
|
+
# module DataMapperAdapter
|
66
|
+
#
|
67
|
+
# # Implement the interface for fetching records
|
68
|
+
# #
|
69
|
+
# module Records
|
70
|
+
# def records
|
71
|
+
# klass.all(id: @ids)
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# # ...
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# # Register the adapter
|
79
|
+
# #
|
80
|
+
# Elasticsearch::Model::Adapter.register(
|
81
|
+
# DataMapperAdapter,
|
82
|
+
# lambda { |klass|
|
83
|
+
# defined?(::DataMapper::Resource) and klass.ancestors.include?(::DataMapper::Resource)
|
84
|
+
# }
|
85
|
+
# )
|
86
|
+
#
|
87
|
+
def self.register(name, condition)
|
88
|
+
self.adapters[name] = condition
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return the collection of registered adapters
|
92
|
+
#
|
93
|
+
# @example Return the currently registered adapters
|
94
|
+
#
|
95
|
+
# Elasticsearch::Model::Adapter.adapters
|
96
|
+
# # => {
|
97
|
+
# # Elasticsearch::Model::Adapter::ActiveRecord => #<Proc:0x007...(lambda)>,
|
98
|
+
# # Elasticsearch::Model::Adapter::Mongoid => #<Proc:0x007... (lambda)>,
|
99
|
+
# # }
|
100
|
+
#
|
101
|
+
# @return [Hash] The collection of adapters
|
102
|
+
#
|
103
|
+
def self.adapters
|
104
|
+
@adapters ||= {}
|
105
|
+
end
|
106
|
+
|
107
|
+
# Return the module with {Default::Records} interface implementation
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
#
|
111
|
+
def records_mixin
|
112
|
+
adapter.const_get(:Records)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Return the module with {Default::Callbacks} interface implementation
|
116
|
+
#
|
117
|
+
# @api private
|
118
|
+
#
|
119
|
+
def callbacks_mixin
|
120
|
+
adapter.const_get(:Callbacks)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Return the module with {Default::Importing} interface implementation
|
124
|
+
#
|
125
|
+
# @api private
|
126
|
+
#
|
127
|
+
def importing_mixin
|
128
|
+
adapter.const_get(:Importing)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns the adapter module
|
132
|
+
#
|
133
|
+
# @api private
|
134
|
+
#
|
135
|
+
def adapter
|
136
|
+
@adapter ||= begin
|
137
|
+
self.class.adapters.find( lambda {[]} ) { |name, condition| condition.call(klass) }.first \
|
138
|
+
|| Elasticsearch::Model::Adapter::Default
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|