elasticsearch-model 7.0.0.pre → 7.0.0
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.
- checksums.yaml +4 -4
- data/README.md +33 -23
- data/examples/activerecord_associations.rb +16 -0
- data/gemfiles/6.0.gemfile +3 -3
- data/lib/elasticsearch/model.rb +11 -56
- data/lib/elasticsearch/model/importing.rb +33 -12
- data/lib/elasticsearch/model/indexing.rb +40 -35
- data/lib/elasticsearch/model/naming.rb +1 -10
- data/lib/elasticsearch/model/proxy.rb +41 -21
- data/lib/elasticsearch/model/response/records.rb +0 -1
- data/lib/elasticsearch/model/version.rb +1 -1
- data/spec/elasticsearch/model/indexing_spec.rb +3 -3
- data/spec/spec_helper.rb +9 -3
- data/spec/support/app.rb +9 -2
- metadata +5 -7
- data/spec/elasticsearch/model/naming_inheritance_spec.rb +0 -123
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ced6c99b3278104e708dc2db19a73422273f92b9c18d3aa1f0d552e0ba27d97
|
4
|
+
data.tar.gz: 9075efe50a3f7da082933e3e9acc9751901dc4561f92a70c4d3cbea000c581ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8f7d0e726d805048544b8ffce8a81b269be4f17c3696241372f6258a7c9add622998718fb23c35b752cc1a51d64a0b8ef42a293b31718f6ba4ed51cfced7586
|
7
|
+
data.tar.gz: 36e3325b72bfa63f8ea133b44086d579bb8727a6e5d8c71115ab25d424b6058e849a32aa68326f5450c1f0fbe5c75fedead8878893309ffbca29901c773367be
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ the [`elasticsearch`](https://github.com/elastic/elasticsearch-ruby) library.
|
|
5
5
|
|
6
6
|
It aims to simplify integration of Ruby classes ("models"), commonly found
|
7
7
|
e.g. in [Ruby on Rails](http://rubyonrails.org) applications, with the
|
8
|
-
[Elasticsearch](
|
8
|
+
[Elasticsearch](https://www.elastic.co) search and analytics engine.
|
9
9
|
|
10
10
|
## Compatibility
|
11
11
|
|
@@ -19,6 +19,7 @@ is compatible with the Elasticsearch `master` branch, therefore, with the next m
|
|
19
19
|
| 0.1 | → | 1.x |
|
20
20
|
| 2.x | → | 2.x |
|
21
21
|
| 5.x | → | 5.x |
|
22
|
+
| 6.x | → | 6.x |
|
22
23
|
| master | → | master |
|
23
24
|
|
24
25
|
## Installation
|
@@ -151,7 +152,7 @@ for information about the Ruby client API.
|
|
151
152
|
|
152
153
|
### Importing the data
|
153
154
|
|
154
|
-
The first thing you'll want to do is
|
155
|
+
The first thing you'll want to do is import your data into the index:
|
155
156
|
|
156
157
|
```ruby
|
157
158
|
Article.import
|
@@ -322,7 +323,7 @@ Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model
|
|
322
323
|
#### The Elasticsearch DSL
|
323
324
|
|
324
325
|
In most situations, you'll want to pass the search definition
|
325
|
-
in the Elasticsearch [domain-specific language](
|
326
|
+
in the Elasticsearch [domain-specific language](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html) to the client:
|
326
327
|
|
327
328
|
```ruby
|
328
329
|
response = Article.search query: { match: { title: "Fox Dogs" } },
|
@@ -532,7 +533,7 @@ class Indexer
|
|
532
533
|
Logger = Sidekiq.logger.level == Logger::DEBUG ? Sidekiq.logger : nil
|
533
534
|
Client = Elasticsearch::Client.new host: 'localhost:9200', logger: Logger
|
534
535
|
|
535
|
-
def
|
536
|
+
def perform_async(operation, record_id)
|
536
537
|
logger.debug [operation, "ID: #{record_id}"]
|
537
538
|
|
538
539
|
case operation.to_s
|
@@ -732,13 +733,8 @@ module and its submodules for technical information.
|
|
732
733
|
|
733
734
|
The module provides a common `settings` method to customize various features.
|
734
735
|
|
735
|
-
|
736
|
-
|
737
|
-
in Rails:
|
738
|
-
|
739
|
-
```ruby
|
740
|
-
Elasticsearch::Model.settings[:inheritance_enabled] = true
|
741
|
-
```
|
736
|
+
Before version 7.0.0 of the gem, the only supported setting was `:inheritance_enabled`. This setting has been deprecated
|
737
|
+
and removed.
|
742
738
|
|
743
739
|
## Development and Community
|
744
740
|
|
@@ -756,20 +752,34 @@ curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticse
|
|
756
752
|
SERVER=start TEST_CLUSTER_COMMAND=$PWD/tmp/elasticsearch-1.0.0.RC1/bin/elasticsearch bundle exec rake test:all
|
757
753
|
```
|
758
754
|
|
755
|
+
### Single Table Inheritance support
|
756
|
+
|
757
|
+
Versions < 7.0.0 of this gem supported inheritance-- more specifically, `Single Table Inheritance`. With this feature,
|
758
|
+
elasticsearch settings (index mappings, etc) on a parent model could be inherited by a child model leading to different
|
759
|
+
model documents being indexed into the same Elasticsearch index. This feature depended on the ability to set a `type`
|
760
|
+
for a document in Elasticsearch. The Elasticsearch team has deprecated support for `types`, as is described
|
761
|
+
[here.](https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html)
|
762
|
+
This gem will also remove support for types and `Single Table Inheritance` in version 7.0 as it enables an anti-pattern.
|
763
|
+
Please save different model documents in separate indices. If you want to use STI, you can include an artificial
|
764
|
+
`type` field manually in each document and use it in other operations.
|
765
|
+
|
759
766
|
## License
|
760
767
|
|
761
768
|
This software is licensed under the Apache 2 license, quoted below.
|
762
769
|
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
770
|
+
Licensed to Elasticsearch B.V. under one or more contributor
|
771
|
+
license agreements. See the NOTICE file distributed with
|
772
|
+
this work for additional information regarding copyright
|
773
|
+
ownership. Elasticsearch B.V. licenses this file to you under
|
774
|
+
the Apache License, Version 2.0 (the "License"); you may
|
775
|
+
not use this file except in compliance with the License.
|
767
776
|
You may obtain a copy of the License at
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
Unless required by applicable law or agreed to in writing,
|
772
|
-
distributed under the License is distributed on an
|
773
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
774
|
-
See the License for the
|
775
|
-
|
777
|
+
|
778
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
779
|
+
|
780
|
+
Unless required by applicable law or agreed to in writing,
|
781
|
+
software distributed under the License is distributed on an
|
782
|
+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
783
|
+
KIND, either express or implied. See the License for the
|
784
|
+
specific language governing permissions and limitations
|
785
|
+
under the License.
|
@@ -98,6 +98,22 @@ module Searchable
|
|
98
98
|
|
99
99
|
module Indexing
|
100
100
|
|
101
|
+
#Index only the specified fields
|
102
|
+
settings do
|
103
|
+
mappings dynamic: false do
|
104
|
+
indexes :categories, type: :object do
|
105
|
+
indexes :title
|
106
|
+
end
|
107
|
+
indexes :authors, type: :object do
|
108
|
+
indexes :full_name
|
109
|
+
indexes :department
|
110
|
+
end
|
111
|
+
indexes :comments, type: :object do
|
112
|
+
indexes :text
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
101
117
|
# Customize the JSON serialization for Elasticsearch
|
102
118
|
def as_indexed_json(options={})
|
103
119
|
self.as_json(
|
data/gemfiles/6.0.gemfile
CHANGED
@@ -25,10 +25,10 @@ source 'https://rubygems.org'
|
|
25
25
|
|
26
26
|
gemspec path: '../'
|
27
27
|
|
28
|
-
gem 'activemodel', '6.0.0
|
29
|
-
gem 'activerecord', '6.0.0
|
28
|
+
gem 'activemodel', '6.0.0'
|
29
|
+
gem 'activerecord', '6.0.0'
|
30
30
|
gem 'sqlite3' unless defined?(JRUBY_VERSION)
|
31
|
-
gem 'mongoid', '~> 6'
|
31
|
+
#gem 'mongoid', '~> 6'
|
32
32
|
|
33
33
|
group :development, :testing do
|
34
34
|
gem 'rspec'
|
data/lib/elasticsearch/model.rb
CHANGED
@@ -89,9 +89,10 @@ module Elasticsearch
|
|
89
89
|
|
90
90
|
# Adds the `Elasticsearch::Model` functionality to the including class.
|
91
91
|
#
|
92
|
-
# * Creates the `__elasticsearch__` class and instance methods
|
93
|
-
#
|
94
|
-
# *
|
92
|
+
# * Creates the `__elasticsearch__` class and instance method. These methods return a proxy object with
|
93
|
+
# other common methods defined on them.
|
94
|
+
# * The module includes other modules with further functionality.
|
95
|
+
# * Sets up delegation for common methods such as `import` and `search`.
|
95
96
|
#
|
96
97
|
# @example Include the module in the `Article` model definition
|
97
98
|
#
|
@@ -108,50 +109,16 @@ module Elasticsearch
|
|
108
109
|
base.class_eval do
|
109
110
|
include Elasticsearch::Model::Proxy
|
110
111
|
|
111
|
-
|
112
|
-
include Elasticsearch::Model::Client::ClassMethods
|
113
|
-
include Elasticsearch::Model::Naming::ClassMethods
|
114
|
-
include Elasticsearch::Model::Indexing::ClassMethods
|
115
|
-
include Elasticsearch::Model::Searching::ClassMethods
|
116
|
-
end
|
117
|
-
|
118
|
-
Elasticsearch::Model::Proxy::InstanceMethodsProxy.class_eval do
|
119
|
-
include Elasticsearch::Model::Client::InstanceMethods
|
120
|
-
include Elasticsearch::Model::Naming::InstanceMethods
|
121
|
-
include Elasticsearch::Model::Indexing::InstanceMethods
|
122
|
-
include Elasticsearch::Model::Serializing::InstanceMethods
|
123
|
-
end
|
124
|
-
|
125
|
-
Elasticsearch::Model::Proxy::InstanceMethodsProxy.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
126
|
-
def as_indexed_json(options={})
|
127
|
-
target.respond_to?(:as_indexed_json) ? target.__send__(:as_indexed_json, options) : super
|
128
|
-
end
|
129
|
-
CODE
|
130
|
-
|
131
|
-
# Delegate important methods to the `__elasticsearch__` proxy, unless they are defined already
|
132
|
-
#
|
112
|
+
# Delegate common methods to the `__elasticsearch__` ClassMethodsProxy, unless they are defined already
|
133
113
|
class << self
|
134
114
|
METHODS.each do |method|
|
135
|
-
delegate method, to: :__elasticsearch__ unless self.
|
115
|
+
delegate method, to: :__elasticsearch__ unless self.respond_to?(method)
|
136
116
|
end
|
137
117
|
end
|
138
|
-
|
139
|
-
# Mix the importing module into the proxy
|
140
|
-
#
|
141
|
-
self.__elasticsearch__.class_eval do
|
142
|
-
include Elasticsearch::Model::Importing::ClassMethods
|
143
|
-
include Adapter.from_class(base).importing_mixin
|
144
|
-
end
|
145
|
-
|
146
|
-
# Add to the registry if it's a class (and not in intermediate module)
|
147
|
-
Registry.add(base) if base.is_a?(Class)
|
148
118
|
end
|
149
|
-
end
|
150
119
|
|
151
|
-
|
152
|
-
|
153
|
-
def self.settings
|
154
|
-
@settings ||= {}
|
120
|
+
# Add to the model to the registry if it's a class (and not in intermediate module)
|
121
|
+
Registry.add(base) if base.is_a?(Class)
|
155
122
|
end
|
156
123
|
|
157
124
|
module ClassMethods
|
@@ -205,22 +172,10 @@ module Elasticsearch
|
|
205
172
|
Response::Response.new(models, request)
|
206
173
|
end
|
207
174
|
|
208
|
-
#
|
209
|
-
#
|
210
|
-
# @note Inheritance is disabled by default.
|
211
|
-
#
|
212
|
-
def inheritance_enabled
|
213
|
-
@inheritance_enabled ||= false
|
214
|
-
end
|
215
|
-
|
216
|
-
# Enable inheritance of index_name and document_type
|
217
|
-
#
|
218
|
-
# @example Enable inheritance
|
219
|
-
#
|
220
|
-
# Elasticsearch::Model.inheritance_enabled = true
|
175
|
+
# Access the module settings
|
221
176
|
#
|
222
|
-
def
|
223
|
-
@
|
177
|
+
def settings
|
178
|
+
@settings ||= {}
|
224
179
|
end
|
225
180
|
end
|
226
181
|
extend ClassMethods
|
@@ -53,7 +53,29 @@ module Elasticsearch
|
|
53
53
|
#
|
54
54
|
# @yield [Hash] Gives the Hash with the Elasticsearch response to the block
|
55
55
|
#
|
56
|
-
# @return [Fixnum]
|
56
|
+
# @return [Fixnum] default, number of errors encountered during importing
|
57
|
+
# @return [Array<Hash>] if +return+ option is specified to be +"errors"+,
|
58
|
+
# contains only those failed items in the response +items+ key, e.g.:
|
59
|
+
#
|
60
|
+
# [
|
61
|
+
# {
|
62
|
+
# "index" => {
|
63
|
+
# "error" => 'FAILED',
|
64
|
+
# "_index" => "test",
|
65
|
+
# "_type" => "_doc",
|
66
|
+
# "_id" => '1',
|
67
|
+
# "_version" => 1,
|
68
|
+
# "result" => "foo",
|
69
|
+
# "_shards" => {
|
70
|
+
# "total" => 1,
|
71
|
+
# "successful" => 0,
|
72
|
+
# "failed" => 1
|
73
|
+
# },
|
74
|
+
# "status" => 400
|
75
|
+
# }
|
76
|
+
# }
|
77
|
+
# ]
|
78
|
+
#
|
57
79
|
#
|
58
80
|
# @example Import all records into the index
|
59
81
|
#
|
@@ -99,20 +121,19 @@ module Elasticsearch
|
|
99
121
|
#
|
100
122
|
# @example Update the batch before yielding it
|
101
123
|
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
124
|
+
# class Article
|
125
|
+
# # ...
|
126
|
+
# def self.enrich(batch)
|
127
|
+
# batch.each do |item|
|
128
|
+
# item.metadata = MyAPI.get_metadata(item.id)
|
129
|
+
# end
|
130
|
+
# batch
|
131
|
+
# end
|
132
|
+
# end
|
111
133
|
#
|
112
134
|
# Article.import preprocess: :enrich
|
113
135
|
#
|
114
|
-
# @example Return an array of error elements instead of the number of errors,
|
115
|
-
# to try importing these records again
|
136
|
+
# @example Return an array of error elements instead of the number of errors, e.g. to try importing these records again
|
116
137
|
#
|
117
138
|
# Article.import return: 'errors'
|
118
139
|
#
|
@@ -30,7 +30,7 @@ module Elasticsearch
|
|
30
30
|
#
|
31
31
|
module Indexing
|
32
32
|
|
33
|
-
# Wraps the [index settings](
|
33
|
+
# Wraps the [index settings](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html)
|
34
34
|
#
|
35
35
|
class Settings
|
36
36
|
attr_accessor :settings
|
@@ -48,7 +48,7 @@ module Elasticsearch
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
# Wraps the [index mappings](
|
51
|
+
# Wraps the [index mappings](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html)
|
52
52
|
#
|
53
53
|
class Mappings
|
54
54
|
attr_accessor :options, :type
|
@@ -308,7 +308,7 @@ module Elasticsearch
|
|
308
308
|
#
|
309
309
|
# Article.__elasticsearch__.refresh_index! index: 'my-index'
|
310
310
|
#
|
311
|
-
# @see
|
311
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-refresh.html
|
312
312
|
#
|
313
313
|
def refresh_index!(options={})
|
314
314
|
target_index = options.delete(:index) || self.index_name
|
@@ -338,13 +338,17 @@ module Elasticsearch
|
|
338
338
|
#
|
339
339
|
# @see #update_document
|
340
340
|
#
|
341
|
-
base.before_save do |
|
342
|
-
if
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
341
|
+
base.before_save do |obj|
|
342
|
+
if obj.respond_to?(:changes_to_save) # Rails 5.1
|
343
|
+
changes_to_save = obj.changes_to_save
|
344
|
+
elsif obj.respond_to?(:changes)
|
345
|
+
changes_to_save = obj.changes
|
346
|
+
end
|
347
|
+
|
348
|
+
if changes_to_save
|
349
|
+
attrs = obj.instance_variable_get(:@__changed_model_attributes) || {}
|
350
|
+
latest_changes = changes_to_save.inject({}) { |latest_changes, (k,v)| latest_changes.merge!(k => v.last) }
|
351
|
+
obj.instance_variable_set(:@__changed_model_attributes, attrs.merge(latest_changes))
|
348
352
|
end
|
349
353
|
end if base.respond_to?(:before_save)
|
350
354
|
end
|
@@ -364,14 +368,13 @@ module Elasticsearch
|
|
364
368
|
# @see http://rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions:index
|
365
369
|
#
|
366
370
|
def index_document(options={})
|
367
|
-
document =
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
)
|
371
|
+
document = as_indexed_json
|
372
|
+
request = { index: index_name,
|
373
|
+
id: id,
|
374
|
+
body: document }
|
375
|
+
request.merge!(type: document_type) if document_type
|
376
|
+
|
377
|
+
client.index(request.merge!(options))
|
375
378
|
end
|
376
379
|
|
377
380
|
# Deletes the model instance from the index
|
@@ -388,11 +391,11 @@ module Elasticsearch
|
|
388
391
|
# @see http://rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions:delete
|
389
392
|
#
|
390
393
|
def delete_document(options={})
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
)
|
394
|
+
request = { index: index_name,
|
395
|
+
id: self.id }
|
396
|
+
request.merge!(type: document_type) if document_type
|
397
|
+
|
398
|
+
client.delete(request.merge!(options))
|
396
399
|
end
|
397
400
|
|
398
401
|
# Tries to gather the changed attributes of a model instance
|
@@ -427,12 +430,14 @@ module Elasticsearch
|
|
427
430
|
attributes_in_database
|
428
431
|
end
|
429
432
|
|
430
|
-
|
431
|
-
{ index: index_name,
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
433
|
+
unless attributes.empty?
|
434
|
+
request = { index: index_name,
|
435
|
+
id: self.id,
|
436
|
+
body: { doc: attributes } }
|
437
|
+
request.merge!(type: document_type) if document_type
|
438
|
+
|
439
|
+
client.update(request.merge!(options))
|
440
|
+
end
|
436
441
|
else
|
437
442
|
index_document(options)
|
438
443
|
end
|
@@ -453,12 +458,12 @@ module Elasticsearch
|
|
453
458
|
# @return [Hash] The response from Elasticsearch
|
454
459
|
#
|
455
460
|
def update_document_attributes(attributes, options={})
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
)
|
461
|
+
request = { index: index_name,
|
462
|
+
id: self.id,
|
463
|
+
body: { doc: attributes } }
|
464
|
+
request.merge!(type: document_type) if document_type
|
465
|
+
|
466
|
+
client.update(request.merge!(options))
|
462
467
|
end
|
463
468
|
end
|
464
469
|
|
@@ -92,16 +92,7 @@ module Elasticsearch
|
|
92
92
|
private
|
93
93
|
|
94
94
|
def implicit(prop)
|
95
|
-
|
96
|
-
|
97
|
-
if Elasticsearch::Model.settings[:inheritance_enabled]
|
98
|
-
self.ancestors.each do |klass|
|
99
|
-
next if klass == self
|
100
|
-
break if value = klass.respond_to?(prop) && klass.send(prop)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
value || self.send("default_#{prop}")
|
95
|
+
self.send("default_#{prop}")
|
105
96
|
end
|
106
97
|
|
107
98
|
def default_index_name
|
@@ -19,15 +19,15 @@ module Elasticsearch
|
|
19
19
|
module Model
|
20
20
|
|
21
21
|
# This module provides a proxy interfacing between the including class and
|
22
|
-
#
|
22
|
+
# `Elasticsearch::Model`, preventing the pollution of the including class namespace.
|
23
23
|
#
|
24
24
|
# The only "gateway" between the model and Elasticsearch::Model is the
|
25
|
-
#
|
25
|
+
# `#__elasticsearch__` class and instance method.
|
26
26
|
#
|
27
27
|
# The including class must be compatible with
|
28
28
|
# [ActiveModel](https://github.com/rails/rails/tree/master/activemodel).
|
29
29
|
#
|
30
|
-
# @example Include the
|
30
|
+
# @example Include the `Elasticsearch::Model` module into an `Article` model
|
31
31
|
#
|
32
32
|
# class Article < ActiveRecord::Base
|
33
33
|
# include Elasticsearch::Model
|
@@ -53,21 +53,19 @@ module Elasticsearch
|
|
53
53
|
# module and the functionality is accessible via the proxy.
|
54
54
|
#
|
55
55
|
def self.included(base)
|
56
|
+
|
56
57
|
base.class_eval do
|
57
|
-
|
58
|
-
#
|
58
|
+
|
59
|
+
# `ClassMethodsProxy` instance, accessed as `MyModel.__elasticsearch__`
|
59
60
|
def self.__elasticsearch__ &block
|
60
61
|
@__elasticsearch__ ||= ClassMethodsProxy.new(self)
|
61
62
|
@__elasticsearch__.instance_eval(&block) if block_given?
|
62
63
|
@__elasticsearch__
|
63
64
|
end
|
64
65
|
|
65
|
-
#
|
66
|
-
|
67
|
-
|
68
|
-
@__elasticsearch__ ||= InstanceMethodsProxy.new(self)
|
69
|
-
@__elasticsearch__.instance_eval(&block) if block_given?
|
70
|
-
@__elasticsearch__
|
66
|
+
# Mix the importing module into the `ClassMethodsProxy`
|
67
|
+
self.__elasticsearch__.class_eval do
|
68
|
+
include Adapter.from_class(base).importing_mixin
|
71
69
|
end
|
72
70
|
|
73
71
|
# Register a callback for storing changed attributes for models which implement
|
@@ -75,18 +73,28 @@ module Elasticsearch
|
|
75
73
|
#
|
76
74
|
# @see http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
|
77
75
|
#
|
78
|
-
before_save do |
|
79
|
-
if
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
76
|
+
before_save do |obj|
|
77
|
+
if obj.respond_to?(:changes_to_save) # Rails 5.1
|
78
|
+
changes_to_save = obj.changes_to_save
|
79
|
+
elsif obj.respond_to?(:changes)
|
80
|
+
changes_to_save = obj.changes
|
81
|
+
end
|
82
|
+
|
83
|
+
if changes_to_save
|
84
|
+
attrs = obj.__elasticsearch__.instance_variable_get(:@__changed_model_attributes) || {}
|
85
|
+
latest_changes = changes_to_save.inject({}) { |latest_changes, (k,v)| latest_changes.merge!(k => v.last) }
|
86
|
+
obj.__elasticsearch__.instance_variable_set(:@__changed_model_attributes, attrs.merge(latest_changes))
|
87
87
|
end
|
88
88
|
end if respond_to?(:before_save)
|
89
89
|
end
|
90
|
+
|
91
|
+
# {InstanceMethodsProxy}, accessed as `@mymodel.__elasticsearch__`
|
92
|
+
#
|
93
|
+
def __elasticsearch__ &block
|
94
|
+
@__elasticsearch__ ||= InstanceMethodsProxy.new(self)
|
95
|
+
@__elasticsearch__.instance_eval(&block) if block_given?
|
96
|
+
@__elasticsearch__
|
97
|
+
end
|
90
98
|
end
|
91
99
|
|
92
100
|
# @overload dup
|
@@ -130,6 +138,11 @@ module Elasticsearch
|
|
130
138
|
#
|
131
139
|
class ClassMethodsProxy
|
132
140
|
include Base
|
141
|
+
include Elasticsearch::Model::Client::ClassMethods
|
142
|
+
include Elasticsearch::Model::Naming::ClassMethods
|
143
|
+
include Elasticsearch::Model::Indexing::ClassMethods
|
144
|
+
include Elasticsearch::Model::Searching::ClassMethods
|
145
|
+
include Elasticsearch::Model::Importing::ClassMethods
|
133
146
|
end
|
134
147
|
|
135
148
|
# A proxy interfacing between Elasticsearch::Model instance methods and model instance methods
|
@@ -138,6 +151,10 @@ module Elasticsearch
|
|
138
151
|
#
|
139
152
|
class InstanceMethodsProxy
|
140
153
|
include Base
|
154
|
+
include Elasticsearch::Model::Client::InstanceMethods
|
155
|
+
include Elasticsearch::Model::Naming::InstanceMethods
|
156
|
+
include Elasticsearch::Model::Indexing::InstanceMethods
|
157
|
+
include Elasticsearch::Model::Serializing::InstanceMethods
|
141
158
|
|
142
159
|
def klass
|
143
160
|
target.class
|
@@ -153,8 +170,11 @@ module Elasticsearch
|
|
153
170
|
def as_json(options={})
|
154
171
|
target.as_json(options)
|
155
172
|
end
|
156
|
-
end
|
157
173
|
|
174
|
+
def as_indexed_json(options={})
|
175
|
+
target.respond_to?(:as_indexed_json) ? target.__send__(:as_indexed_json, options) : super
|
176
|
+
end
|
177
|
+
end
|
158
178
|
end
|
159
179
|
end
|
160
180
|
end
|
@@ -418,7 +418,7 @@ describe Elasticsearch::Model::Indexing do
|
|
418
418
|
expect(instance).to receive(:client).and_return(client)
|
419
419
|
expect(instance).to receive(:as_indexed_json).and_return('JSON')
|
420
420
|
expect(instance).to receive(:index_name).and_return('foo')
|
421
|
-
expect(instance).to receive(:document_type).and_return('bar')
|
421
|
+
expect(instance).to receive(:document_type).twice.and_return('bar')
|
422
422
|
expect(instance).to receive(:id).and_return('1')
|
423
423
|
end
|
424
424
|
|
@@ -458,7 +458,7 @@ describe Elasticsearch::Model::Indexing do
|
|
458
458
|
before do
|
459
459
|
expect(instance).to receive(:client).and_return(client)
|
460
460
|
expect(instance).to receive(:index_name).and_return('foo')
|
461
|
-
expect(instance).to receive(:document_type).and_return('bar')
|
461
|
+
expect(instance).to receive(:document_type).twice.and_return('bar')
|
462
462
|
expect(instance).to receive(:id).and_return('1')
|
463
463
|
end
|
464
464
|
|
@@ -602,7 +602,7 @@ describe Elasticsearch::Model::Indexing do
|
|
602
602
|
before do
|
603
603
|
expect(instance).to receive(:client).and_return(client)
|
604
604
|
expect(instance).to receive(:index_name).and_return('foo')
|
605
|
-
expect(instance).to receive(:document_type).and_return('bar')
|
605
|
+
expect(instance).to receive(:document_type).twice.and_return('bar')
|
606
606
|
expect(instance).to receive(:id).and_return('1')
|
607
607
|
instance.instance_variable_set(:@__changed_model_attributes, { author: 'john' })
|
608
608
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -23,7 +23,11 @@ require 'will_paginate/collection'
|
|
23
23
|
require 'elasticsearch/model'
|
24
24
|
require 'hashie/version'
|
25
25
|
require 'active_model'
|
26
|
-
|
26
|
+
begin
|
27
|
+
require 'mongoid'
|
28
|
+
rescue LoadError
|
29
|
+
$stderr.puts("'mongoid' gem could not be loaded")
|
30
|
+
end
|
27
31
|
require 'yaml'
|
28
32
|
require 'active_record'
|
29
33
|
|
@@ -151,8 +155,10 @@ def test_mongoid?
|
|
151
155
|
client.database.command(ping: 1) && true
|
152
156
|
end
|
153
157
|
end and true
|
154
|
-
rescue
|
155
|
-
|
158
|
+
rescue LoadError
|
159
|
+
$stderr.puts("'mongoid' gem could not be loaded")
|
160
|
+
rescue Timeout::Error, Mongo::Error => e
|
161
|
+
client.close if client
|
156
162
|
$stderr.puts("MongoDB not installed or running: #{e}")
|
157
163
|
end
|
158
164
|
end
|
data/spec/support/app.rb
CHANGED
@@ -26,9 +26,7 @@ require 'support/app/namespaced_book'
|
|
26
26
|
require 'support/app/article_for_pagination'
|
27
27
|
require 'support/app/article_with_dynamic_index_name'
|
28
28
|
require 'support/app/episode'
|
29
|
-
require 'support/app/image'
|
30
29
|
require 'support/app/series'
|
31
|
-
require 'support/app/mongoid_article'
|
32
30
|
require 'support/app/article'
|
33
31
|
require 'support/app/article_no_type'
|
34
32
|
require 'support/app/searchable'
|
@@ -37,3 +35,12 @@ require 'support/app/author'
|
|
37
35
|
require 'support/app/authorship'
|
38
36
|
require 'support/app/comment'
|
39
37
|
require 'support/app/post'
|
38
|
+
|
39
|
+
|
40
|
+
# Mongoid models
|
41
|
+
begin
|
42
|
+
require 'support/app/image'
|
43
|
+
require 'support/app/mongoid_article'
|
44
|
+
rescue
|
45
|
+
$stderr.puts("'mongoid' gem is not installed, could not load Mongoid models")
|
46
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticsearch-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.0
|
4
|
+
version: 7.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karel Minarik
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: elasticsearch
|
@@ -399,7 +399,6 @@ files:
|
|
399
399
|
- spec/elasticsearch/model/indexing_spec.rb
|
400
400
|
- spec/elasticsearch/model/module_spec.rb
|
401
401
|
- spec/elasticsearch/model/multimodel_spec.rb
|
402
|
-
- spec/elasticsearch/model/naming_inheritance_spec.rb
|
403
402
|
- spec/elasticsearch/model/naming_spec.rb
|
404
403
|
- spec/elasticsearch/model/proxy_spec.rb
|
405
404
|
- spec/elasticsearch/model/response/aggregations_spec.rb
|
@@ -453,11 +452,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
453
452
|
version: 1.9.3
|
454
453
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
455
454
|
requirements:
|
456
|
-
- - "
|
455
|
+
- - ">="
|
457
456
|
- !ruby/object:Gem::Version
|
458
|
-
version:
|
457
|
+
version: '0'
|
459
458
|
requirements: []
|
460
|
-
rubygems_version: 3.0.
|
459
|
+
rubygems_version: 3.0.6
|
461
460
|
signing_key:
|
462
461
|
specification_version: 4
|
463
462
|
summary: ActiveModel/Record integrations for Elasticsearch.
|
@@ -485,7 +484,6 @@ test_files:
|
|
485
484
|
- spec/elasticsearch/model/indexing_spec.rb
|
486
485
|
- spec/elasticsearch/model/module_spec.rb
|
487
486
|
- spec/elasticsearch/model/multimodel_spec.rb
|
488
|
-
- spec/elasticsearch/model/naming_inheritance_spec.rb
|
489
487
|
- spec/elasticsearch/model/naming_spec.rb
|
490
488
|
- spec/elasticsearch/model/proxy_spec.rb
|
491
489
|
- spec/elasticsearch/model/response/aggregations_spec.rb
|
@@ -1,123 +0,0 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V. under one or more contributor
|
2
|
-
# license agreements. See the NOTICE file distributed with
|
3
|
-
# this work for additional information regarding copyright
|
4
|
-
# ownership. Elasticsearch B.V. licenses this file to you under
|
5
|
-
# the Apache License, Version 2.0 (the "License"); you may
|
6
|
-
# not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing,
|
12
|
-
# software distributed under the License is distributed on an
|
13
|
-
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
-
# KIND, either express or implied. See the License for the
|
15
|
-
# specific language governing permissions and limitations
|
16
|
-
# under the License.
|
17
|
-
|
18
|
-
require 'spec_helper'
|
19
|
-
|
20
|
-
describe 'naming inheritance' do
|
21
|
-
|
22
|
-
before(:all) do
|
23
|
-
class ::TestBase
|
24
|
-
extend ActiveModel::Naming
|
25
|
-
|
26
|
-
extend Elasticsearch::Model::Naming::ClassMethods
|
27
|
-
include Elasticsearch::Model::Naming::InstanceMethods
|
28
|
-
end
|
29
|
-
|
30
|
-
class ::Animal < ::TestBase
|
31
|
-
extend ActiveModel::Naming
|
32
|
-
|
33
|
-
extend Elasticsearch::Model::Naming::ClassMethods
|
34
|
-
include Elasticsearch::Model::Naming::InstanceMethods
|
35
|
-
|
36
|
-
index_name "mammals"
|
37
|
-
document_type "mammal"
|
38
|
-
end
|
39
|
-
|
40
|
-
class ::Dog < ::Animal
|
41
|
-
end
|
42
|
-
|
43
|
-
module ::MyNamespace
|
44
|
-
class Dog < ::Animal
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
class ::Cat < ::Animal
|
49
|
-
extend ActiveModel::Naming
|
50
|
-
|
51
|
-
extend Elasticsearch::Model::Naming::ClassMethods
|
52
|
-
include Elasticsearch::Model::Naming::InstanceMethods
|
53
|
-
|
54
|
-
index_name "cats"
|
55
|
-
document_type "cat"
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
after(:all) do
|
61
|
-
remove_classes(TestBase, Animal, MyNamespace, Cat)
|
62
|
-
end
|
63
|
-
|
64
|
-
around(:all) do |example|
|
65
|
-
original_value = Elasticsearch::Model.settings[:inheritance_enabled]
|
66
|
-
Elasticsearch::Model.settings[:inheritance_enabled] = true
|
67
|
-
example.run
|
68
|
-
Elasticsearch::Model.settings[:inheritance_enabled] = original_value
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
describe '#index_name' do
|
73
|
-
|
74
|
-
it 'returns the default index name' do
|
75
|
-
expect(TestBase.index_name).to eq('test_bases')
|
76
|
-
expect(TestBase.new.index_name).to eq('test_bases')
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'returns the explicit index name' do
|
80
|
-
expect(Animal.index_name).to eq('mammals')
|
81
|
-
expect(Animal.new.index_name).to eq('mammals')
|
82
|
-
|
83
|
-
expect(Cat.index_name).to eq('cats')
|
84
|
-
expect(Cat.new.index_name).to eq('cats')
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'returns the ancestor index name' do
|
88
|
-
expect(Dog.index_name).to eq('mammals')
|
89
|
-
expect(Dog.new.index_name).to eq('mammals')
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'returns the ancestor index name for namespaced models' do
|
93
|
-
expect(::MyNamespace::Dog.index_name).to eq('mammals')
|
94
|
-
expect(::MyNamespace::Dog.new.index_name).to eq('mammals')
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
describe '#document_type' do
|
99
|
-
|
100
|
-
it 'returns nil' do
|
101
|
-
expect(TestBase.document_type).to be_nil
|
102
|
-
expect(TestBase.new.document_type).to be_nil
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'returns the explicit document type' do
|
106
|
-
expect(Animal.document_type).to eq('mammal')
|
107
|
-
expect(Animal.new.document_type).to eq('mammal')
|
108
|
-
|
109
|
-
expect(Cat.document_type).to eq('cat')
|
110
|
-
expect(Cat.new.document_type).to eq('cat')
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'returns the ancestor document type' do
|
114
|
-
expect(Dog.document_type).to eq('mammal')
|
115
|
-
expect(Dog.new.document_type).to eq('mammal')
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'returns the ancestor document type for namespaced models' do
|
119
|
-
expect(::MyNamespace::Dog.document_type).to eq('mammal')
|
120
|
-
expect(::MyNamespace::Dog.new.document_type).to eq('mammal')
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|