elasticsearch-model 0.0.1 → 0.1.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|