chewy 0.10.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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