Skip to content

Commit c3da11e

Browse files
committed
[MODEL] Added code annotations throughout the source
1 parent 3c95de6 commit c3da11e

19 files changed

+443
-39
lines changed

elasticsearch-model/lib/elasticsearch/model.rb

+32-10
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,23 @@ module Elasticsearch
3535
# Elasticsearch integration for Ruby models
3636
# =========================================
3737
#
38-
# TODO: Description
38+
# `Elasticsearch::Model` contains modules for integrating the Elasticsearch search and analytical engine
39+
# with ActiveModel-based classes, or models, for the Ruby programming language.
40+
#
41+
# It facilitates importing your data into an index, automatically updating it when a record changes,
42+
# searching the specific index, setting up the index mapping or the model JSON serialization.
43+
#
44+
# When the `Elasticsearch::Model` module is included in your class, it automatically extends it
45+
# with the functionality; see {Elasticsearch::Model.included}. Most methods are available via
46+
# the `__elasticsearch__` class and instance method proxies.
47+
#
48+
# It is possible to include/extend the model with the corresponding
49+
# modules directly, if that is desired:
50+
#
51+
# MyModel.__send__ :extend, Elasticsearch::Model::Client::ClassMethods
52+
# MyModel.__send__ :include, Elasticsearch::Model::Client::InstanceMethods
53+
# MyModel.__send__ :extend, Elasticsearch::Model::Searching::ClassMethods
54+
# # ...
3955
#
4056
module Model
4157

@@ -45,23 +61,16 @@ module Model
4561
# * Includes the necessary modules in the proxy classes
4662
# * Sets up delegation for crucial methods such as `search`, etc.
4763
#
48-
# @example Include the {Elasticsearch::Model} module in the `Article` model definition
64+
# @example Include the module in the `Article` model definition
4965
#
5066
# class Article < ActiveRecord::Base
5167
# include Elasticsearch::Model
5268
# end
5369
#
54-
# @example Inject the {Elasticsearch::Model} module into the `Article` model
70+
# @example Inject the module into the `Article` model during run time
5571
#
5672
# Article.__send__ :include, Elasticsearch::Model
5773
#
58-
# It is possible to include/extend the model with the corresponding
59-
# modules directly, without using the proxy, if this is desired:
60-
#
61-
# MyModel.__send__ :extend, Elasticsearch::Model::Client::ClassMethods
62-
# MyModel.__send__ :include, Elasticsearch::Model::Client::InstanceMethods
63-
# MyModel.__send__ :extend, Elasticsearch::Model::Searching::ClassMethods
64-
# # ...
6574
#
6675
def self.included(base)
6776
base.class_eval do
@@ -100,6 +109,19 @@ module ClassMethods
100109

101110
# Get or set the client for all models
102111
#
112+
# @example Get the client
113+
#
114+
# Elasticsearch::Model.client
115+
# => #<Elasticsearch::Transport::Client:0x007f96a7d0d000 @transport=... >
116+
#
117+
# @example Configure (set) the client for all the models
118+
#
119+
# Elasticsearch::Model.client Elasticsearch::Client.new host: 'http://localhost:9200', tracer: true
120+
# => #<Elasticsearch::Transport::Client:0x007f96a6dd0d80 @transport=... >
121+
#
122+
# @note You have to set the client before you call Elasticsearch methods on the model,
123+
# or set it directly on the model; see {Elasticsearch::Model::Client::ClassMethods#client}
124+
#
103125
def client client=nil
104126
@client = client || @client || Elasticsearch::Client.new
105127
end

elasticsearch-model/lib/elasticsearch/model/adapter.rb

+92
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,137 @@
11
module Elasticsearch
22
module Model
3+
4+
# Contains an adapter which provides OxM-specific implementations for common behaviour:
5+
#
6+
# * {Adapter::Adapter#records_mixin Fetching records from the database}
7+
# * {Adapter::Adapter#callbacks_mixin Model callbacks for automatic index updates}
8+
# * {Adapter::Adapter#importing_mixin Efficient bulk loading from the database}
9+
#
10+
# @see Elasticsearch::Model::Adapter::Default
11+
# @see Elasticsearch::Model::Adapter::ActiveRecord
12+
# @see Elasticsearch::Model::Adapter::Mongoid
13+
#
314
module Adapter
15+
16+
# Returns an adapter based on the Ruby class passed
17+
#
18+
# @example Create an adapter for an ActiveRecord-based model
19+
#
20+
# class Article < ActiveRecord::Base; end
21+
#
22+
# myadapter = Elasticsearch::Model::Adapter.from_class(Article)
23+
# myadapter.adapter
24+
# # => Elasticsearch::Model::Adapter::ActiveRecord
25+
#
26+
# @see Adapter.adapters The list of included adapters
27+
# @see Adapter.register Register a custom adapter
28+
#
429
def from_class(klass)
530
Adapter.new(klass)
631
end; module_function :from_class
732

33+
# Returns registered adapters
34+
#
35+
# @see ::Elasticsearch::Model::Adapter::Adapter.adapters
36+
#
837
def adapters
938
Adapter.adapters
1039
end; module_function :adapters
1140

41+
# Registers an adapter
42+
#
43+
# @see ::Elasticsearch::Model::Adapter::Adapter.register
44+
#
1245
def register(name, condition)
1346
Adapter.register(name, condition)
1447
end; module_function :register
1548

49+
# Contains an adapter for specific OxM or architecture.
50+
#
1651
class Adapter
1752
attr_reader :klass
1853

1954
def initialize(klass)
2055
@klass = klass
2156
end
2257

58+
# Registers an adapter for specific condition
59+
#
60+
# @param name [Module] The module containing the implemented interface
61+
# @param condition [Proc] An object with a `call` method which is evaluated in {.adapter}
62+
#
63+
# @example Register an adapter for DataMapper
64+
#
65+
# module DataMapperAdapter
66+
#
67+
# # Implement the interface for fetching records
68+
# #
69+
# module Records
70+
# def records
71+
# klass.all(id: @ids)
72+
# end
73+
#
74+
# # ...
75+
# end
76+
# end
77+
#
78+
# # Register the adapter
79+
# #
80+
# Elasticsearch::Model::Adapter.register(
81+
# DataMapperAdapter,
82+
# lambda { |klass|
83+
# defined?(::DataMapper::Resource) and klass.ancestors.include?(::DataMapper::Resource)
84+
# }
85+
# )
86+
#
2387
def self.register(name, condition)
2488
self.adapters[name] = condition
2589
end
2690

91+
# Return the collection of registered adapters
92+
#
93+
# @example Return the currently registered adapters
94+
#
95+
# Elasticsearch::Model::Adapter.adapters
96+
# # => {
97+
# # Elasticsearch::Model::Adapter::ActiveRecord => #<Proc:0x007...(lambda)>,
98+
# # Elasticsearch::Model::Adapter::Mongoid => #<Proc:0x007... (lambda)>,
99+
# # }
100+
#
101+
# @return [Hash] The collection of adapters
102+
#
27103
def self.adapters
28104
@adapters ||= {}
29105
end
30106

107+
# Return the module with {Default::Records} interface implementation
108+
#
109+
# @api private
110+
#
31111
def records_mixin
32112
adapter.const_get(:Records)
33113
end
34114

115+
# Return the module with {Default::Callbacks} interface implementation
116+
#
117+
# @api private
118+
#
35119
def callbacks_mixin
36120
adapter.const_get(:Callbacks)
37121
end
38122

123+
# Return the module with {Default::Importing} interface implementation
124+
#
125+
# @api private
126+
#
39127
def importing_mixin
40128
adapter.const_get(:Importing)
41129
end
42130

131+
# Returns the adapter module
132+
#
133+
# @api private
134+
#
43135
def adapter
44136
@adapter ||= begin
45137
self.class.adapters.find( lambda {[]} ) { |name, condition| condition.call(klass) }.first \

elasticsearch-model/lib/elasticsearch/model/adapters/active_record.rb

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
module Elasticsearch
22
module Model
33
module Adapter
4+
5+
# An adapter for ActiveRecord-based models
6+
#
47
module ActiveRecord
58

69
Adapter.register self,
710
lambda { |klass| defined?(::ActiveRecord::Base) && klass.ancestors.include?(::ActiveRecord::Base) }
811

912
module Records
1013

11-
# Return the `ActiveRecord::Relation` instance
14+
# Returns an `ActiveRecord::Relation` instance
1215
#
1316
def records
1417
sql_records = klass.where(id: @ids)
@@ -32,7 +35,7 @@ def load
3235
records.load
3336
end
3437

35-
# Intercept call to order, so we can ignore the order from Elasticsearch
38+
# Intercept call to the `order` method, so we can ignore the order from Elasticsearch
3639
#
3740
def order(*args)
3841
sql_records = records.__send__ :order, *args
@@ -48,6 +51,12 @@ def order(*args)
4851
end
4952

5053
module Callbacks
54+
55+
# Handle index updates (creating, updating or deleting documents)
56+
# when the model changes, by hooking into the lifecycle
57+
#
58+
# @see http://guides.rubyonrails.org/active_record_callbacks.html
59+
#
5160
def self.included(base)
5261
base.class_eval do
5362
after_commit lambda { __elasticsearch__.index_document }, on: [:create]
@@ -58,9 +67,10 @@ def self.included(base)
5867
end
5968

6069
module Importing
70+
6171
# Fetch batches of records from the database
6272
#
63-
# Use the [`find_in_batches`](http://api.rubyonrails.org/classes/ActiveRecord/Batches.html) method
73+
# @see http://api.rubyonrails.org/classes/ActiveRecord/Batches.html ActiveRecord::Batches.find_in_batches
6474
#
6575
def __find_in_batches(options={}, &block)
6676
find_in_batches(options) do |batch|
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,38 @@
11
module Elasticsearch
22
module Model
33
module Adapter
4+
5+
# The default adapter for models which haven't one registered
6+
#
47
module Default
58

9+
# Module for implementing methods and logic related to fetching records from the database
10+
#
611
module Records
7-
# Use `ActiveModel#find`
12+
13+
# Return the collection of records fetched from the database
14+
#
15+
# By default uses `MyModel#find[1, 2, 3]`
816
#
917
def records
1018
klass.find(@ids)
1119
end
1220
end
1321

22+
# Module for implementing methods and logic related to hooking into model lifecycle
23+
# (e.g. to perform automatic index updates)
24+
#
25+
# @see http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html
1426
module Callbacks
1527
# noop
1628
end
1729

30+
# Module for efficiently fetching records from the database to import them into the index
31+
#
1832
module Importing
33+
34+
# @abstract Implement this method in your adapter
35+
#
1936
def __find_in_batches(options={}, &block)
2037
raise NoMethodError, "Method not implemented for default adapter"
2138
end
@@ -24,4 +41,4 @@ def __find_in_batches(options={}, &block)
2441
end
2542
end
2643
end
27-
end
44+
end

elasticsearch-model/lib/elasticsearch/model/adapters/mongoid.rb

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
module Elasticsearch
22
module Model
33
module Adapter
4+
5+
# An adapter for Mongoid-based models
6+
#
7+
# @see http://mongoid.org
8+
#
49
module Mongoid
510

611
Adapter.register self,
712
lambda { |klass| defined?(::Mongoid::Document) && klass.ancestors.include?(::Mongoid::Document) }
813

914
module Records
10-
# Return the `ActiveRecord::Relation` instance
15+
16+
# Return a `Mongoid::Criteria` instance
1117
#
1218
def records
1319
criteria = klass.where(:id.in => @ids)
@@ -36,6 +42,12 @@ def records
3642
end
3743

3844
module Callbacks
45+
46+
# Handle index updates (creating, updating or deleting documents)
47+
# when the model changes, by hooking into the lifecycle
48+
#
49+
# @see http://mongoid.org/en/mongoid/docs/callbacks.html
50+
#
3951
def self.included(base)
4052
base.after_create { |document| document.__elasticsearch__.index_document }
4153
base.after_update { |document| document.__elasticsearch__.update_document }
@@ -44,6 +56,7 @@ def self.included(base)
4456
end
4557

4658
module Importing
59+
4760
# Fetch batches of records from the database
4861
#
4962
# @see https://github.com/mongoid/mongoid/issues/1334

elasticsearch-model/lib/elasticsearch/model/callbacks.rb

+23
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,30 @@
11
module Elasticsearch
22
module Model
3+
4+
# Allows to automatically update index based on model changes,
5+
# by hooking into the model lifecycle.
6+
#
7+
# @note A blocking HTTP request is done during the update process.
8+
# If you need a more performant/resilient way of updating the index,
9+
# consider adapting the callbacks behaviour, and use a background
10+
# processing solution such as [Sidekiq](http://sidekiq.org)
11+
# or [Resque](https://github.com/resque/resque).
12+
#
313
module Callbacks
414

15+
# When included in a model, automatically injects the callback subscribers (`after_save`, etc)
16+
#
17+
# @example Automatically update Elasticsearch index when the model changes
18+
#
19+
# class Article
20+
# include Elasticsearch::Model
21+
# include Elasticsearch::Model::Callbacks
22+
# end
23+
#
24+
# Article.first.update_attribute :title, 'Updated'
25+
# # SQL (0.3ms) UPDATE "articles" SET "title" = ...
26+
# # 2013-11-20 15:08:52 +0100: POST http://localhost:9200/articles/article/1/_update ...
27+
#
528
def self.included(base)
629
adapter = Adapter.from_class(base)
730
base.__send__ :include, adapter.callbacks_mixin

0 commit comments

Comments
 (0)