Skip to content

Commit f29501d

Browse files
committed
[STORE] Update README for Repository mixin refactor
1 parent 049857a commit f29501d

File tree

1 file changed

+162
-63
lines changed

1 file changed

+162
-63
lines changed

Diff for: elasticsearch-persistence/README.md

+162-63
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Elasticsearch::Persistence
22

3-
Persistence layer for Ruby domain objects in Elasticsearch, using the Repository and ActiveRecord patterns.
3+
Persistence layer for Ruby domain objects in Elasticsearch, using the Repository pattern.
44

55
## Compatibility
66

@@ -14,6 +14,7 @@ is compatible with the Elasticsearch `master` branch, therefore, with the next m
1414
| 0.1 || 1.x |
1515
| 2.x || 2.x |
1616
| 5.x || 5.x |
17+
| 6.x || 6.x |
1718
| master || master |
1819

1920
## Installation
@@ -24,7 +25,7 @@ Install the package from [Rubygems](https://rubygems.org):
2425

2526
To use an unreleased version, either add it to your `Gemfile` for [Bundler](http://bundler.io):
2627

27-
gem 'elasticsearch-persistence', git: 'git://github.com/elastic/elasticsearch-rails.git', branch: '5.x'
28+
gem 'elasticsearch-persistence', git: 'git://github.com/elastic/elasticsearch-rails.git', branch: '6.x'
2829

2930
or install it from a source code checkout:
3031

@@ -35,9 +36,7 @@ or install it from a source code checkout:
3536

3637
## Usage
3738

38-
The library provides two different patterns for adding persistence to your Ruby objects:
39-
40-
* [Repository Pattern](#the-repository-pattern)
39+
The library provides the Repository pattern for adding persistence to your Ruby objects.
4140

4241
### The Repository Pattern
4342

@@ -67,7 +66,8 @@ Let's create a default, "dumb" repository, as a first step:
6766

6867
```ruby
6968
require 'elasticsearch/persistence'
70-
repository = Elasticsearch::Persistence::Repository.new
69+
class MyRepository; include Elasticsearch::Persistence::Repository; end
70+
repository = MyRepository.new
7171
```
7272

7373
We can save a `Note` instance into the repository...
@@ -120,32 +120,17 @@ The repository module provides a number of features and facilities to configure
120120
* Providing access to the Elasticsearch response for search results (aggregations, total, ...)
121121
* Defining the methods for serialization and deserialization
122122

123-
You can use the default repository class, or include the module in your own. Let's review it in detail.
123+
There are two mixins you can include in your Repository class. The first `Elasticsearch::Persistence::Repository`,
124+
provides the basic methods and settings you'll need. The second, `Elasticsearch::Persistence::Repository::DSL` adds
125+
some additional class methods that allow you to set options that instances of the class will share.
124126

125-
#### The Default Class
127+
#### Basic Repository mixin
126128

127-
For simple cases, you can use the default, bundled repository class, and configure/customize it:
129+
For simple cases, you can just include the Elasticsearch::Persistence::Repository mixin to your class:
128130

129131
```ruby
130-
repository = Elasticsearch::Persistence::Repository.new do
131-
# Configure the Elasticsearch client
132-
client Elasticsearch::Client.new url: ENV['ELASTICSEARCH_URL'], log: true
133-
134-
# Set a custom index name
135-
index :my_notes
136-
137-
# Set a custom document type
138-
type :my_note
139-
140-
# Specify the class to initialize when deserializing documents
141-
klass Note
142-
143-
# Configure the settings and mappings for the Elasticsearch index
144-
settings number_of_shards: 1 do
145-
mapping do
146-
indexes :text, analyzer: 'snowball'
147-
end
148-
end
132+
class MyRepository
133+
include Elasticsearch::Persistence::Repository
149134

150135
# Customize the serialization logic
151136
def serialize(document)
@@ -154,10 +139,18 @@ repository = Elasticsearch::Persistence::Repository.new do
154139

155140
# Customize the de-serialization logic
156141
def deserialize(document)
157-
puts "# ***** CUSTOM DESERIALIZE LOGIC KICKING IN... *****"
142+
puts "# ***** CUSTOM DESERIALIZE LOGIC... *****"
158143
super
159144
end
160145
end
146+
147+
client = Elasticsearch::Client.new(url: ENV['ELASTICSEARCH_URL'], log: true)
148+
repository = MyRepository.new(client: client, index_name: :my_notes, type: :my_note, klass: Note)
149+
repository.settings number_of_shards: 1 do
150+
mapping do
151+
indexes :text, analyzer: 'snowball'
152+
end
153+
end
161154
```
162155

163156
The custom Elasticsearch client will be used now, with a custom index and type names,
@@ -188,28 +181,27 @@ repository.find(1)
188181
<Note:0x007f9bd782b7a0 @attributes={... "my_special_key"=>"my_special_stuff"}>
189182
```
190183

191-
#### A Custom Class
184+
#### The DSL mixin
192185

193-
In most cases, though, you'll want to use a custom class for the repository, so let's do that:
186+
In some cases, you'll want to set some of the repository configurations at the class level. This makes
187+
most sense when the instances of the repository will use that same configuration:
194188

195189
```ruby
196190
require 'base64'
197191

198192
class NoteRepository
199193
include Elasticsearch::Persistence::Repository
194+
include Elasticsearch::Persistence::Repository::DSL
200195

201-
def initialize(options={})
202-
index options[:index] || 'notes'
203-
client Elasticsearch::Client.new url: options[:url], log: options[:log]
204-
end
205-
196+
index_name 'notes'
197+
document_type 'note'
206198
klass Note
207199

208200
settings number_of_shards: 1 do
209201
mapping do
210202
indexes :text, analyzer: 'snowball'
211203
# Do not index images
212-
indexes :image, index: 'no'
204+
indexes :image, index: false
213205
end
214206
end
215207

@@ -231,23 +223,26 @@ class NoteRepository
231223
end
232224
```
233225

234-
Include the `Elasticsearch::Persistence::Repository` module to add the repository methods into the class.
226+
You can create an instance of this custom class and get each of the configurations.
235227

236-
You can customize the repository in the familiar way, by calling the DSL-like methods.
228+
```ruby
229+
client = Elasticsearch::Client.new(url: 'http://localhost:9200', log: true)
230+
repository = NoteRepository.new(client: client)
231+
repository.index_name
232+
# => 'notes'
237233

238-
You can implement a custom initializer for your repository, add complex logic in its
239-
class and instance methods -- in general, have all the freedom of a standard Ruby class.
234+
```
235+
236+
You can also override the default configuration with options passed to the initialize method:
240237

241238
```ruby
242-
repository = NoteRepository.new url: 'http://localhost:9200', log: true
239+
client = Elasticsearch::Client.new(url: 'http://localhost:9250', log: true)
240+
client.transport.logger.formatter = proc { |s, d, p, m| "\e[2m# #{m}\n\e[0m" }
241+
repository = NoteRepository.new(client: client, index_name: 'notes_development')
243242

244-
# Configure the repository instance
245-
repository.index = 'notes_development'
246-
repository.client.transport.logger.formatter = proc { |s, d, p, m| "\e[2m# #{m}\n\e[0m" }
243+
repository.create_index!(force: true)
247244

248-
repository.create_index! force: true
249-
250-
note = Note.new 'id' => 1, 'text' => 'Document with image', 'image' => '... BINARY DATA ...'
245+
note = Note.new('id' => 1, 'text' => 'Document with image', 'image' => '... BINARY DATA ...')
251246

252247
repository.save(note)
253248
# PUT http://localhost:9200/notes_development/note/1
@@ -258,47 +253,110 @@ puts repository.find(1).attributes['image']
258253
# => ... BINARY DATA ...
259254
```
260255

261-
#### Methods Provided by the Repository
256+
#### Functionality Provided by the Repository mixin
257+
258+
Each of the following configurations can be set for a repository instance.
259+
If you have included the `Elasticsearch::Persistence::Repository::DSL` mixin, then you can use the class-level DSL
260+
methods to set each configuration. You can override the configuration for any instance by passing options to the
261+
`#initialize` method.
262+
If you don't use the DSL mixin, you can set also the instance configuration with options passed the `#initialize` method.
262263

263264
##### Client
264265

265-
The repository uses the standard Elasticsearch [client](https://github.com/elastic/elasticsearch-ruby#usage),
266-
which is accessible with the `client` getter and setter methods:
266+
The repository uses the standard Elasticsearch [client](https://github.com/elastic/elasticsearch-ruby#usage).
267267

268268
```ruby
269-
repository.client = Elasticsearch::Client.new url: 'http://search.server.org'
269+
client = Elasticsearch::Client.new(url: 'http://search.server.org')
270+
repository = NoteRepository.new(client: client)
270271
repository.client.transport.logger = Logger.new(STDERR)
271272
```
272273

274+
or with the DSL mixin:
275+
276+
```ruby
277+
class NoteRepository
278+
include Elasticsearch::Persistence::Repository
279+
include Elasticsearch::Persistence::Repository::DSL
280+
281+
client Elasticsearch::Client.new url: 'http://search.server.org'
282+
end
283+
284+
repository = NoteRepository.new
285+
286+
```
287+
273288
##### Naming
274289

275-
The `index` method specifies the Elasticsearch index to use for storage, lookup and search
276-
(when not set, the value is inferred from the repository class name):
290+
The `index_name` method specifies the Elasticsearch index to use for storage, lookup and search. The default index name
291+
is 'repository'.
292+
293+
```ruby
294+
repository = NoteRepository.new(index_name: 'notes_development')
295+
```
296+
297+
or with the DSL mixin:
298+
299+
```ruby
300+
class NoteRepository
301+
include Elasticsearch::Persistence::Repository
302+
include Elasticsearch::Persistence::Repository::DSL
303+
304+
index_name 'notes_development'
305+
end
306+
307+
repository = NoteRepository.new
308+
309+
```
310+
311+
The `type` method specifies the Elasticsearch document type to use for storage, lookup and search. The default value is
312+
'_doc'. Keep in mind that future versions of Elasticsearch will not allow you to set this yourself and will use the type,
313+
'_doc'.
277314

278315
```ruby
279-
repository.index = 'notes_development'
316+
repository = NoteRepository.new(document_type: 'note')
280317
```
281318

282-
The `type` method specifies the Elasticsearch document type to use for storage, lookup and search
283-
(when not set, the value is inferred from the document class name, or `_all` is used):
319+
or with the DSL mixin:
284320

285321
```ruby
286-
repository.type = 'my_note'
322+
class NoteRepository
323+
include Elasticsearch::Persistence::Repository
324+
include Elasticsearch::Persistence::Repository::DSL
325+
326+
document_type 'note'
327+
end
328+
329+
repository = NoteRepository.new
330+
287331
```
288332

289333
The `klass` method specifies the Ruby class name to use when initializing objects from
290-
documents retrieved from the repository (when not set, the value is inferred from the
291-
document `_type` as fetched from Elasticsearch):
334+
documents retrieved from the repository. If this value is not set, a Hash representation of the document will be
335+
returned instead.
336+
337+
```ruby
338+
repository = NoteRepository.new(klass: Note)
339+
```
340+
341+
or with the DSL mixin:
292342

293343
```ruby
294-
repository.klass = MyNote
344+
class NoteRepository
345+
include Elasticsearch::Persistence::Repository
346+
include Elasticsearch::Persistence::Repository::DSL
347+
348+
klass Note
349+
end
350+
351+
repository = NoteRepository.new
352+
295353
```
296354

297355
##### Index Configuration
298356

299357
The `settings` and `mappings` methods, provided by the
300358
[`elasticsearch-model`](http://rubydoc.info/gems/elasticsearch-model/Elasticsearch/Model/Indexing/ClassMethods)
301-
gem, allow to configure the index properties:
359+
gem, allow you to configure the index properties:
302360

303361
```ruby
304362
repository.settings number_of_shards: 1
@@ -310,7 +368,39 @@ repository.mappings.to_hash
310368
# => { :note => {:properties=> ... }}
311369
```
312370

371+
or with the DSL mixin:
372+
373+
```ruby
374+
class NoteRepository
375+
include Elasticsearch::Persistence::Repository
376+
include Elasticsearch::Persistence::Repository::DSL
377+
378+
mappings { indexes :title, analyzer: 'snowball' }
379+
settings number_of_shards: 1
380+
end
381+
382+
repository = NoteRepository.new
383+
384+
```
385+
386+
You can also use the `#create` method defined on the repository class to create and set the mappings and settings
387+
on an instance with a block in one call:
388+
389+
```ruby
390+
repository = NoteRepository.create(index_name: 'notes_development') do
391+
settings number_of_shards: 1, number_of_replicas: 0 do
392+
mapping dynamic: 'strict' do
393+
indexes :foo do
394+
indexes :bar
395+
end
396+
indexes :baz
397+
end
398+
end
399+
end
400+
```
401+
313402
The convenience methods `create_index!`, `delete_index!` and `refresh_index!` allow you to manage the index lifecycle.
403+
These methods can only be called on repository instances and are not implemented at the class level.
314404

315405
##### Serialization
316406

@@ -319,9 +409,12 @@ to the storage, and the initialization procedure when loading it from the storag
319409

320410
```ruby
321411
class NoteRepository
412+
include Elasticsearch::Persistence::Repository
413+
322414
def serialize(document)
323415
Hash[document.to_hash.map() { |k,v| v.upcase! if k == :title; [k,v] }]
324416
end
417+
325418
def deserialize(document)
326419
MyNote.new ActiveSupport::HashWithIndifferentAccess.new(document['_source']).deep_symbolize_keys
327420
end
@@ -426,9 +519,15 @@ end
426519
results.total
427520
# => 2
428521

429-
# Access the raw response as a Hashie::Mash instance
522+
# Access the raw response as a Hashie::Mash instance.
523+
# Note that a Hashie::Mash will only be created if the 'response' method is called on the results.
430524
results.response._shards.failed
431525
# => 0
526+
527+
# Access the raw response
528+
results.raw_response
529+
# => 0
530+
432531
```
433532

434533
#### Example Application

0 commit comments

Comments
 (0)