Skip to content

Commit ca1270d

Browse files
committed
[STORE] Added code annotation, documentation and examples
1 parent 44c9952 commit ca1270d

File tree

9 files changed

+288
-2
lines changed

9 files changed

+288
-2
lines changed

elasticsearch-persistence/lib/elasticsearch/persistence.rb

+58
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,72 @@
1717
require 'elasticsearch/persistence/repository'
1818

1919
module Elasticsearch
20+
21+
# Persistence for Ruby domain objects and models in Elasticsearch
22+
# ===============================================================
23+
#
24+
# `Elasticsearch::Persistence` contains modules for storing and retrieving Ruby domain objects and models
25+
# in Elasticsearch.
26+
#
27+
# == Repository
28+
#
29+
# The repository patterns allows to store and retrieve Ruby objects in Elasticsearch.
30+
#
31+
# require 'elasticsearch/persistence'
32+
#
33+
# class Note
34+
# def to_hash; {foo: 'bar'}; end
35+
# end
36+
#
37+
# repository = Elasticsearch::Persistence::Repository.new
38+
#
39+
# repository.save Note.new
40+
# # => {"_index"=>"repository", "_type"=>"note", "_id"=>"mY108X9mSHajxIy2rzH2CA", ...}
41+
#
42+
# Customize your repository by including the main module in a Ruby class
43+
# class MyRepository
44+
# include Elasticsearch::Persistence::Repository
45+
#
46+
# index 'my_notes'
47+
# klass Note
48+
#
49+
# client Elasticsearch::Client.new log: true
50+
# end
51+
#
52+
# repository = MyRepository.new
53+
#
54+
# repository.save Note.new
55+
# # 2014-04-04 22:15:25 +0200: POST http://localhost:9200/my_notes/note [status:201, request:0.009s, query:n/a]
56+
# # 2014-04-04 22:15:25 +0200: > {"foo":"bar"}
57+
# # 2014-04-04 22:15:25 +0200: < {"_index":"my_notes","_type":"note","_id":"-d28yXLFSlusnTxb13WIZQ", ...}
58+
#
2059
module Persistence
2160

2261
# :nodoc:
2362
module ClassMethods
63+
64+
# Get or set the default client for all repositories and models
65+
#
66+
# @example Set and configure the default client
67+
#
68+
# Elasticsearch::Persistence.client Elasticsearch::Client.new host: 'http://localhost:9200', tracer: true
69+
#
70+
# @example Perform an API request through the client
71+
#
72+
# Elasticsearch::Persistence.client.cluster.health
73+
# # => { "cluster_name" => "elasticsearch" ... }
74+
#
2475
def client client=nil
2576
@client = client || @client || Elasticsearch::Client.new
2677
end
2778

79+
# Set the default client for all repositories and models
80+
#
81+
# @example Set and configure the default client
82+
#
83+
# Elasticsearch::Persistence.client = Elasticsearch::Client.new host: 'http://localhost:9200', tracer: true
84+
# => #<Elasticsearch::Transport::Client:0x007f96a6dd0d80 @transport=... >
85+
#
2886
def client=(client)
2987
@client = client
3088
end

elasticsearch-persistence/lib/elasticsearch/persistence/client.rb

+30
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,40 @@ module Persistence
33
module Repository
44

55
module Client
6+
7+
# Get or set the default client for this repository
8+
#
9+
# @example Set and configure the client for the repository class
10+
#
11+
# class MyRepository
12+
# include Elasticsearch::Persistence::Repository
13+
# client Elasticsearch::Client.new host: 'http://localhost:9200', log: true
14+
# end
15+
#
16+
# @example Set and configure the client for this repository instance
17+
#
18+
# repository.client Elasticsearch::Client.new host: 'http://localhost:9200', tracer: true
19+
#
20+
# @example Perform an API request through the client
21+
#
22+
# MyRepository.client.cluster.health
23+
# repository.client.cluster.health
24+
# # => { "cluster_name" => "elasticsearch" ... }
25+
#
626
def client client=nil
727
@client = client || @client || Elasticsearch::Persistence.client
828
end
929

30+
# Set the default client for this repository
31+
#
32+
# @example Set and configure the client for the repository class
33+
#
34+
# MyRepository.client = Elasticsearch::Client.new host: 'http://localhost:9200', log: true
35+
#
36+
# @example Set and configure the client for this repository instance
37+
#
38+
# repository.client = Elasticsearch::Client.new host: 'http://localhost:9200', tracer: true
39+
#
1040
def client=(client)
1141
@client = client
1242
@client

elasticsearch-persistence/lib/elasticsearch/persistence/repository/class.rb

+39
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,41 @@ module Elasticsearch
22
module Persistence
33
module Repository
44

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+
#
15+
# @example Shortcut use
16+
#
17+
# repository = Elasticsearch::Persistence::Repository.new
18+
# # => #<Elasticsearch::Persistence::Repository::Class ...>
19+
#
20+
# @example Configuration via a block
21+
#
22+
# repository = Elasticsearch::Persistence::Repository.new do
23+
# index 'my_notes'
24+
# end
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+
#
540
class Class
641
include Elasticsearch::Persistence::Repository::Client
742
include Elasticsearch::Persistence::Repository::Naming
@@ -20,6 +55,10 @@ def initialize(options={}, &block)
2055
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
2156
end
2257

58+
# Return the "host" class, if this repository is a gateway hosted in another class
59+
#
60+
# @return [nil, Class]
61+
#
2362
def host
2463
options[:host]
2564
end

elasticsearch-persistence/lib/elasticsearch/persistence/repository/find.rb

+30
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,24 @@ module Persistence
33
module Repository
44
class DocumentNotFound < StandardError; end
55

6+
# Retrieves one or more domain objects from the repository
7+
#
68
module Find
9+
10+
# Retrieve a single object or multiple objects from Elasticsearch by ID or IDs
11+
#
12+
# @example Retrieve a single object by ID
13+
#
14+
# repository.find(1)
15+
# # => <Note ...>
16+
#
17+
# @example Retrieve multiple objects by IDs
18+
#
19+
# repository.find(1, 2)
20+
# # => [<Note ...>, <Note ...>
21+
#
22+
# @return [Object,Array]
23+
#
724
def find(*args)
825
options = args.last.is_a?(Hash) ? args.pop : {}
926
ids = args
@@ -16,11 +33,22 @@ def find(*args)
1633
end
1734
end
1835

36+
# Return if object exists in the repository
37+
#
38+
# @example
39+
#
40+
# repository.exists?(1)
41+
# => true
42+
#
43+
# @return [true, false]
44+
#
1945
def exists?(id, options={})
2046
type = document_type || (klass ? __get_type_from_class(klass) : '_all')
2147
client.exists( { index: index_name, type: type, id: id }.merge(options) )
2248
end
2349

50+
# @api private
51+
#
2452
def __find_one(id, options={})
2553
type = document_type || (klass ? __get_type_from_class(klass) : '_all')
2654
document = client.get( { index: index_name, type: type, id: id }.merge(options) )
@@ -30,6 +58,8 @@ def __find_one(id, options={})
3058
raise DocumentNotFound, e.message, caller
3159
end
3260

61+
# @api private
62+
#
3363
def __find_many(ids, options={})
3464
type = document_type || (klass ? __get_type_from_class(klass) : '_all')
3565
documents = client.mget( { index: index_name, type: type, body: { ids: ids } }.merge(options) )

elasticsearch-persistence/lib/elasticsearch/persistence/repository/naming.rb

+37
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@ module Persistence
33
module Repository
44

55
module Naming
6+
7+
# Get or set the class used to initialize domain objects when deserializing them
8+
#
69
def klass name=nil
710
@klass = name || @klass
811
end
912

13+
# Set the class used to initialize domain objects when deserializing them
14+
#
1015
def klass=klass
1116
@klass = klass
1217
end
1318

19+
# Get or set the index name used when storing and retrieving documents
20+
#
1421
def index_name name=nil
1522
@index_name = name || @index_name || begin
1623
if respond_to?(:host) && host && host.is_a?(Module)
@@ -21,29 +28,59 @@ def index_name name=nil
2128
end
2229
end; alias :index :index_name
2330

31+
# Set the index name used when storing and retrieving documents
32+
#
2433
def index_name=(name)
2534
@index_name = name
2635
end; alias :index= :index_name=
2736

37+
# Get or set the document type used when storing and retrieving documents
38+
#
2839
def document_type name=nil
2940
@document_type = name || @document_type || (klass ? klass.to_s.underscore : nil)
3041
end; alias :type :document_type
3142

43+
# Set the document type used when storing and retrieving documents
44+
#
3245
def document_type=(name)
3346
@document_type = name
3447
end; alias :type= :document_type=
3548

49+
# Get the Ruby class from the Elasticsearch `_type`
50+
#
51+
# @example
52+
# repository.__get_klass_from_type 'note'
53+
# => Note
54+
#
55+
# @api private
56+
#
3657
def __get_klass_from_type(type)
3758
klass = type.classify
3859
klass.constantize
3960
rescue NameError => e
4061
raise NameError, "Attempted to get class '#{klass}' from the '#{type}' type, but no such class can be found."
4162
end
4263

64+
# Get the Elasticsearch `_type` from the Ruby class
65+
#
66+
# @example
67+
# repository.__get_type_from_class Note
68+
# => "note"
69+
#
70+
# @api private
71+
#
4372
def __get_type_from_class(klass)
4473
klass.to_s.underscore
4574
end
4675

76+
# Get a document ID from the document (assuming Hash or Hash-like object)
77+
#
78+
# @example
79+
# repository.__get_id_from_document title: 'Test', id: 'abc123'
80+
# => "abc123"
81+
#
82+
# @api private
83+
#
4784
def __get_id_from_document(document)
4885
document[:id] || document['id'] || document[:_id] || document['_id']
4986
end

elasticsearch-persistence/lib/elasticsearch/persistence/repository/response/results.rb

+38-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
module Elasticsearch
22
module Persistence
33
module Repository
4-
module Response
4+
module Response # :nodoc:
55

6+
# Encapsulates the domain objects and documents returned from Elasticsearch when searching
7+
#
8+
# Implements `Enumerable` and forwards its methods to the {#results} object.
9+
#
610
class Results
711
include Enumerable
812

9-
attr_reader :repository, :response, :response
13+
attr_reader :repository
1014

15+
# @param repository [Elasticsearch::Persistence::Repository::Class] The repository instance
16+
# @param response [Hash] The full response returned from the Elasticsearch client
17+
# @param options [Hash] Optional parameters
18+
#
1119
def initialize(repository, response, options={})
1220
@repository = repository
1321
@response = Hashie::Mash.new(response)
@@ -22,10 +30,14 @@ def respond_to?(method_name, include_private = false)
2230
results.respond_to?(method_name) || super
2331
end
2432

33+
# The number of total hits for a query
34+
#
2535
def total
2636
response['hits']['total']
2737
end
2838

39+
# The maximum score for a query
40+
#
2941
def max_score
3042
response['hits']['max_score']
3143
end
@@ -42,11 +54,35 @@ def map_with_hit(&block)
4254
results.zip(response['hits']['hits']).map(&block)
4355
end
4456

57+
# Return the collection of domain objects
58+
#
59+
# @example Iterate over the results
60+
#
61+
# results.map { |r| r.attributes[:title] }
62+
# => ["Fox", "Dog"]
63+
#
64+
# @return [Array]
65+
#
4566
def results
4667
@results ||= response['hits']['hits'].map do |document|
4768
repository.deserialize(document.to_hash)
4869
end
4970
end
71+
72+
# Access the response returned from Elasticsearch by the client
73+
#
74+
# @example Access the aggregations in the response
75+
#
76+
# results = repository.search query: { match: { title: 'fox dog' } },
77+
# aggregations: { titles: { terms: { field: 'title' } } }
78+
# results.response.aggregations.titles.buckets.map { |term| "#{term['key']}: #{term['doc_count']}" }
79+
# # => ["brown: 1", "dog: 1", ...]
80+
#
81+
# @return [Hashie::Mash]
82+
#
83+
def response
84+
@response
85+
end
5086
end
5187
end
5288
end

0 commit comments

Comments
 (0)