elasticsearch-persistence 5.0.2 → 6.1.1

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 (81) hide show
  1. checksums.yaml +5 -5
  2. data/.rspec +2 -0
  3. data/Gemfile +9 -0
  4. data/README.md +206 -338
  5. data/Rakefile +15 -12
  6. data/elasticsearch-persistence.gemspec +6 -7
  7. data/examples/notes/application.rb +3 -4
  8. data/lib/elasticsearch/persistence.rb +2 -110
  9. data/lib/elasticsearch/persistence/repository.rb +212 -53
  10. data/lib/elasticsearch/persistence/repository/dsl.rb +94 -0
  11. data/lib/elasticsearch/persistence/repository/find.rb +27 -10
  12. data/lib/elasticsearch/persistence/repository/response/results.rb +21 -8
  13. data/lib/elasticsearch/persistence/repository/search.rb +30 -18
  14. data/lib/elasticsearch/persistence/repository/serialize.rb +65 -7
  15. data/lib/elasticsearch/persistence/repository/store.rb +38 -44
  16. data/lib/elasticsearch/persistence/version.rb +1 -1
  17. data/spec/repository/find_spec.rb +179 -0
  18. data/spec/repository/response/results_spec.rb +128 -0
  19. data/spec/repository/search_spec.rb +181 -0
  20. data/spec/repository/serialize_spec.rb +53 -0
  21. data/spec/repository/store_spec.rb +327 -0
  22. data/spec/repository_spec.rb +723 -0
  23. data/spec/spec_helper.rb +32 -0
  24. metadata +26 -104
  25. data/examples/music/album.rb +0 -54
  26. data/examples/music/artist.rb +0 -70
  27. data/examples/music/artists/_form.html.erb +0 -8
  28. data/examples/music/artists/artists_controller.rb +0 -67
  29. data/examples/music/artists/artists_controller_test.rb +0 -53
  30. data/examples/music/artists/index.html.erb +0 -60
  31. data/examples/music/artists/show.html.erb +0 -54
  32. data/examples/music/assets/application.css +0 -257
  33. data/examples/music/assets/autocomplete.css +0 -48
  34. data/examples/music/assets/blank_artist.png +0 -0
  35. data/examples/music/assets/blank_cover.png +0 -0
  36. data/examples/music/assets/form.css +0 -113
  37. data/examples/music/index_manager.rb +0 -73
  38. data/examples/music/search/index.html.erb +0 -95
  39. data/examples/music/search/search_controller.rb +0 -41
  40. data/examples/music/search/search_controller_test.rb +0 -12
  41. data/examples/music/search/search_helper.rb +0 -15
  42. data/examples/music/suggester.rb +0 -69
  43. data/examples/music/template.rb +0 -430
  44. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.css +0 -7
  45. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.js +0 -6
  46. data/examples/music/vendor/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  47. data/lib/elasticsearch/persistence/client.rb +0 -51
  48. data/lib/elasticsearch/persistence/model.rb +0 -135
  49. data/lib/elasticsearch/persistence/model/base.rb +0 -87
  50. data/lib/elasticsearch/persistence/model/errors.rb +0 -8
  51. data/lib/elasticsearch/persistence/model/find.rb +0 -180
  52. data/lib/elasticsearch/persistence/model/rails.rb +0 -47
  53. data/lib/elasticsearch/persistence/model/store.rb +0 -254
  54. data/lib/elasticsearch/persistence/model/utils.rb +0 -0
  55. data/lib/elasticsearch/persistence/repository/class.rb +0 -71
  56. data/lib/elasticsearch/persistence/repository/naming.rb +0 -115
  57. data/lib/rails/generators/elasticsearch/model/model_generator.rb +0 -21
  58. data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +0 -9
  59. data/lib/rails/generators/elasticsearch_generator.rb +0 -2
  60. data/test/integration/model/model_basic_test.rb +0 -233
  61. data/test/integration/repository/custom_class_test.rb +0 -85
  62. data/test/integration/repository/customized_class_test.rb +0 -82
  63. data/test/integration/repository/default_class_test.rb +0 -116
  64. data/test/integration/repository/virtus_model_test.rb +0 -118
  65. data/test/test_helper.rb +0 -55
  66. data/test/unit/model_base_test.rb +0 -72
  67. data/test/unit/model_find_test.rb +0 -153
  68. data/test/unit/model_gateway_test.rb +0 -101
  69. data/test/unit/model_rails_test.rb +0 -112
  70. data/test/unit/model_store_test.rb +0 -576
  71. data/test/unit/persistence_test.rb +0 -32
  72. data/test/unit/repository_class_test.rb +0 -51
  73. data/test/unit/repository_client_test.rb +0 -32
  74. data/test/unit/repository_find_test.rb +0 -388
  75. data/test/unit/repository_indexing_test.rb +0 -37
  76. data/test/unit/repository_module_test.rb +0 -146
  77. data/test/unit/repository_naming_test.rb +0 -146
  78. data/test/unit/repository_response_results_test.rb +0 -98
  79. data/test/unit/repository_search_test.rb +0 -117
  80. data/test/unit/repository_serialize_test.rb +0 -57
  81. data/test/unit/repository_store_test.rb +0 -303
@@ -1,47 +0,0 @@
1
- module Elasticsearch
2
- module Persistence
3
- module Model
4
-
5
- # Make the `Persistence::Model` models compatible with Ruby On Rails applications
6
- #
7
- module Rails
8
- def self.included(base)
9
- base.class_eval do
10
-
11
- def initialize(attributes={})
12
- super(__convert_rails_dates(attributes))
13
- end
14
-
15
- def update(attributes={}, options={})
16
- super(__convert_rails_dates(attributes), options)
17
- end
18
- end
19
- end
20
-
21
- # Decorates the passed in `attributes` so they extract the date & time values from Rails forms
22
- #
23
- # @example Correctly combine the date and time to a datetime string
24
- #
25
- # params = { "published_on(1i)"=>"2014",
26
- # "published_on(2i)"=>"1",
27
- # "published_on(3i)"=>"1",
28
- # "published_on(4i)"=>"12",
29
- # "published_on(5i)"=>"00"
30
- # }
31
- # MyRailsModel.new(params).published_on.iso8601
32
- # # => "2014-01-01T12:00:00+00:00"
33
- #
34
- def __convert_rails_dates(attributes={})
35
- day = attributes.select { |p| p =~ /\([1-3]/ }.reduce({}) { |sum, item| (sum[item.first.gsub(/\(.+\)/, '')] ||= '' )<< item.last+'-'; sum }
36
- time = attributes.select { |p| p =~ /\([4-6]/ }.reduce({}) { |sum, item| (sum[item.first.gsub(/\(.+\)/, '')] ||= '' )<< item.last+':'; sum }
37
- unless day.empty?
38
- attributes.update day.reduce({}) { |sum, item| sum[item.first] = item.last; sum[item.first] += ' ' + time[item.first] unless time.empty?; sum }
39
- end
40
-
41
- return attributes
42
- end; module_function :__convert_rails_dates
43
- end
44
-
45
- end
46
- end
47
- end
@@ -1,254 +0,0 @@
1
- module Elasticsearch
2
- module Persistence
3
- module Model
4
-
5
- # This module contains the storage related features of {Elasticsearch::Persistence::Model}
6
- #
7
- module Store
8
- module ClassMethods #:nodoc:
9
-
10
- # Creates a class instance, saves it, if validations pass, and returns it
11
- #
12
- # @example Create a new person
13
- #
14
- # Person.create name: 'John Smith'
15
- # # => #<Person:0x007f889e302b30 ... @id="bG7yQDAXRhCi3ZfVcx6oAA", @name="John Smith" ...>
16
- #
17
- # @return [Object] The model instance
18
- #
19
- def create(attributes, options={})
20
- object = self.new(attributes)
21
- object.run_callbacks :create do
22
- object.save(options)
23
- object
24
- end
25
- end
26
- end
27
-
28
- module InstanceMethods
29
-
30
- # Saves the model (if validations pass) and returns the response (or `false`)
31
- #
32
- # @example Save a valid model instance
33
- #
34
- # p = Person.new(name: 'John')
35
- # p.save
36
- # => {"_index"=>"people", ... "_id"=>"RzFSXFR0R8u1CZIWNs2Gvg", "_version"=>1, "created"=>true}
37
- #
38
- # @example Save an invalid model instance
39
- #
40
- # p = Person.new(name: nil)
41
- # p.save
42
- # # => false
43
- #
44
- # @return [Hash,FalseClass] The Elasticsearch response as a Hash or `false`
45
- #
46
- def save(options={})
47
- unless options.delete(:validate) == false
48
- return false unless valid?
49
- end
50
-
51
- run_callbacks :save do
52
- options.update id: self.id
53
- options.update index: self._index if self._index
54
- options.update type: self._type if self._type
55
-
56
- self[:updated_at] = Time.now.utc
57
-
58
- response = self.class.gateway.save(self, options)
59
-
60
- @_id = response['_id']
61
- @_index = response['_index']
62
- @_type = response['_type']
63
- @_version = response['_version']
64
- @persisted = true
65
-
66
- response
67
- end
68
- end
69
-
70
- # Deletes the model from Elasticsearch (if it's persisted), freezes it, and returns the response
71
- #
72
- # @example Delete a model instance
73
- #
74
- # p.destroy
75
- # => {"_index"=>"people", ... "_id"=>"RzFSXFR0R8u1CZIWNs2Gvg", "_version"=>2 ...}
76
- #
77
- # @return [Hash] The Elasticsearch response as a Hash
78
- #
79
- def destroy(options={})
80
- raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
81
-
82
- run_callbacks :destroy do
83
- options.update index: self._index if self._index
84
- options.update type: self._type if self._type
85
-
86
- response = self.class.gateway.delete(self.id, options)
87
-
88
- @destroyed = true
89
- @persisted = false
90
- self.freeze
91
- response
92
- end
93
- end; alias :delete :destroy
94
-
95
- # Updates the model (via Elasticsearch's "Update" API) and returns the response
96
- #
97
- # @example Update a model with partial attributes
98
- #
99
- # p.update name: 'UPDATED'
100
- # => {"_index"=>"people", ... "_version"=>2}
101
- #
102
- # @example Pass a version for concurrency control
103
- #
104
- # p.update( { name: 'UPDATED' }, { version: 2 } )
105
- # => {"_index"=>"people", ... "_version"=>3}
106
- #
107
- # @example An exception is raised when the version doesn't match
108
- #
109
- # p.update( { name: 'UPDATED' }, { version: 2 } )
110
- # => Elasticsearch::Transport::Transport::Errors::Conflict: [409] {"error" ... }
111
- #
112
- # @return [Hash] The Elasticsearch response as a Hash
113
- #
114
- def update(attributes={}, options={})
115
- unless options.delete(:validate) == false
116
- return false unless valid?
117
- end
118
- raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
119
-
120
- run_callbacks :update do
121
- options.update index: self._index if self._index
122
- options.update type: self._type if self._type
123
-
124
- attributes.update( { updated_at: Time.now.utc } )
125
- response = self.class.gateway.update(self.id, { doc: attributes}.merge(options))
126
-
127
- self.attributes = self.attributes.merge(attributes)
128
- @_index = response['_index']
129
- @_type = response['_type']
130
- @_version = response['_version']
131
-
132
- response
133
- end
134
- end; alias :update_attributes :update
135
-
136
- # Increments a numeric attribute (via Elasticsearch's "Update" API) and returns the response
137
- #
138
- # @example Increment the `salary` attribute by 1
139
- #
140
- # p.increment :salary
141
- #
142
- # @example Increment the `salary` attribute by 100
143
- #
144
- # p.increment :salary, 100
145
- #
146
- # @return [Hash] The Elasticsearch response as a Hash
147
- #
148
- def increment(attribute, value=1, options={})
149
- raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
150
-
151
- options.update index: self._index if self._index
152
- options.update type: self._type if self._type
153
-
154
- response = self.class.gateway.update(self.id, { script: "ctx._source.#{attribute} += #{value}"}.merge(options))
155
-
156
- self[attribute] += value
157
-
158
- @_index = response['_index']
159
- @_type = response['_type']
160
- @_version = response['_version']
161
-
162
- response
163
- end
164
-
165
- # Decrements a numeric attribute (via Elasticsearch's "Update" API) and returns the response
166
- #
167
- # @example Decrement the `salary` attribute by 1
168
- #
169
- # p.decrement :salary
170
- #
171
- # @example Decrement the `salary` attribute by 100
172
- #
173
- # p.decrement :salary, 100
174
- #
175
- # @return [Hash] The Elasticsearch response as a Hash
176
- #
177
- def decrement(attribute, value=1, options={})
178
- raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
179
-
180
- options.update index: self._index if self._index
181
- options.update type: self._type if self._type
182
-
183
- response = self.class.gateway.update(self.id, { script: "ctx._source.#{attribute} = ctx._source.#{attribute} - #{value}"}.merge(options))
184
- self[attribute] -= value
185
-
186
- @_index = response['_index']
187
- @_type = response['_type']
188
- @_version = response['_version']
189
-
190
- response
191
- end
192
-
193
- # Updates the `updated_at` attribute, saves the model and returns the response
194
- #
195
- # @example Update the `updated_at` attribute (default)
196
- #
197
- # p.touch
198
- #
199
- # @example Update a custom attribute: `saved_on`
200
- #
201
- # p.touch :saved_on
202
- #
203
- # @return [Hash] The Elasticsearch response as a Hash
204
- #
205
- def touch(attribute=:updated_at, options={})
206
- raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
207
- raise ArgumentError, "Object does not have '#{attribute}' attribute" unless respond_to?(attribute)
208
-
209
- run_callbacks :touch do
210
- options.update index: self._index if self._index
211
- options.update type: self._type if self._type
212
-
213
- value = Time.now.utc
214
- response = self.class.gateway.update(self.id, { doc: { attribute => value.iso8601 }}.merge(options))
215
-
216
- self[attribute] = value
217
-
218
- @_index = response['_index']
219
- @_type = response['_type']
220
- @_version = response['_version']
221
-
222
- response
223
- end
224
- end
225
-
226
- # Returns true when the model has been destroyed, false otherwise
227
- #
228
- # @return [TrueClass,FalseClass]
229
- #
230
- def destroyed?
231
- !!@destroyed
232
- end
233
-
234
- # Returns true when the model has been already saved to the database, false otherwise
235
- #
236
- # @return [TrueClass,FalseClass]
237
- #
238
- def persisted?
239
- !!@persisted && !destroyed?
240
- end
241
-
242
- # Returns true when the model has not been saved yet, false otherwise
243
- #
244
- # @return [TrueClass,FalseClass]
245
- #
246
- def new_record?
247
- !persisted? && !destroyed?
248
- end
249
- end
250
- end
251
-
252
- end
253
- end
254
- end
@@ -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