chewy 0.10.1 → 5.0.0

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 (73) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +25 -25
  3. data/.travis.yml +21 -29
  4. data/Appraisals +27 -9
  5. data/CHANGELOG.md +36 -0
  6. data/Gemfile +3 -1
  7. data/README.md +73 -23
  8. data/chewy.gemspec +6 -8
  9. data/gemfiles/rails.4.0.activerecord.gemfile +1 -0
  10. data/gemfiles/rails.4.1.activerecord.gemfile +1 -0
  11. data/gemfiles/rails.4.2.activerecord.gemfile +1 -0
  12. data/gemfiles/{rails.4.2.mongoid.5.1.gemfile → rails.4.2.mongoid.5.2.gemfile} +2 -1
  13. data/gemfiles/rails.5.0.activerecord.gemfile +2 -1
  14. data/gemfiles/{rails.5.0.mongoid.6.0.gemfile → rails.5.0.mongoid.6.1.gemfile} +3 -2
  15. data/gemfiles/rails.5.1.activerecord.gemfile +2 -1
  16. data/gemfiles/{rails.5.1.mongoid.6.1.gemfile → rails.5.1.mongoid.6.3.gemfile} +3 -2
  17. data/gemfiles/rails.5.2.activerecord.gemfile +16 -0
  18. data/gemfiles/sequel.4.45.gemfile +2 -2
  19. data/lib/chewy.rb +1 -0
  20. data/lib/chewy/config.rb +8 -19
  21. data/lib/chewy/fields/base.rb +15 -3
  22. data/lib/chewy/fields/root.rb +13 -9
  23. data/lib/chewy/index.rb +1 -1
  24. data/lib/chewy/index/actions.rb +14 -12
  25. data/lib/chewy/index/settings.rb +2 -0
  26. data/lib/chewy/index/specification.rb +12 -10
  27. data/lib/chewy/minitest/helpers.rb +6 -6
  28. data/lib/chewy/minitest/search_index_receiver.rb +17 -17
  29. data/lib/chewy/query.rb +135 -96
  30. data/lib/chewy/query/filters.rb +20 -3
  31. data/lib/chewy/query/loading.rb +0 -1
  32. data/lib/chewy/railtie.rb +2 -4
  33. data/lib/chewy/rake_helper.rb +5 -5
  34. data/lib/chewy/rspec/update_index.rb +3 -5
  35. data/lib/chewy/search.rb +2 -2
  36. data/lib/chewy/search/parameters/concerns/query_storage.rb +4 -3
  37. data/lib/chewy/stash.rb +30 -21
  38. data/lib/chewy/strategy/atomic.rb +1 -1
  39. data/lib/chewy/type.rb +2 -2
  40. data/lib/chewy/type/adapter/base.rb +9 -9
  41. data/lib/chewy/type/adapter/mongoid.rb +1 -3
  42. data/lib/chewy/type/adapter/sequel.rb +4 -6
  43. data/lib/chewy/type/crutch.rb +1 -1
  44. data/lib/chewy/type/import.rb +3 -2
  45. data/lib/chewy/type/import/bulk_builder.rb +1 -1
  46. data/lib/chewy/type/import/journal_builder.rb +3 -3
  47. data/lib/chewy/type/import/routine.rb +2 -2
  48. data/lib/chewy/type/mapping.rb +40 -34
  49. data/lib/chewy/type/observe.rb +13 -9
  50. data/lib/chewy/type/syncer.rb +2 -2
  51. data/lib/chewy/type/witchcraft.rb +2 -2
  52. data/lib/chewy/type/wrapper.rb +2 -2
  53. data/lib/chewy/version.rb +1 -1
  54. data/lib/sequel/plugins/chewy_observe.rb +4 -19
  55. data/spec/chewy/config_spec.rb +16 -0
  56. data/spec/chewy/fields/base_spec.rb +61 -65
  57. data/spec/chewy/fields/root_spec.rb +13 -13
  58. data/spec/chewy/index/actions_spec.rb +37 -5
  59. data/spec/chewy/index/specification_spec.rb +25 -16
  60. data/spec/chewy/index_spec.rb +61 -8
  61. data/spec/chewy/journal_spec.rb +11 -11
  62. data/spec/chewy/query/filters_spec.rb +1 -1
  63. data/spec/chewy/query/nodes/not_spec.rb +1 -0
  64. data/spec/chewy/query_spec.rb +3 -2
  65. data/spec/chewy/rake_helper_spec.rb +46 -33
  66. data/spec/chewy/search_spec.rb +20 -10
  67. data/spec/chewy/stash_spec.rb +1 -1
  68. data/spec/chewy/strategy/shoryuken_spec.rb +2 -0
  69. data/spec/chewy/type/import/journal_builder_spec.rb +8 -8
  70. data/spec/chewy/type/import_spec.rb +6 -0
  71. data/spec/chewy/type/mapping_spec.rb +48 -17
  72. data/spec/spec_helper.rb +8 -0
  73. metadata +26 -25
@@ -6,6 +6,7 @@ gem "activerecord", "~> 4.0.0"
6
6
  gem "activesupport", "~> 4.0.0"
7
7
  gem "resque", require: false
8
8
  gem "shoryuken", require: false
9
+ gem "aws-sdk-sqs", require: false
9
10
  gem "sidekiq", require: false
10
11
  gem "kaminari", "~> 0.17.0", require: false
11
12
  gem "will_paginate", require: false
@@ -6,6 +6,7 @@ gem "activerecord", "~> 4.1.0"
6
6
  gem "activesupport", "~> 4.1.0"
7
7
  gem "resque", require: false
8
8
  gem "shoryuken", require: false
9
+ gem "aws-sdk-sqs", require: false
9
10
  gem "sidekiq", require: false
10
11
  gem "kaminari", "~> 0.17.0", require: false
11
12
  gem "will_paginate", require: false
@@ -7,6 +7,7 @@ gem "activesupport", "~> 4.2.0"
7
7
  gem "activejob", "~> 4.2.0"
8
8
  gem "resque", require: false
9
9
  gem "shoryuken", require: false
10
+ gem "aws-sdk-sqs", require: false
10
11
  gem "sidekiq", require: false
11
12
  gem "kaminari", "~> 0.17.0", require: false
12
13
  gem "will_paginate", require: false
@@ -2,11 +2,12 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "mongoid", "~> 5.1.0"
5
+ gem "mongoid", "~> 5.2.0"
6
6
  gem "activesupport", "~> 4.2.0"
7
7
  gem "activejob", "~> 4.2.0"
8
8
  gem "resque", require: false
9
9
  gem "shoryuken", require: false
10
+ gem "aws-sdk-sqs", require: false
10
11
  gem "sidekiq", require: false
11
12
  gem "kaminari", "~> 0.17.0", require: false
12
13
  gem "will_paginate", require: false
@@ -7,8 +7,9 @@ gem "activesupport", "~> 5.0.0"
7
7
  gem "activejob", "~> 5.0.0"
8
8
  gem "resque", require: false
9
9
  gem "shoryuken", require: false
10
+ gem "aws-sdk-sqs", require: false
10
11
  gem "sidekiq", require: false
11
- gem "kaminari-core", "~> 1.0.0", require: false
12
+ gem "kaminari-core", "~> 1.1.0", require: false
12
13
  gem "will_paginate", require: false
13
14
  gem "parallel", require: false
14
15
 
@@ -2,13 +2,14 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "mongoid", "~> 6.0.0"
5
+ gem "mongoid", "~> 6.1.0"
6
6
  gem "activesupport", "~> 5.0.0"
7
7
  gem "activejob", "~> 5.0.0"
8
8
  gem "resque", require: false
9
9
  gem "shoryuken", require: false
10
+ gem "aws-sdk-sqs", require: false
10
11
  gem "sidekiq", require: false
11
- gem "kaminari-core", "~> 1.0.0", require: false
12
+ gem "kaminari-core", "~> 1.1.0", require: false
12
13
  gem "will_paginate", require: false
13
14
  gem "parallel", require: false
14
15
 
@@ -7,8 +7,9 @@ gem "activesupport", "~> 5.1.0"
7
7
  gem "activejob", "~> 5.1.0"
8
8
  gem "resque", require: false
9
9
  gem "shoryuken", require: false
10
+ gem "aws-sdk-sqs", require: false
10
11
  gem "sidekiq", require: false
11
- gem "kaminari-core", "~> 1.0.0", require: false
12
+ gem "kaminari-core", "~> 1.1.0", require: false
12
13
  gem "will_paginate", require: false
13
14
  gem "parallel", require: false
14
15
 
@@ -2,13 +2,14 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "mongoid", "~> 6.1.0"
5
+ gem "mongoid", "~> 6.3.0"
6
6
  gem "activesupport", "~> 5.1.0"
7
7
  gem "activejob", "~> 5.1.0"
8
8
  gem "resque", require: false
9
9
  gem "shoryuken", require: false
10
+ gem "aws-sdk-sqs", require: false
10
11
  gem "sidekiq", require: false
11
- gem "kaminari-core", "~> 1.0.0", require: false
12
+ gem "kaminari-core", "~> 1.1.0", require: false
12
13
  gem "will_paginate", require: false
13
14
  gem "parallel", require: false
14
15
 
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.2.0.rc1"
6
+ gem "activesupport", "~> 5.2.0.rc1"
7
+ gem "activejob", "~> 5.2.0.rc1"
8
+ gem "resque", require: false
9
+ gem "shoryuken", require: false
10
+ gem "aws-sdk-sqs", require: false
11
+ gem "sidekiq", require: false
12
+ gem "kaminari-core", "~> 1.1.0", require: false
13
+ gem "will_paginate", require: false
14
+ gem "parallel", require: false
15
+
16
+ gemspec path: "../"
@@ -3,8 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "sequel", "~> 4.45.0"
6
- gem "activesupport", "~> 5.0.0"
7
- gem "kaminari-core", "~> 1.0.0", require: false
6
+ gem "activesupport", "~> 5.1.0"
7
+ gem "kaminari-core", "~> 1.1.0", require: false
8
8
  gem "will_paginate", require: false
9
9
  gem "parallel", require: false
10
10
 
@@ -17,6 +17,7 @@ require 'active_support/core_ext/string/inflections'
17
17
  require 'i18n/core_ext/hash'
18
18
  require 'chewy/backports/deep_dup' unless Object.respond_to?(:deep_dup)
19
19
  require 'singleton'
20
+ require 'base64'
20
21
 
21
22
  require 'elasticsearch'
22
23
 
@@ -2,65 +2,54 @@ module Chewy
2
2
  class Config
3
3
  include Singleton
4
4
 
5
- attr_accessor :settings, :transport_logger, :transport_tracer, :logger,
6
-
5
+ attr_accessor :settings, :logger,
7
6
  # Default query compilation mode. `:must` by default.
8
7
  # See Chewy::Query#query_mode for details
9
8
  #
10
9
  :query_mode,
11
-
12
10
  # Default filters compilation mode. `:and` by default.
13
11
  # See Chewy::Query#filter_mode for details
14
12
  #
15
13
  :filter_mode,
16
-
17
14
  # Default post_filters compilation mode. `nil` by default.
18
15
  # See Chewy::Query#post_filter_mode for details
19
16
  #
20
17
  :post_filter_mode,
21
-
22
18
  # The first strategy in stack. `:base` by default.
23
19
  # If you need to return to the previous chewy behavior -
24
20
  # just set it to `:bypass`
25
21
  #
26
22
  :root_strategy,
27
-
28
23
  # Default request strategy middleware, used in e.g
29
24
  # Rails controllers. See Chewy::Railtie::RequestStrategy
30
25
  # for more info.
31
26
  #
32
27
  :request_strategy,
33
-
34
28
  # Use after_commit callbacks for RDBMS instead of
35
29
  # after_save and after_destroy. True by default. Useful
36
30
  # in tests with transactional fixtures or transactional
37
31
  # DatabaseCleaner strategy.
38
32
  #
39
33
  :use_after_commit_callbacks,
40
-
41
34
  # Where Chewy expects to find index definitions
42
35
  # within a Rails app folder.
43
36
  :indices_path,
44
-
45
37
  # Set index refresh_interval setting to -1 before reset and put the original value after.
46
38
  # If setting not present, put back to default 1s
47
39
  # https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
48
40
  :reset_disable_refresh_interval,
49
-
50
41
  # Set number_of_replicas to 0 before reset and put the original value after
51
42
  # https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html
52
43
  :reset_no_replicas,
53
-
54
44
  # Refresh or not when import async (sidekiq, resque, activejob)
55
45
  :disable_refresh_async,
56
-
57
46
  # Default options for root of Chewy type. Allows to set default options
58
47
  # for type mappings like `_all`.
59
48
  :default_root_options,
60
-
61
49
  # Default field type for any field in any Chewy type. Defaults to 'string'.
62
- :default_field_type,
50
+ :default_field_type
63
51
 
52
+ attr_reader :transport_logger, :transport_tracer,
64
53
  # Chewy search request DSL base class, used by every index.
65
54
  :search_class
66
55
 
@@ -80,7 +69,7 @@ module Chewy
80
69
  @disable_refresh_async = false
81
70
  @indices_path = 'app/chewy'
82
71
  @default_root_options = {}
83
- @default_field_type = 'string'.freeze
72
+ @default_field_type = 'text'.freeze
84
73
  self.search_class = Chewy::Search::Request
85
74
  end
86
75
 
@@ -124,7 +113,7 @@ module Chewy
124
113
  #
125
114
  # :wait_for_status - if this option set - chewy actions such
126
115
  # as creating or deleting index, importing data will wait for
127
- # the status specified. Extremely useful for tests under havy
116
+ # the status specified. Extremely useful for tests under heavy
128
117
  # indexes manipulations.
129
118
  #
130
119
  # test:
@@ -153,7 +142,7 @@ module Chewy
153
142
 
154
143
  def yaml_settings
155
144
  @yaml_settings ||= begin
156
- if defined?(Rails)
145
+ if defined?(Rails::VERSION)
157
146
  file = Rails.root.join('config', 'chewy.yml')
158
147
 
159
148
  if File.exist?(file)
@@ -168,9 +157,9 @@ module Chewy
168
157
  def build_search_class(base)
169
158
  Class.new(base).tap do |search_class|
170
159
  if defined?(::Kaminari)
171
- search_class.include Chewy::Search::Pagination::Kaminari
160
+ search_class.send :include, Chewy::Search::Pagination::Kaminari
172
161
  elsif defined?(::WillPaginate)
173
- search_class.include Chewy::Search::Pagination::WillPaginate
162
+ search_class.send :include, Chewy::Search::Pagination::WillPaginate
174
163
  end
175
164
  end
176
165
  end
@@ -4,13 +4,18 @@ module Chewy
4
4
  attr_reader :name, :options, :value, :children
5
5
  attr_accessor :parent
6
6
 
7
- def initialize(name, options = {})
7
+ def initialize(name, value: nil, **options)
8
8
  @name = name.to_sym
9
- @options = options.deep_symbolize_keys
10
- @value = @options.delete(:value)
9
+ @options = {}
10
+ update_options!(options)
11
+ @value = value
11
12
  @children = []
12
13
  end
13
14
 
15
+ def update_options!(**options)
16
+ @options = options
17
+ end
18
+
14
19
  def multi_field?
15
20
  children.present? && !object_field?
16
21
  end
@@ -28,6 +33,13 @@ module Chewy
28
33
  end
29
34
  mapping.reverse_merge!(options)
30
35
  mapping.reverse_merge!(type: (children.present? ? 'object' : Chewy.default_field_type))
36
+
37
+ # This is done to support ES2 journaling and will be removed soon
38
+ if mapping[:type] == 'keyword' && Chewy::Runtime.version < '5.0'
39
+ mapping[:type] = 'string'
40
+ mapping[:index] = 'not_analyzed'
41
+ end
42
+
31
43
  {name => mapping}
32
44
  end
33
45
 
@@ -6,15 +6,18 @@ module Chewy
6
6
  attr_reader :parent
7
7
  attr_reader :parent_id
8
8
 
9
- def initialize(*args)
10
- super(*args)
9
+ def initialize(*)
10
+ super
11
11
 
12
- @id = @options.delete(:id) || options.delete(:_id)
13
- @parent = @options.delete(:parent) || options.delete(:_parent)
14
- @parent_id = @options.delete(:parent_id)
15
12
  @value ||= -> { self }
16
13
  @dynamic_templates = []
17
- @options.delete(:type)
14
+ end
15
+
16
+ def update_options!(**options)
17
+ @id = options.fetch(:id, options.fetch(:_id, @id))
18
+ @parent = options.fetch(:parent, options.fetch(:_parent, @parent))
19
+ @parent_id = options.fetch(:parent_id, @parent_id)
20
+ @options.merge!(options.except(:id, :_id, :parent, :_parent, :parent_id, :type))
18
21
  end
19
22
 
20
23
  def mappings_hash
@@ -66,7 +69,8 @@ module Chewy
66
69
  # @param object [Object] a base object for composition
67
70
  # @param crutches [Object] any object that will be passed to every field value proc as a last argument
68
71
  # @param fields [Array<Symbol>] a list of fields to compose, every field will be composed if empty
69
- # @return [Hash] JSON-ready heash with stringifyed keys
72
+ # @return [Hash] JSON-ready hash with stringified keys
73
+ #
70
74
  def compose(object, crutches = nil, fields: [])
71
75
  result = evaluate([object, crutches])
72
76
 
@@ -81,9 +85,9 @@ module Chewy
81
85
  memo.merge!(field.compose(result, crutches) || {})
82
86
  end.as_json
83
87
  elsif fields.present?
84
- result.as_json(only: fields)
88
+ result.as_json(only: fields, root: false)
85
89
  else
86
- result.as_json
90
+ result.as_json(root: false)
87
91
  end
88
92
  end
89
93
 
@@ -52,7 +52,7 @@ module Chewy
52
52
  # @return [String] result index name
53
53
  def index_name(suggest = nil, prefix: nil, suffix: nil)
54
54
  if suggest
55
- @base_name = suggest.to_s.underscore.presence
55
+ @base_name = suggest.to_s.presence
56
56
  else
57
57
  [
58
58
  prefix || prefix_with_deprecation,
@@ -57,14 +57,9 @@ module Chewy
57
57
  general_name = index_name
58
58
  suffixed_name = index_name(suffix: suffix)
59
59
 
60
- if Chewy::Runtime.version >= 1.1
61
- body = specification_hash
62
- body[:aliases] = {general_name => {}} if options[:alias] && suffixed_name != general_name
63
- result = client.indices.create(index: suffixed_name, body: body)
64
- else
65
- result = client.indices.create(index: suffixed_name, body: specification_hash)
66
- result &&= client.indices.put_alias(index: suffixed_name, name: general_name) if options[:alias] && name != index_name
67
- end
60
+ body = specification_hash
61
+ body[:aliases] = {general_name => {}} if options[:alias] && suffixed_name != general_name
62
+ result = client.indices.create(index: suffixed_name, body: body)
68
63
 
69
64
  Chewy.wait_for_status if result
70
65
  result
@@ -140,8 +135,15 @@ module Chewy
140
135
  #
141
136
  %i[import import!].each do |method|
142
137
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
143
- def #{method} options = {}
144
- objects = options.reject { |k, v| !type_names.map(&:to_sym).include?(k) }
138
+ def #{method}(*args)
139
+ options = args.extract_options!
140
+ if args.one? && type_names.one?
141
+ objects = {type_names.first.to_sym => args.first}
142
+ elsif args.one?
143
+ fail ArgumentError, "Please pass objects for `#{method}` as a hash with type names"
144
+ else
145
+ objects = options.reject { |k, v| !type_names.map(&:to_sym).include?(k) }
146
+ end
145
147
  types.map do |type|
146
148
  args = [objects[type.type_name.to_sym], options.dup].reject(&:blank?)
147
149
  type.#{method} *args
@@ -164,7 +166,7 @@ module Chewy
164
166
  # @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime
165
167
  # @param suffix [String] a suffix for the newly created index
166
168
  # @param apply_journal [true, false] if true, journal is applied after the import is completed
167
- # @param journal [true, false] journalig is switched off for import during reset by default
169
+ # @param journal [true, false] journaling is switched off for import during reset by default
168
170
  # @param import_options [Hash] options, passed to the import call
169
171
  # @return [true, false] false in case of errors
170
172
  def reset!(suffix = nil, apply_journal: true, journal: false, **import_options)
@@ -231,7 +233,7 @@ module Chewy
231
233
  end
232
234
 
233
235
  def index_settings(setting_name)
234
- return {} unless settings_hash.key?(:settings) || settings_hash[:settings].key?(:index)
236
+ return {} unless settings_hash.key?(:settings) && settings_hash[:settings].key?(:index)
235
237
  settings_hash[:settings][:index].slice(setting_name)
236
238
  end
237
239
  end
@@ -4,12 +4,14 @@ module Chewy
4
4
  # hash. At first, you need to store some analyzers or other
5
5
  # analysis options to the corresponding repository:
6
6
  #
7
+ # @example
7
8
  # Chewy.analyzer :title_analyzer, type: 'custom', filter: %w(lowercase icu_folding title_nysiis)
8
9
  # Chewy.filter :title_nysiis, type: 'phonetic', encoder: 'nysiis', replace: false
9
10
  #
10
11
  # `title_nysiis` filter here will be expanded automatically when
11
12
  # `title_analyzer` analyser will be used in index settings:
12
13
  #
14
+ # @example
13
15
  # class ProductsIndex < Chewy::Index
14
16
  # settings analysis: {
15
17
  # analyzer: [
@@ -2,21 +2,21 @@ module Chewy
2
2
  class Index
3
3
  # Index specification is a combination of index settings and
4
4
  # mappings. The idea behind this class is that specification
5
- # can be locked in the `Chewy::Stash` between resets, so it is
6
- # possible to track changes. In the future it is planned to
7
- # be way smarter but right now `rake chewy:deploy` checks
8
- # if there were changes and resets the index only if anything
9
- # was changed. Otherwise, the index reset is skipped.
5
+ # can be locked in the `Chewy::Stash::Specification` between
6
+ # resets, so it is possible to track changes. In the future
7
+ # it is planned to be way smarter but right now `rake chewy:deploy`
8
+ # checks if there were changes and resets the index only if
9
+ # anything was changed. Otherwise, the index reset is skipped.
10
10
  #
11
- # @see Chewy::Stash
11
+ # @see Chewy::Stash::Specification
12
12
  class Specification
13
- # @see Chewy::Index.specification
13
+ # @see Chewy::Index::Specification
14
14
  # @param index [Chewy::Index] Just a chewy index
15
15
  def initialize(index)
16
16
  @index = index
17
17
  end
18
18
 
19
- # Stores the current index specification to the `Chewy::Stash`
19
+ # Stores the current index specification to the `Chewy::Stash::Specification`
20
20
  # as json.
21
21
  #
22
22
  # @raise [Chewy::ImportFailed] if something went wrong
@@ -24,7 +24,7 @@ module Chewy
24
24
  def lock!
25
25
  Chewy::Stash::Specification.import!([
26
26
  id: @index.derivable_name,
27
- value: current.to_json
27
+ specification: Base64.encode64(current.to_json)
28
28
  ], journal: false)
29
29
  end
30
30
 
@@ -34,7 +34,9 @@ module Chewy
34
34
  # @return [Hash] hash produced with JSON parser
35
35
  def locked
36
36
  filter = {ids: {values: [@index.derivable_name]}}
37
- JSON.parse(Chewy::Stash::Specification.filter(filter).first.try!(:value) || '{}')
37
+ document = Chewy::Stash::Specification.filter(filter).first
38
+ return {} unless document
39
+ JSON.load(Base64.decode64(document.specification)) # rubocop:disable Security/JSONLoad
38
40
  end
39
41
 
40
42
  # Simply returns `Chewy::Index.specification_hash`, but