elasticsearch-persistence 5.1.0 → 6.0.0.pre

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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/Gemfile +9 -0
  4. data/README.md +164 -323
  5. data/Rakefile +8 -8
  6. data/elasticsearch-persistence.gemspec +4 -5
  7. data/lib/elasticsearch/persistence.rb +2 -110
  8. data/lib/elasticsearch/persistence/repository.rb +212 -53
  9. data/lib/elasticsearch/persistence/repository/dsl.rb +94 -0
  10. data/lib/elasticsearch/persistence/repository/find.rb +27 -10
  11. data/lib/elasticsearch/persistence/repository/response/results.rb +17 -5
  12. data/lib/elasticsearch/persistence/repository/search.rb +15 -4
  13. data/lib/elasticsearch/persistence/repository/serialize.rb +65 -7
  14. data/lib/elasticsearch/persistence/repository/store.rb +38 -44
  15. data/lib/elasticsearch/persistence/version.rb +1 -1
  16. data/spec/repository/find_spec.rb +179 -0
  17. data/spec/repository/response/results_spec.rb +105 -0
  18. data/spec/repository/search_spec.rb +181 -0
  19. data/spec/repository/serialize_spec.rb +53 -0
  20. data/spec/repository/store_spec.rb +327 -0
  21. data/spec/repository_spec.rb +716 -0
  22. data/spec/spec_helper.rb +28 -0
  23. metadata +25 -80
  24. data/lib/elasticsearch/persistence/client.rb +0 -51
  25. data/lib/elasticsearch/persistence/model.rb +0 -153
  26. data/lib/elasticsearch/persistence/model/base.rb +0 -87
  27. data/lib/elasticsearch/persistence/model/errors.rb +0 -8
  28. data/lib/elasticsearch/persistence/model/find.rb +0 -180
  29. data/lib/elasticsearch/persistence/model/rails.rb +0 -47
  30. data/lib/elasticsearch/persistence/model/store.rb +0 -254
  31. data/lib/elasticsearch/persistence/model/utils.rb +0 -0
  32. data/lib/elasticsearch/persistence/repository/class.rb +0 -71
  33. data/lib/elasticsearch/persistence/repository/naming.rb +0 -115
  34. data/lib/rails/generators/elasticsearch/model/model_generator.rb +0 -21
  35. data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +0 -9
  36. data/lib/rails/generators/elasticsearch_generator.rb +0 -2
  37. data/test/integration/model/model_basic_test.rb +0 -238
  38. data/test/integration/repository/custom_class_test.rb +0 -85
  39. data/test/integration/repository/customized_class_test.rb +0 -82
  40. data/test/integration/repository/default_class_test.rb +0 -116
  41. data/test/integration/repository/virtus_model_test.rb +0 -118
  42. data/test/test_helper.rb +0 -55
  43. data/test/unit/model_base_test.rb +0 -72
  44. data/test/unit/model_find_test.rb +0 -153
  45. data/test/unit/model_gateway_test.rb +0 -101
  46. data/test/unit/model_rails_test.rb +0 -112
  47. data/test/unit/model_store_test.rb +0 -576
  48. data/test/unit/persistence_test.rb +0 -32
  49. data/test/unit/repository_class_test.rb +0 -51
  50. data/test/unit/repository_client_test.rb +0 -32
  51. data/test/unit/repository_find_test.rb +0 -388
  52. data/test/unit/repository_indexing_test.rb +0 -37
  53. data/test/unit/repository_module_test.rb +0 -146
  54. data/test/unit/repository_naming_test.rb +0 -146
  55. data/test/unit/repository_response_results_test.rb +0 -98
  56. data/test/unit/repository_search_test.rb +0 -117
  57. data/test/unit/repository_serialize_test.rb +0 -57
  58. data/test/unit/repository_store_test.rb +0 -303
@@ -1,71 +0,0 @@
1
- module Elasticsearch
2
- module Persistence
3
- module Repository
4
-
5
- # The default repository class, to be used either directly, or as a gateway in a custom repository class
6
- #
7
- # @example Standalone use
8
- #
9
- # repository = Elasticsearch::Persistence::Repository::Class.new
10
- # # => #<Elasticsearch::Persistence::Repository::Class ...>
11
- # repository.save(my_object)
12
- # # => {"_index"=> ... }
13
- #
14
- # @example Shortcut use
15
- #
16
- # repository = Elasticsearch::Persistence::Repository.new
17
- # # => #<Elasticsearch::Persistence::Repository::Class ...>
18
- #
19
- # @example Configuration via a block
20
- #
21
- # repository = Elasticsearch::Persistence::Repository.new do
22
- # index 'my_notes'
23
- # end
24
- #
25
- # # => #<Elasticsearch::Persistence::Repository::Class ...>
26
- # # > repository.save(my_object)
27
- # # => {"_index"=> ... }
28
- #
29
- # @example Accessing the gateway in a custom class
30
- #
31
- # class MyRepository
32
- # include Elasticsearch::Persistence::Repository
33
- # end
34
- #
35
- # repository = MyRepository.new
36
- #
37
- # repository.gateway.client.info
38
- # # => {"status"=>200, "name"=>"Venom", ... }
39
- #
40
- class Class
41
- include Elasticsearch::Persistence::Repository::Client
42
- include Elasticsearch::Persistence::Repository::Naming
43
- include Elasticsearch::Persistence::Repository::Serialize
44
- include Elasticsearch::Persistence::Repository::Store
45
- include Elasticsearch::Persistence::Repository::Find
46
- include Elasticsearch::Persistence::Repository::Search
47
-
48
- include Elasticsearch::Model::Indexing::ClassMethods
49
-
50
- attr_reader :options
51
-
52
- def initialize(options={}, &block)
53
- @options = options
54
- index_name options.delete(:index)
55
- block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
56
- end
57
-
58
- # Return the "host" class, if this repository is a gateway hosted in another class
59
- #
60
- # @return [nil, Class]
61
- #
62
- # @api private
63
- #
64
- def host
65
- options[:host]
66
- end
67
- end
68
-
69
- end
70
- end
71
- end
@@ -1,115 +0,0 @@
1
- module Elasticsearch
2
- module Persistence
3
- module Repository
4
-
5
- # Wraps all naming-related features of the repository (index name, the domain object class, etc)
6
- #
7
- module Naming
8
-
9
- # Get or set the class used to initialize domain objects when deserializing them
10
- #
11
- def klass name=nil
12
- @klass = name || @klass
13
- end
14
-
15
- # Set the class used to initialize domain objects when deserializing them
16
- #
17
- def klass=klass
18
- @klass = klass
19
- end
20
-
21
- # Get or set the index name used when storing and retrieving documents
22
- #
23
- def index_name name=nil
24
- @index_name = name || @index_name || begin
25
- if respond_to?(:host) && host && host.is_a?(Module)
26
- self.host.to_s.underscore.gsub(/\//, '-')
27
- else
28
- self.class.to_s.underscore.gsub(/\//, '-')
29
- end
30
- end
31
- end; alias :index :index_name
32
-
33
- # Set the index name used when storing and retrieving documents
34
- #
35
- def index_name=(name)
36
- @index_name = name
37
- end; alias :index= :index_name=
38
-
39
- # Get or set the document type used when storing and retrieving documents
40
- #
41
- def document_type name=nil
42
- @document_type = name || @document_type || (klass ? klass.to_s.underscore : nil)
43
- end; alias :type :document_type
44
-
45
- # Set the document type used when storing and retrieving documents
46
- #
47
- def document_type=(name)
48
- @document_type = name
49
- end; alias :type= :document_type=
50
-
51
- # Get the Ruby class from the Elasticsearch `_type`
52
- #
53
- # @example
54
- # repository.__get_klass_from_type 'note'
55
- # => Note
56
- #
57
- # @return [Class] The class corresponding to the passed type
58
- # @raise [NameError] if the class cannot be found
59
- #
60
- # @api private
61
- #
62
- def __get_klass_from_type(type)
63
- klass = type.classify
64
- klass.constantize
65
- rescue NameError => e
66
- raise NameError, "Attempted to get class '#{klass}' from the '#{type}' type, but no such class can be found."
67
- end
68
-
69
- # Get the Elasticsearch `_type` from the Ruby class
70
- #
71
- # @example
72
- # repository.__get_type_from_class Note
73
- # => "note"
74
- #
75
- # @return [String] The type corresponding to the passed class
76
- #
77
- # @api private
78
- #
79
- def __get_type_from_class(klass)
80
- klass.to_s.underscore
81
- end
82
-
83
- # Get a document ID from the document (assuming Hash or Hash-like object)
84
- #
85
- # @example
86
- # repository.__get_id_from_document title: 'Test', id: 'abc123'
87
- # => "abc123"
88
- #
89
- # @api private
90
- #
91
- def __get_id_from_document(document)
92
- document[:id] || document['id'] || document[:_id] || document['_id']
93
- end
94
-
95
- # Extract a document ID from the document (assuming Hash or Hash-like object)
96
- #
97
- # @note Calling this method will *remove* the `id` or `_id` key from the passed object.
98
- #
99
- # @example
100
- # options = { title: 'Test', id: 'abc123' }
101
- # repository.__extract_id_from_document options
102
- # # => "abc123"
103
- # options
104
- # # => { title: 'Test' }
105
- #
106
- # @api private
107
- #
108
- def __extract_id_from_document(document)
109
- document.delete(:id) || document.delete('id') || document.delete(:_id) || document.delete('_id')
110
- end
111
- end
112
-
113
- end
114
- end
115
- end
@@ -1,21 +0,0 @@
1
- require "rails/generators/elasticsearch_generator"
2
-
3
- module Elasticsearch
4
- module Generators
5
- class ModelGenerator < ::Rails::Generators::NamedBase
6
- source_root File.expand_path('../templates', __FILE__)
7
-
8
- desc "Creates an Elasticsearch::Persistence model"
9
- argument :attributes, type: :array, default: [], banner: "attribute:type attribute:type"
10
-
11
- check_class_collision
12
-
13
- def create_model_file
14
- @padding = attributes.map { |a| a.name.size }.max
15
- template "model.rb.tt", File.join("app/models", class_path, "#{file_name}.rb")
16
- end
17
-
18
- hook_for :test_framework
19
- end
20
- end
21
- end
@@ -1,9 +0,0 @@
1
- <% module_namespacing do -%>
2
- class <%= class_name %>
3
- include Elasticsearch::Persistence::Model
4
-
5
- <% attributes.each do |attribute| -%>
6
- <%= "attribute :#{attribute.name},".ljust(@padding+12) %> <%= attribute.type %>
7
- <% end -%>
8
- end
9
- <% end -%>
@@ -1,2 +0,0 @@
1
- require "rails/generators/named_base"
2
- require "rails/generators/active_model"
@@ -1,238 +0,0 @@
1
- require 'test_helper'
2
-
3
- require 'elasticsearch/persistence/model'
4
- require 'elasticsearch/persistence/model/rails'
5
-
6
- module Elasticsearch
7
- module Persistence
8
- class PersistenceModelBasicIntegrationTest < Elasticsearch::Test::IntegrationTestCase
9
-
10
- class ::Person
11
- include Elasticsearch::Persistence::Model
12
- include Elasticsearch::Persistence::Model::Rails
13
-
14
- settings index: { number_of_shards: 1 }
15
- document_type 'human_being'
16
-
17
- attribute :name, String,
18
- mapping: { fields: {
19
- name: { type: 'text', analyzer: 'snowball' },
20
- raw: { type: 'keyword' }
21
- } }
22
-
23
- attribute :birthday, Date
24
- attribute :department, String
25
- attribute :salary, Integer
26
- attribute :admin, Boolean, default: false
27
-
28
- validates :name, presence: true
29
- end
30
-
31
- context "A basic persistence model" do
32
- setup do
33
- Person.create_index! force: true
34
- end
35
-
36
- should "warn that the ActiveRecord persistence pattern is deprecated" do
37
- Kernel.expects(:warn).at_least_once
38
- class ShouldWarn; include Elasticsearch::Persistence::Model; end
39
- end
40
-
41
- should "save the object with custom ID" do
42
- person = Person.new id: 1, name: 'Number One'
43
- person.save
44
-
45
- document = Person.find(1)
46
- assert_not_nil document
47
- assert_equal 'Number One', document.name
48
- end
49
-
50
- should "create the object with custom ID" do
51
- person = Person.create id: 1, name: 'Number One'
52
-
53
- document = Person.find(1)
54
- assert_not_nil document
55
- assert_equal 'Number One', document.name
56
- end
57
-
58
- should "save and find the object" do
59
- person = Person.new name: 'John Smith', birthday: Date.parse('1970-01-01')
60
- assert person.save
61
-
62
- assert_not_nil person.id
63
- document = Person.find(person.id)
64
-
65
- assert_instance_of Person, document
66
- assert_equal 'John Smith', document.name
67
- assert_equal 'John Smith', Person.find(person.id).name
68
-
69
- assert_not_nil Elasticsearch::Persistence.client.get index: 'people', type: 'human_being', id: person.id
70
- end
71
-
72
- should "not save an invalid object" do
73
- person = Person.new name: nil
74
- assert ! person.save
75
- end
76
-
77
- should "save an invalid object with the :validate option" do
78
- person = Person.new name: nil, salary: 100
79
- assert person.save validate: false
80
-
81
- assert_not_nil person.id
82
- document = Person.find(person.id)
83
- assert_equal 100, document.salary
84
- end
85
-
86
- should "delete the object" do
87
- person = Person.create name: 'John Smith', birthday: Date.parse('1970-01-01')
88
-
89
- person.destroy
90
- assert person.frozen?
91
-
92
- assert_raise Elasticsearch::Transport::Transport::Errors::NotFound do
93
- Elasticsearch::Persistence.client.get index: 'people', type: 'person', id: person.id
94
- end
95
- end
96
-
97
- should "update an object attribute" do
98
- person = Person.create name: 'John Smith'
99
-
100
- person.update name: 'UPDATED'
101
-
102
- assert_equal 'UPDATED', person.name
103
- assert_equal 'UPDATED', Person.find(person.id).name
104
- end
105
-
106
- should "create the model with correct Date form Rails' form attributes" do
107
- params = { "birthday(1i)"=>"2014",
108
- "birthday(2i)"=>"1",
109
- "birthday(3i)"=>"1"
110
- }
111
- person = Person.create params.merge(name: 'TEST')
112
-
113
- assert_equal Date.parse('2014-01-01'), person.birthday
114
- assert_equal Date.parse('2014-01-01'), Person.find(person.id).birthday
115
- end
116
-
117
- should_eventually "update the model with correct Date form Rails' form attributes" do
118
- params = { "birthday(1i)"=>"2014",
119
- "birthday(2i)"=>"1",
120
- "birthday(3i)"=>"1"
121
- }
122
- person = Person.create params.merge(name: 'TEST')
123
-
124
- person.update params.merge('birthday(1i)' => '2015')
125
-
126
- assert_equal Date.parse('2015-01-01'), person.birthday
127
- assert_equal Date.parse('2015-01-01'), Person.find(person.id).birthday
128
- end
129
-
130
- should "increment an object attribute" do
131
- person = Person.create name: 'John Smith', salary: 1_000
132
-
133
- person.increment :salary
134
-
135
- assert_equal 1_001, person.salary
136
- assert_equal 1_001, Person.find(person.id).salary
137
- end
138
-
139
- should "update the object timestamp" do
140
- person = Person.create name: 'John Smith'
141
- updated_at = person.updated_at
142
-
143
- sleep 1
144
- person.touch
145
-
146
- assert person.updated_at > updated_at, [person.updated_at, updated_at].inspect
147
-
148
- found = Person.find(person.id)
149
- assert found.updated_at > updated_at, [found.updated_at, updated_at].inspect
150
- end
151
-
152
- should 'update the object timestamp on save' do
153
- person = Person.create name: 'John Smith'
154
- person.admin = true
155
- sleep 1
156
- person.save
157
-
158
- Person.gateway.refresh_index!
159
-
160
- found = Person.find(person.id)
161
-
162
- # Compare without milliseconds
163
- assert_equal person.updated_at.to_i, found.updated_at.to_i
164
- end
165
-
166
- should "respect the version" do
167
- person = Person.create name: 'John Smith'
168
-
169
- person.update( { name: 'UPDATE 1' })
170
-
171
- assert_raise Elasticsearch::Transport::Transport::Errors::Conflict do
172
- person.update( { name: 'UPDATE 2' }, { version: 1 } )
173
- end
174
- end
175
-
176
- should "find all instances" do
177
- Person.create name: 'John Smith'
178
- Person.create name: 'Mary Smith'
179
- Person.gateway.refresh_index!
180
-
181
- people = Person.all
182
-
183
- assert_equal 2, people.total
184
- assert_equal 2, people.size
185
- end
186
-
187
- should "find instances by search" do
188
- Person.create name: 'John Smith'
189
- Person.create name: 'Mary Smith'
190
- Person.gateway.refresh_index!
191
-
192
- people = Person.search query: { match: { name: 'smith' } },
193
- highlight: { fields: { name: {} } }
194
-
195
- assert_equal 2, people.total
196
- assert_equal 2, people.size
197
-
198
- assert people.map_with_hit { |o,h| h._score }.all? { |s| s > 0 }
199
-
200
- assert_not_nil people.first.hit
201
- assert_match /smith/i, people.first.hit.highlight['name'].first
202
- end
203
-
204
- should "find instances in batches" do
205
- 50.times { |i| Person.create name: "John #{i+1}" }
206
- Person.gateway.refresh_index!
207
-
208
- @batches = 0
209
- @results = []
210
-
211
- Person.find_in_batches(_source_include: 'name') do |batch|
212
- @batches += 1
213
- @results += batch.map(&:name)
214
- end
215
-
216
- assert_equal 3, @batches
217
- assert_equal 50, @results.size
218
- assert_contains @results, 'John 1'
219
- end
220
-
221
- should "find each instance" do
222
- 50.times { |i| Person.create name: "John #{i+1}" }
223
- Person.gateway.refresh_index!
224
-
225
- @results = []
226
-
227
- Person.find_each(_source_include: 'name') do |person|
228
- @results << person.name
229
- end
230
-
231
- assert_equal 50, @results.size
232
- assert_contains @results, 'John 1'
233
- end
234
- end
235
-
236
- end
237
- end
238
- end