chewy 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +35 -29
  4. data/Appraisals +37 -0
  5. data/CHANGELOG.md +115 -4
  6. data/Gemfile +2 -3
  7. data/README.md +135 -40
  8. data/chewy.gemspec +4 -3
  9. data/gemfiles/rails.3.2.activerecord.gemfile +13 -0
  10. data/gemfiles/rails.3.2.activerecord.kaminari.gemfile +14 -0
  11. data/gemfiles/rails.3.2.activerecord.will_paginate.gemfile +14 -0
  12. data/gemfiles/rails.4.0.activerecord.gemfile +13 -0
  13. data/gemfiles/rails.4.0.activerecord.kaminari.gemfile +14 -0
  14. data/gemfiles/rails.4.0.activerecord.will_paginate.gemfile +14 -0
  15. data/gemfiles/rails.4.0.mongoid.gemfile +13 -0
  16. data/gemfiles/rails.4.0.mongoid.kaminari.gemfile +14 -0
  17. data/gemfiles/rails.4.0.mongoid.will_paginate.gemfile +14 -0
  18. data/gemfiles/rails.4.1.activerecord.gemfile +13 -0
  19. data/gemfiles/rails.4.1.activerecord.kaminari.gemfile +14 -0
  20. data/gemfiles/rails.4.1.activerecord.will_paginate.gemfile +14 -0
  21. data/gemfiles/rails.4.1.mongoid.gemfile +13 -0
  22. data/gemfiles/rails.4.1.mongoid.kaminari.gemfile +14 -0
  23. data/gemfiles/rails.4.1.mongoid.will_paginate.gemfile +14 -0
  24. data/gemfiles/rails.4.2.activerecord.gemfile +13 -0
  25. data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +14 -0
  26. data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +14 -0
  27. data/gemfiles/rails.4.2.mongoid.gemfile +13 -0
  28. data/gemfiles/rails.4.2.mongoid.kaminari.gemfile +14 -0
  29. data/gemfiles/rails.4.2.mongoid.will_paginate.gemfile +14 -0
  30. data/lib/chewy.rb +65 -0
  31. data/lib/chewy/config.rb +44 -93
  32. data/lib/chewy/errors.rb +14 -5
  33. data/lib/chewy/fields/base.rb +8 -7
  34. data/lib/chewy/fields/root.rb +2 -2
  35. data/lib/chewy/index.rb +7 -9
  36. data/lib/chewy/log_subscriber.rb +34 -0
  37. data/lib/chewy/query.rb +41 -27
  38. data/lib/chewy/query/criteria.rb +28 -23
  39. data/lib/chewy/query/scoping.rb +20 -0
  40. data/lib/chewy/railtie.rb +51 -13
  41. data/lib/chewy/repository.rb +61 -0
  42. data/lib/chewy/rspec/update_index.rb +3 -6
  43. data/lib/chewy/search.rb +28 -7
  44. data/lib/chewy/strategy.rb +60 -0
  45. data/lib/chewy/strategy/atomic.rb +31 -0
  46. data/lib/chewy/strategy/base.rb +27 -0
  47. data/lib/chewy/strategy/bypass.rb +15 -0
  48. data/lib/chewy/strategy/urgent.rb +17 -0
  49. data/lib/chewy/type.rb +19 -5
  50. data/lib/chewy/type/adapter/active_record.rb +28 -117
  51. data/lib/chewy/type/adapter/base.rb +35 -0
  52. data/lib/chewy/type/adapter/mongoid.rb +23 -123
  53. data/lib/chewy/type/adapter/object.rb +41 -19
  54. data/lib/chewy/type/adapter/orm.rb +142 -0
  55. data/lib/chewy/type/import.rb +43 -16
  56. data/lib/chewy/type/observe.rb +8 -21
  57. data/lib/chewy/version.rb +1 -1
  58. data/lib/tasks/chewy.rake +8 -4
  59. data/spec/chewy/config_spec.rb +20 -97
  60. data/spec/chewy/fields/base_spec.rb +24 -11
  61. data/spec/chewy/fields/time_fields_spec.rb +27 -0
  62. data/spec/chewy/index/settings_spec.rb +2 -1
  63. data/spec/chewy/index_spec.rb +98 -79
  64. data/spec/chewy/query/criteria_spec.rb +14 -0
  65. data/spec/chewy/query_spec.rb +1 -1
  66. data/spec/chewy/repository_spec.rb +50 -0
  67. data/spec/chewy/search_spec.rb +100 -0
  68. data/spec/chewy/strategy_spec.rb +109 -0
  69. data/spec/chewy/type/adapter/active_record_spec.rb +110 -46
  70. data/spec/chewy/type/adapter/mongoid_spec.rb +123 -74
  71. data/spec/chewy/type/adapter/object_spec.rb +51 -34
  72. data/spec/chewy/type/import_spec.rb +21 -21
  73. data/spec/chewy/type/observe_spec.rb +26 -29
  74. data/spec/chewy/type_spec.rb +19 -0
  75. data/spec/chewy_spec.rb +19 -3
  76. data/spec/spec_helper.rb +1 -1
  77. data/spec/support/active_record.rb +2 -1
  78. data/spec/support/mongoid.rb +29 -38
  79. metadata +85 -55
  80. data/gemfiles/Gemfile.rails-3.2.active_record +0 -6
  81. data/gemfiles/Gemfile.rails-3.2.active_record.kaminari +0 -7
  82. data/gemfiles/Gemfile.rails-3.2.active_record.will_paginate +0 -7
  83. data/gemfiles/Gemfile.rails-4.0.active_record +0 -6
  84. data/gemfiles/Gemfile.rails-4.0.active_record.kaminari +0 -7
  85. data/gemfiles/Gemfile.rails-4.0.active_record.will_paginate +0 -7
  86. data/gemfiles/Gemfile.rails-4.0.mongoid +0 -6
  87. data/gemfiles/Gemfile.rails-4.0.mongoid.kaminari +0 -7
  88. data/gemfiles/Gemfile.rails-4.0.mongoid.will_paginate +0 -7
  89. data/gemfiles/Gemfile.rails-4.1.active_record +0 -6
  90. data/gemfiles/Gemfile.rails-4.1.active_record.kaminari +0 -7
  91. data/gemfiles/Gemfile.rails-4.1.active_record.will_paginate +0 -7
  92. data/gemfiles/Gemfile.rails-4.1.mongoid +0 -6
  93. data/gemfiles/Gemfile.rails-4.1.mongoid.kaminari +0 -7
  94. data/gemfiles/Gemfile.rails-4.1.mongoid.will_paginate +0 -7
  95. data/gemfiles/Gemfile.rails-4.2.active_record +0 -6
  96. data/gemfiles/Gemfile.rails-4.2.active_record.kaminari +0 -7
  97. data/gemfiles/Gemfile.rails-4.2.active_record.will_paginate +0 -7
  98. data/gemfiles/Gemfile.rails-4.2.mongoid +0 -6
  99. data/gemfiles/Gemfile.rails-4.2.mongoid.kaminari +0 -7
  100. data/gemfiles/Gemfile.rails-4.2.mongoid.will_paginate +0 -7
  101. data/spec/chewy/index/search_spec.rb +0 -46
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 12e0c49636421098824baf242c46477ec44a1253
4
- data.tar.gz: d8861ffbacc81ec75d4c9a40b36ec19b345ef3aa
3
+ metadata.gz: 84273a240a5c4dac56535e864d042f647b655bef
4
+ data.tar.gz: a66632f1c947d9c8f446ef581139de5175c55763
5
5
  SHA512:
6
- metadata.gz: a29788d87989658ea5a7017554217b21bfdf6a52c7486a740c977261f5a095b591d5f4f352bb1ccbe5f8a26c74f8e355c0f4c2ce4b896a3a71cdb6106974434f
7
- data.tar.gz: cffc378f5fe51f0a9507c43315491f005b6f1ad9d993946786583a54df95b44bcba56483d186c6356d2fef2168dc692979146a900b8c33870782eb84cc4c6cb6
6
+ metadata.gz: 08810417cade81d8cc563438139c1558dde2efc7321eeb1a988399b406c1339ca3bdacb56f083d6d4fc0ebdfbf3c8b7bf232c40ac034abe69f2e868d296821bd
7
+ data.tar.gz: 7c0cf989f04a92fea804ff67490f623037119ed58ab54ba3e4bfdce272f2d546403313e0afb11fd522794473e9b04719d0b24a9753299538c574f8d0c326efaf
data/.gitignore CHANGED
@@ -3,7 +3,8 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
- Gemfile*.lock
6
+ Gemfile.lock
7
+ gemfiles/*.lock
7
8
  InstalledFiles
8
9
  _yardoc
9
10
  coverage
@@ -1,36 +1,42 @@
1
1
  language: ruby
2
+ services:
3
+ - mongodb
2
4
  rvm:
3
5
  - 2.0.0
4
- - 2.1.3
6
+ - 2.1.5
7
+ - 2.2.0
5
8
  # - rbx
6
9
  gemfile:
7
- - Gemfile
8
- - gemfiles/Gemfile.rails-3.2.active_record
9
- - gemfiles/Gemfile.rails-3.2.active_record.kaminari
10
- - gemfiles/Gemfile.rails-3.2.active_record.will_paginate
11
- - gemfiles/Gemfile.rails-4.0.active_record
12
- - gemfiles/Gemfile.rails-4.0.active_record.kaminari
13
- - gemfiles/Gemfile.rails-4.0.active_record.will_paginate
14
- - gemfiles/Gemfile.rails-4.0.mongoid
15
- - gemfiles/Gemfile.rails-4.0.mongoid.kaminari
16
- - gemfiles/Gemfile.rails-4.0.mongoid.will_paginate
17
- - gemfiles/Gemfile.rails-4.1.active_record
18
- - gemfiles/Gemfile.rails-4.1.active_record.kaminari
19
- - gemfiles/Gemfile.rails-4.1.active_record.will_paginate
20
- - gemfiles/Gemfile.rails-4.1.mongoid
21
- - gemfiles/Gemfile.rails-4.1.mongoid.kaminari
22
- - gemfiles/Gemfile.rails-4.1.mongoid.will_paginate
23
- # - gemfiles/Gemfile.rails-4.2.active_record
24
- # - gemfiles/Gemfile.rails-4.2.active_record.kaminari
25
- # - gemfiles/Gemfile.rails-4.2.active_record.will_paginate
26
- # - gemfiles/Gemfile.rails-4.2.mongoid
27
- # - gemfiles/Gemfile.rails-4.2.mongoid.kaminari
28
- # - gemfiles/Gemfile.rails-4.2.mongoid.will_paginate
29
-
10
+ - gemfiles/rails.3.2.activerecord.gemfile
11
+ - gemfiles/rails.3.2.activerecord.kaminari.gemfile
12
+ - gemfiles/rails.3.2.activerecord.will_paginate.gemfile
13
+ - gemfiles/rails.4.0.activerecord.gemfile
14
+ - gemfiles/rails.4.0.activerecord.kaminari.gemfile
15
+ - gemfiles/rails.4.0.activerecord.will_paginate.gemfile
16
+ - gemfiles/rails.4.1.activerecord.gemfile
17
+ - gemfiles/rails.4.1.activerecord.kaminari.gemfile
18
+ - gemfiles/rails.4.1.activerecord.will_paginate.gemfile
19
+ - gemfiles/rails.4.2.activerecord.gemfile
20
+ - gemfiles/rails.4.2.activerecord.kaminari.gemfile
21
+ - gemfiles/rails.4.2.activerecord.will_paginate.gemfile
22
+ - gemfiles/rails.4.0.mongoid.gemfile
23
+ - gemfiles/rails.4.0.mongoid.kaminari.gemfile
24
+ - gemfiles/rails.4.0.mongoid.will_paginate.gemfile
25
+ - gemfiles/rails.4.1.mongoid.gemfile
26
+ - gemfiles/rails.4.1.mongoid.kaminari.gemfile
27
+ - gemfiles/rails.4.1.mongoid.will_paginate.gemfile
28
+ - gemfiles/rails.4.2.mongoid.gemfile
29
+ - gemfiles/rails.4.2.mongoid.kaminari.gemfile
30
+ - gemfiles/rails.4.2.mongoid.will_paginate.gemfile
31
+ matrix:
32
+ exclude:
33
+ - rvm: 2.2.0
34
+ gemfile: gemfiles/rails.3.2.activerecord.gemfile
35
+ - rvm: 2.2.0
36
+ gemfile: gemfiles/rails.3.2.activerecord.kaminari.gemfile
37
+ - rvm: 2.2.0
38
+ gemfile: gemfiles/rails.3.2.activerecord.will_paginate.gemfile
30
39
  before_install:
31
- - curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.3.0.tar.gz | tar xz -C /tmp
40
+ - curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.4.tar.gz | tar xz -C /tmp
32
41
  before_script:
33
- - TEST_CLUSTER_COMMAND="/tmp/elasticsearch-1.3.0/bin/elasticsearch" rake elasticsearch:start
34
- services:
35
- - mongodb
36
-
42
+ - TEST_CLUSTER_COMMAND="/tmp/elasticsearch-1.4.4/bin/elasticsearch" rake elasticsearch:start
@@ -0,0 +1,37 @@
1
+ %w(3.2 4.0 4.1 4.2).each do |version|
2
+ appraise "rails.#{version}.activerecord" do
3
+ gem 'activerecord', "~> #{version}.0"
4
+ gem 'activesupport', "~> #{version}.0"
5
+ end
6
+
7
+ appraise "rails.#{version}.activerecord.kaminari" do
8
+ gem 'activerecord', "~> #{version}.0"
9
+ gem 'activesupport', "~> #{version}.0"
10
+ gem 'kaminari', require: false
11
+ end
12
+
13
+ appraise "rails.#{version}.activerecord.will_paginate" do
14
+ gem 'activerecord', "~> #{version}.0"
15
+ gem 'activesupport', "~> #{version}.0"
16
+ gem 'will_paginate', require: false
17
+ end
18
+ end
19
+
20
+ %w(4.0 4.1 4.2).each do |version|
21
+ appraise "rails.#{version}.mongoid" do
22
+ gem 'mongoid', '~> 4.0.0'
23
+ gem 'activesupport', "~> #{version}.0"
24
+ end
25
+
26
+ appraise "rails.#{version}.mongoid.kaminari" do
27
+ gem 'mongoid', '~> 4.0.0'
28
+ gem 'activesupport', "~> #{version}.0"
29
+ gem 'kaminari', require: false
30
+ end
31
+
32
+ appraise "rails.#{version}.mongoid.will_paginate" do
33
+ gem 'mongoid', '~> 4.0.0'
34
+ gem 'activesupport', "~> #{version}.0"
35
+ gem 'will_paginate', require: false
36
+ end
37
+ end
@@ -1,5 +1,116 @@
1
1
  # master
2
2
 
3
+ ## Incompatible changes:
4
+
5
+ * `Chewy.use_after_commit_callbacks = false` returns previous RDBMS behavior
6
+ in tests.
7
+
8
+ * ActiveRecord import is now called after_commit instead of after_save and after_destroy
9
+
10
+ * Import now respects default scope and removes unmatched documents
11
+
12
+ * `delete_from_index?` method is deprecated, use
13
+
14
+ ```ruby
15
+ define_type User, delete_if: ->{ removed? } do
16
+ ...
17
+ end
18
+ ```
19
+
20
+ * `Chewy.request_strategy` to configure action controller's request wrapping strategy
21
+
22
+ * `Chewy.root_strategy` to configure the first strategy in stack
23
+
24
+ * Default strategy for controller actions is `:atomic`
25
+
26
+ * Default strategy for activerecord migrations is `:bypass`
27
+
28
+ * Default strategy for sandbox console is `:bypass`
29
+
30
+ * Default strategy for rails console is `:urgent`
31
+
32
+ * `Chewy.configuration` was renamed to `Chewy.settings`
33
+
34
+ * Reworked index update strategies implementation. `Chewy.atomic`
35
+ and `Chewy.urgent_update` are now deprecated in favour of the new
36
+ `Chewy.strategy` API.
37
+
38
+ * Loading objects for object-sourced types using `wrap` method is
39
+ deprecated, `load_one` method should be used instead. Or method name
40
+ might be passed to `define_type`:
41
+
42
+ ```ruby
43
+ class GeoData
44
+ def self.get_data(elasticsearch_document)
45
+ REDIS.get("geo_data_#{elasticsearch_document.id}")
46
+ end
47
+ end
48
+
49
+ ...
50
+ define_type GeoData, load_one_method: :get_data do
51
+ ...
52
+ end
53
+ ```
54
+
55
+ ## Changes
56
+
57
+ * Multiple enhancements by @DNNX
58
+
59
+ * Added `script_fields` to search crteria (@ka8725)
60
+
61
+ * ORM adapters now completely relies on the default scope. This means every scope or objects passed to import are merged with default scope so basically there is no need to define `delete_if` block. Default scope strongly restricts objects which may land in the current index.
62
+
63
+ ```ruby
64
+ define_type Country.where("rating > 30") do
65
+
66
+ end
67
+
68
+ # this code would import only countries with rating between 30 and 50
69
+ CountriesIndex::Country.import(Country.where("rating < 50"))
70
+
71
+ # the same is true for arrays of objects or ids
72
+ CountriesIndex::Country.import(Country.where("rating < 50").to_a)
73
+ CountriesIndex::Country.import(Country.where("rating < 50").pluck(:id))
74
+ ```
75
+
76
+ * Object adapter supports custom initial import and load methods, so it
77
+ could be configured to be used with procs or any class responding to `call`
78
+ method.
79
+
80
+ ```ruby
81
+ class GeoData
82
+ def self.call
83
+ REDIS.get_all
84
+ end
85
+ end
86
+
87
+ ...
88
+ define_type GeoData do
89
+ ...
90
+ end
91
+ ```
92
+
93
+ * Nested fields value procs additional arguments: parent objects.
94
+
95
+ ```ruby
96
+ define_type Country do
97
+ field :name
98
+ field :cities do
99
+ field :district, value: ->(city, country) { city.districts if country.main? }
100
+ end
101
+ end
102
+ ```
103
+
104
+ * Implemented basic named scopes
105
+
106
+ ## Bugfixes
107
+
108
+ * `script_score` allow options (@joeljunstrom)
109
+
110
+ * Chewy indexes eaged loading fixes (@leemhenson)
111
+
112
+ * `Chewy::Index.import nil` imports nothing instead of initial data
113
+
3
114
  # Version 0.6.2
4
115
 
5
116
  ## Changes
@@ -38,14 +149,14 @@
38
149
 
39
150
  # Version 0.5.2
40
151
 
41
- ## Changes
42
-
43
- * `Chewy.massacre` aliased to `Chewy.delete_all` method deletes all the indexes with current prefix
44
-
45
152
  ## Incompatible changes:
46
153
 
47
154
  * `Chewy::Type::Base` removed in favour of using `Chewy::Type` as a base class for all types
48
155
 
156
+ ## Changes
157
+
158
+ * `Chewy.massacre` aliased to `Chewy.delete_all` method deletes all the indexes with current prefix
159
+
49
160
  ## Bugfixes:
50
161
 
51
162
  * Advanced type classes resolving (@inbeom)
data/Gemfile CHANGED
@@ -1,12 +1,11 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in chewy.gemspec
4
3
  gemspec
5
4
 
6
5
  gem 'activerecord'
7
6
  # gem 'mongoid'
8
- gem 'kaminari', require: false
9
- # gem 'will_paginate', require: false
7
+ # gem 'kaminari', require: false
8
+ # gem 'will_pagnate', require: false
10
9
 
11
10
  group :test do
12
11
  gem 'guard'
data/README.md CHANGED
@@ -2,6 +2,9 @@
2
2
  [![Code Climate](https://codeclimate.com/github/toptal/chewy.png)](https://codeclimate.com/github/toptal/chewy)
3
3
  [![Inline docs](http://inch-ci.org/github/toptal/chewy.svg?branch=master)](http://inch-ci.org/github/toptal/chewy)
4
4
 
5
+ <p align="right">Sponsored by</p>
6
+ <p align="right"><a href="http://www.toptal.com/"><img src="http://www.toptal.com/assets/public/blocks/logo/big.png" alt="Toptal" width="105" height="34"></a></p>
7
+
5
8
  # Chewy
6
9
 
7
10
  Chewy is ODM and wrapper for official elasticsearch client (https://github.com/elasticsearch/elasticsearch-ruby)
@@ -18,7 +21,7 @@ Chewy is ODM and wrapper for official elasticsearch client (https://github.com/e
18
21
 
19
22
  * Bulk import everywhere.
20
23
 
21
- Chewy utilizes bulk ES API for full reindexing or index updates. Also it uses atomic updates concept. All the changed objects are collected inside the atomic block and index is updated once at the end of it with all the collected object. See `Chewy.atomic` for more details.
24
+ Chewy utilizes bulk ES API for full reindexing or index updates. Also it uses atomic updates concept. All the changed objects are collected inside the atomic block and index is updated once at the end of it with all the collected object. See `Chewy.strategy(:atomic)` for more details.
22
25
 
23
26
  * Powerful querying DSL.
24
27
 
@@ -40,15 +43,15 @@ Or install it yourself as:
40
43
 
41
44
  ## Usage
42
45
 
43
- ### Client configuration
46
+ ### Client settings
44
47
 
45
- There are 2 ways to configure Chewy client: `Chewy.configuration` hash and `chewy.yml`
48
+ There are 2 ways to configure Chewy client: `Chewy.settings` hash and `chewy.yml`
46
49
 
47
50
  You can create this file manually or run `rails g chewy:install` to do that with yaml way
48
51
 
49
52
  ```ruby
50
53
  # config/initializers/chewy.rb
51
- Chewy.configuration = {host: 'localhost:9250'} # do not use environments
54
+ Chewy.settings = {host: 'localhost:9250'} # do not use environments
52
55
  ```
53
56
 
54
57
  ```yaml
@@ -64,7 +67,7 @@ development:
64
67
  The result config merges both hashes. Client options are passed as is to Elasticsearch::Transport::Client except the `:prefix` - it is used internally by chewy to create prefixed index names:
65
68
 
66
69
  ```ruby
67
- Chewy.configuration = {prefix: 'test'}
70
+ Chewy.settings = {prefix: 'test'}
68
71
  UsersIndex.index_name # => 'test_users'
69
72
  ```
70
73
 
@@ -108,6 +111,8 @@ See [config.rb](lib/chewy/config.rb) for more details.
108
111
  field :projects do # the same block syntax for multi_field, if `:type` is specified
109
112
  field :title
110
113
  field :description # default data type is `string`
114
+ # additional top-level objects passed to value proc:
115
+ field :categories, value: ->(project, user) { project.categories.map(&:name) if user.active? }
111
116
  end
112
117
  field :rating, type: 'integer' # custom data type
113
118
  field :created, type: 'date', include_in_all: false,
@@ -196,7 +201,7 @@ You are able to access index-defined types with the following API:
196
201
 
197
202
  ```ruby
198
203
  UsersIndex::User # => UsersIndex::User
199
- UsersIndex.types_hash['user'] # => UsersIndex::User
204
+ UsersIndex.type_hash['user'] # => UsersIndex::User
200
205
  UsersIndex.user # => UsersIndex::User
201
206
  UsersIndex.types # => [UsersIndex::User]
202
207
  UsersIndex.type_names # => ['user']
@@ -226,57 +231,147 @@ UsersIndex.import user: User.where('rating > 100') # import only active users to
226
231
  UsersIndex.reset! # purges index and imports default data for all types
227
232
  ```
228
233
 
229
- Also if passed user is `#destroyed?` or `#delete_from_index?` or specified id does not exists in the database, import will perform delete from index action for this object.
234
+ Also if passed user is `#destroyed?`, or satisfy `delete_if` type option, or specified id does not exists in the database, import will perform delete from index action for this object.
235
+
236
+ ```ruby
237
+ define_type User, delete_if: :deleted_at
238
+ define_type User, delete_if: -> { deleted_at }
239
+ define_type User, delete_if: ->(user) { user.deleted_at }
240
+ ```
230
241
 
231
242
  See [actions.rb](lib/chewy/index/actions.rb) for more details.
232
243
 
233
- ### Observing strategies
244
+ ### Index update strategies
245
+
246
+ Assume you've got the following code:
247
+
248
+ ```ruby
249
+ class City < ActiveRecord::Base
250
+ update_index 'cities#city', :self
251
+ end
252
+
253
+ class CitiesIndex < Chewy::Index
254
+ define_type City do
255
+ field :name
256
+ end
257
+ end
258
+ ```
259
+
260
+ If you'll perform something like `City.first.save!` you'll get
261
+ UndefinedUpdateStrategy exception instead of normal object saving
262
+ and index update. This exception forces you to choose appropriate
263
+ update strategy for current context.
234
264
 
235
- There are 3 strategies for index updating: do not update index at all, update right after save and cumulative update. The first is by default.
265
+ If you want to return behavior was before 0.7.0 - just set
266
+ `Chewy.root_strategy = :bypass`.
236
267
 
237
- **WARN: It is preferred to use `Chewy.atomic` block in most cases due to performance restrictions of the urgent updates!**
268
+ #### `:atomic`
238
269
 
239
- #### Updating index on-demand
270
+ The main strategy here is `:atomic`. Assume you have to update a
271
+ lot of records in db.
240
272
 
241
- By default Chewy indexes are not updated when the observed model is saved or destroyed.
242
- This depends on the `Chewy.urgent_update` (false by default) or on the per-model update config.
243
- If you will perform `Chewy.urgent_update = true`, all the models will start to update elasticsearch
244
- index right after save.
273
+ ```ruby
274
+ Chewy.strategy(:atomic) do
275
+ City.popular.map(&:do_some_update_action!)
276
+ end
277
+ ```
245
278
 
246
- Note than urgent update options affects only outside-atomic-block behavour. Inside
247
- the `Chewy.atomic { }` block indexes updates as described below.
279
+ Using this strategy delays index update request until the end of
280
+ block. Updated records are aggregated and index update happens with
281
+ bulk API. So this strategy is highly optimized.
248
282
 
249
- #### Using atomic updates
283
+ #### `:urgent`
250
284
 
251
- To perform atomic cummulative updates, use `Chewy.atomic`:
285
+ Next strategy is convenient if you are going to update documents in
286
+ index one-by-one.
252
287
 
253
288
  ```ruby
254
- Chewy.atomic do
255
- user.each { |user| user.update_attributes(name: user.name.strip) }
289
+ Chewy.strategy(:urgent) do
290
+ City.popular.map(&:do_some_update_action!)
256
291
  end
257
292
  ```
258
293
 
259
- Index update will be performed once per Chewy.atomic block for every affected type.
260
- This strategy is highly usable for rails actions:
294
+ This code would perform `City.popular.count` requests for ES
295
+ documents update.
296
+
297
+ Seems to be convenient for usage in e.g. rails console with
298
+ non-block notation:
261
299
 
262
300
  ```ruby
263
- class ApplicationController < ActionController::Base
264
- around_action :chewy_atomic
301
+ > Chewy.strategy(:urgent)
302
+ > City.popular.map(&:do_some_update_action!)
303
+ ```
265
304
 
266
- def chewy_atomic
267
- Chewy.atomic do
268
- yield
269
- end
305
+ #### `:bypass`
306
+
307
+ Bypass strategy simply silences index updates.
308
+
309
+ #### Nesting
310
+
311
+ Strategies are designed to allow nesting, so it is possible
312
+ to redefine it for nested contexts.
313
+
314
+ ```ruby
315
+ Chewy.strategy(:atomic) do
316
+ city1.do_update!
317
+ Chewy.strategy(:urgent) do
318
+ city2.do_update!
319
+ city3.do_update!
320
+ # there will be 2 update index requests for city2 and city3
270
321
  end
322
+ city4..do_update!
323
+ # city1 and city4 will be grouped in one index update request
271
324
  end
272
325
  ```
273
326
 
274
- Also atomic blocks might be nested and don't affect each other.
327
+ #### Non-block notation
328
+
329
+ It is possible to nest strategies without blocks:
330
+
331
+ ```ruby
332
+ Chewy.strategy(:urgent)
333
+ city1.do_update! # index updated
334
+ Chewy.strategy(:bypass)
335
+ city2.do_update! # update bypassed
336
+ Chewy.strategy.pop
337
+ city3.do_update! # index updated again
338
+ ```
339
+
340
+ #### Designing own strategies
341
+
342
+ Async strategy is not implemented yet, but it is planned. So
343
+ it would be a good idea to implements own async strategy for
344
+ particular delayed jobs library or simply threads.
345
+
346
+ See [strategy/base.rb](lib/chewy/strategy/base.rb) for more details.
347
+ See [strategy/atomic.rb](lib/chewy/strategy/atomic.rb) for example.
275
348
 
276
349
  ### Async reindexing
277
350
 
278
351
  Chewy is not support async index update, but it's planned. Until you can use third-party solutions, such as [https://github.com/averell23/chewy_kiqqer](https://github.com/averell23/chewy_kiqqer)
279
352
 
353
+ Not sure it works currently.
354
+
355
+ ### Rails application strategies integration
356
+
357
+ There is a couple of pre-defined strategies for your rails application. At first, rails console uses `:urgent` strategy by default, except the sandbox case. Whan you are running sandbox it switches to `bypass` strategy to avoid index polluting.
358
+
359
+ Also migrations are wrapped with `:bypass` strategy. Because the main behavor implies that indexes are resetted after migration, so there is no need for extra index updates.
360
+ Also indexing might be broken during migrations because of the outdated schema.
361
+
362
+ Controller actions are wrapped with `:atomic` strategy with middleware just to reduce amount of index update requests inside actions.
363
+
364
+ It is also a good idea to set up `:bypass` strategy inside your test suite and import objects manually only when needed, plus use `Chewy.massacre` when needed to flush test ES indexes before every example. This will allow to minimize unnecessary ES requests and reduce overhead.
365
+
366
+
367
+ ```ruby
368
+ RSpec.configure do |config|
369
+ config.before(:suite) do
370
+ Chewy.strategy(:bypass)
371
+ end
372
+ end
373
+ ```
374
+
280
375
  ### Index querying
281
376
 
282
377
  ```ruby
@@ -692,7 +787,7 @@ Chewy has notifing the following events:
692
787
  {index: 30, delete: 5}
693
788
  ```
694
789
 
695
- * `payload[:erorrs]`: might not exists. Contains grouped errors with objects ids list:
790
+ * `payload[:errors]`: might not exists. Contains grouped errors with objects ids list:
696
791
 
697
792
  ```ruby
698
793
  {index: {
@@ -709,26 +804,26 @@ To integrate with NewRelic you may use the following example source (config/init
709
804
 
710
805
  ```ruby
711
806
  ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
712
- metrics = "Database/ElasticSearch/import"
807
+ metric_name = "Database/ElasticSearch/import"
713
808
  duration = (finish - start).to_f
714
809
  logged = "#{payload[:type]} #{payload[:import].to_a.map{ |i| i.join(':') }.join(', ')}"
715
810
 
716
- self.class.trace_execution_scoped([metrics]) do
811
+ self.class.trace_execution_scoped([metric_name]) do
717
812
  NewRelic::Agent.instance.transaction_sampler.notice_sql(logged, nil, duration)
718
- NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metrics, nil, duration)
719
- NewRelic::Agent.instance.stats_engine.record_metrics(metrics, duration)
813
+ NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metric_name, nil, duration)
814
+ NewRelic::Agent.record_metric(metric_name, duration)
720
815
  end
721
816
  end
722
817
 
723
818
  ActiveSupport::Notifications.subscribe('search_query.chewy') do |name, start, finish, id, payload|
724
- metrics = "Database/ElasticSearch/search"
819
+ metric_name = "Database/ElasticSearch/search"
725
820
  duration = (finish - start).to_f
726
- logged = "#{payload[:index]} #{payload[:request]}"
821
+ logged = "#{payload[:type].presence || payload[:index]} #{payload[:request]}"
727
822
 
728
- self.class.trace_execution_scoped([metrics]) do
823
+ self.class.trace_execution_scoped([metric_name]) do
729
824
  NewRelic::Agent.instance.transaction_sampler.notice_sql(logged, nil, duration)
730
- NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metrics, nil, duration)
731
- NewRelic::Agent.instance.stats_engine.record_metrics(metrics, duration)
825
+ NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metric_name, nil, duration)
826
+ NewRelic::Agent.record_metric(metric_name, duration)
732
827
  end
733
828
  end
734
829
  ```