chewy 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 465b8f0c2bff702e61235bbd9b6782f3f57296e6
4
- data.tar.gz: 60827a551d9b4338ee87a91c346b84cfbcca6aa2
3
+ metadata.gz: 366a83f019d42b9edab700ebfa189d949f5937fb
4
+ data.tar.gz: 65c60e5fa14b6f96b9cd13e49ba752ad64b7a271
5
5
  SHA512:
6
- metadata.gz: e0efb611f827fa291ea9f3765d14e50450e6787f0541e9c04f034d79e20189cdb8dd718e2c8c8074e7736ac3575018e13fe9317f880d7b6d0429ac1ab060e6b2
7
- data.tar.gz: 0270d359d7831c3f1c0217369f32d5017c7b90e7871780a5e79f7945414c7a3aaadf39f1505ab85c7a3c61a1f2fbb28ae49c183034f43c12d1ed065cf66e9acf
6
+ metadata.gz: dbee3534a08ddc5c0a3080d159602c1d1d334657abc321f5ef87fdfdc2729e13a97febd9686193f578b1845b083556893865df05dbd058cfa9874819af46d3b8
7
+ data.tar.gz: 0257820ba35319dc0b8a1bd9b21f15acec62ca57701abbf35a49f0fc37a5999ee0875fc8dc043d1bc844a44ca0b7f36b636c3408ff2db01d35e78124e229b4e1
@@ -29,7 +29,7 @@ gemfile:
29
29
  - gemfiles/rails.4.2.mongoid.gemfile
30
30
  - gemfiles/rails.4.2.mongoid.kaminari.gemfile
31
31
  - gemfiles/rails.4.2.mongoid.will_paginate.gemfile
32
- - gemfiles/sequel.4.23.gemfile
32
+ - gemfiles/sequel.4.28.gemfile
33
33
  matrix:
34
34
  exclude:
35
35
  - rvm: 2.2
data/Appraisals CHANGED
@@ -43,7 +43,7 @@ end
43
43
  end
44
44
  end
45
45
 
46
- appraise "sequel.4.23" do
47
- gem 'sequel', "~> 4.23.0"
46
+ appraise "sequel.4.28" do
47
+ gem 'sequel', "~> 4.28.0"
48
48
  gem 'activesupport', '~> 4.2.0'
49
49
  end
@@ -1,5 +1,27 @@
1
1
  # master
2
2
 
3
+ ## Changes
4
+
5
+ * Sequel support completely reworked to use common ORM implementations + better sequel specs covarage.
6
+
7
+ ## Bugfixes
8
+
9
+ * Sequel objects transactional destruction fix
10
+
11
+ * Correct Rspec mocking framework checking (@mainameiz)
12
+
13
+ * Atomic strategy is now compatible with custom ids proc.
14
+
15
+ * Safe unsubscribe on import (@marshall-lee)
16
+
17
+ * Correct custom assets path silencer (@davekaro)
18
+
19
+ ## Incompatible changes:
20
+
21
+ * `Chewy.atomic` and `Chewy.urgent_update=` methods was removed from the codebase, use `Chewy.strategy` block instead.
22
+
23
+ * `delete_from_index?` hook is removed from the codebase.
24
+
3
25
  # Version 0.8.2
4
26
 
5
27
  ## Changes
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "sequel", "~> 4.23.0"
5
+ gem "sequel", "~> 4.28.0"
6
6
  gem "activesupport", "~> 4.2.0"
7
7
 
8
8
  group :test do
@@ -179,20 +179,6 @@ module Chewy
179
179
  end
180
180
  end
181
181
 
182
- def urgent_update= value
183
- ActiveSupport::Deprecation.warn('`Chewy.urgent_update = value` is deprecated and will be removed soon, use `Chewy.strategy(:urgent)` block instead')
184
- if value
185
- strategy(:urgent)
186
- else
187
- strategy.pop
188
- end
189
- end
190
-
191
- def atomic &block
192
- ActiveSupport::Deprecation.warn('`Chewy.atomic` block is deprecated and will be removed soon, use `Chewy.strategy(:atomic)` block instead')
193
- strategy(:atomic, &block)
194
- end
195
-
196
182
  def config
197
183
  Chewy::Config.instance
198
184
  end
@@ -10,7 +10,7 @@ module Chewy
10
10
  end
11
11
 
12
12
  def call(env)
13
- if env['PATH_INFO'].start_with?('/assets/')
13
+ if env['PATH_INFO'].start_with?(Rails.application.config.assets.prefix)
14
14
  @app.call(env)
15
15
  else
16
16
  Chewy.strategy(Chewy.request_strategy) { @app.call(env) }
@@ -194,7 +194,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}|
194
194
  end
195
195
 
196
196
  def agnostic_stub
197
- if defined? Mocha
197
+ if defined?(Mocha) && RSpec.configuration.mock_framework.to_s == 'RSpec::Core::MockingAdapters::Mocha'
198
198
  "type.stubs(:bulk).with"
199
199
  else
200
200
  "allow(type).to receive(:bulk)"
@@ -20,7 +20,7 @@ module Chewy
20
20
  ActiveSupport::Deprecation.warn("`urgent: true` option is deprecated and is not effective inside `:atomic` strategy, use `Chewy.strategy(:urgent)` strategy instead") if options.key?(:urgent)
21
21
 
22
22
  @stash[type] ||= []
23
- @stash[type] |= type.adapter.identify(objects)
23
+ @stash[type] |= type.send(:build_root).id ? Array.wrap(objects) : type.adapter.identify(objects)
24
24
  end
25
25
 
26
26
  def leave
@@ -37,6 +37,10 @@ module Chewy
37
37
  result
38
38
  end
39
39
 
40
+ def target_id
41
+ target.arel_table[target.primary_key]
42
+ end
43
+
40
44
  def pluck_ids(scope)
41
45
  scope.except(:includes).uniq.pluck(target.primary_key.to_sym)
42
46
  end
@@ -45,14 +49,6 @@ module Chewy
45
49
  scope.where(target_id.in(Array.wrap(ids)))
46
50
  end
47
51
 
48
- def all_scope
49
- target.where(nil)
50
- end
51
-
52
- def target_id
53
- target.arel_table[target.primary_key]
54
- end
55
-
56
52
  def relation_class
57
53
  ::ActiveRecord::Relation
58
54
  end
@@ -60,17 +60,12 @@ module Chewy
60
60
  private
61
61
 
62
62
  def grouped_objects(objects)
63
- objects.group_by do |object|
63
+ objects.to_a.group_by do |object|
64
64
  delete_from_index?(object) ? :delete : :index
65
65
  end
66
66
  end
67
67
 
68
68
  def delete_from_index?(object)
69
- if object.respond_to?(:delete_from_index?)
70
- ActiveSupport::Deprecation.warn('`delete_from_index?` method in models is deprecated and will be removed soon. Use per-type `delete_if` option for `define_type`')
71
- delete = object.delete_from_index?
72
- end
73
-
74
69
  delete_if = options[:delete_if]
75
70
  delete ||= case delete_if
76
71
  when Symbol, String
@@ -22,9 +22,9 @@ module Chewy
22
22
  Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified')
23
23
  end
24
24
 
25
- @default_scope = @default_scope.reorder(nil)
26
25
  @default_scope.options.delete(:limit)
27
26
  @default_scope.options.delete(:skip)
27
+ @default_scope = @default_scope.reorder(nil)
28
28
  end
29
29
 
30
30
  def import_scope(scope, batch_size)
@@ -10,7 +10,7 @@ module Chewy
10
10
  @options = args.extract_options!
11
11
  class_or_relation = args.first
12
12
  if class_or_relation.is_a?(relation_class)
13
- @target = class_or_relation.klass
13
+ @target = model_of_relation(class_or_relation)
14
14
  @default_scope = class_or_relation
15
15
  else
16
16
  @target = class_or_relation
@@ -20,7 +20,7 @@ module Chewy
20
20
  end
21
21
 
22
22
  def name
23
- @name ||= (options[:name].present? ? options[:name].to_s.camelize : target.model_name.to_s).demodulize
23
+ @name ||= (options[:name].presence || target.name).to_s.camelize.demodulize
24
24
  end
25
25
 
26
26
  def identify collection
@@ -28,7 +28,7 @@ module Chewy
28
28
  pluck_ids(collection)
29
29
  else
30
30
  Array.wrap(collection).map do |entity|
31
- entity.is_a?(object_class) ? entity.id : entity
31
+ entity.is_a?(object_class) ? entity.public_send(primary_key) : entity
32
32
  end
33
33
  end
34
34
  end
@@ -93,23 +93,23 @@ module Chewy
93
93
 
94
94
  additional_scope = load_options[load_options[:_type].type_name.to_sym].try(:[], :scope) || load_options[:scope]
95
95
 
96
- scope = all_scope_where_ids_in(objects.map(&:id))
96
+ scope = all_scope_where_ids_in(objects.map(&primary_key))
97
97
  loaded_objects = if additional_scope.is_a?(Proc)
98
98
  scope.instance_exec(&additional_scope)
99
- elsif additional_scope.is_a?(relation_class)
99
+ elsif additional_scope.is_a?(relation_class) && scope.respond_to?(:merge)
100
100
  scope.merge(additional_scope)
101
101
  else
102
102
  scope
103
- end.index_by { |object| object.id.to_s }
103
+ end.index_by { |object| object.public_send(primary_key).to_s }
104
104
 
105
- objects.map { |object| loaded_objects[object.id.to_s] }
105
+ objects.map { |object| loaded_objects[object.public_send(primary_key).to_s] }
106
106
  end
107
107
 
108
108
  private
109
109
 
110
110
  def import_objects(collection, batch_size)
111
111
  hash = collection.index_by do |entity|
112
- entity.is_a?(object_class) ? entity.id : entity
112
+ entity.is_a?(object_class) ? entity.public_send(primary_key) : entity
113
113
  end
114
114
 
115
115
  indexed = hash.keys.each_slice(batch_size).map do |ids|
@@ -117,7 +117,7 @@ module Chewy
117
117
  if batch.empty?
118
118
  true
119
119
  else
120
- batch.each { |object| hash.delete(object.id) }
120
+ batch.each { |object| hash.delete(object.public_send(primary_key)) }
121
121
  yield grouped_objects(batch)
122
122
  end
123
123
  end.all?
@@ -129,6 +129,10 @@ module Chewy
129
129
  indexed && deleted
130
130
  end
131
131
 
132
+ def primary_key
133
+ :id
134
+ end
135
+
132
136
  def default_scope_where_ids_in(ids)
133
137
  scope_where_ids_in(default_scope, ids)
134
138
  end
@@ -136,6 +140,14 @@ module Chewy
136
140
  def all_scope_where_ids_in(ids)
137
141
  scope_where_ids_in(all_scope, ids)
138
142
  end
143
+
144
+ def all_scope
145
+ target.where(nil)
146
+ end
147
+
148
+ def model_of_relation relation
149
+ relation.klass
150
+ end
139
151
  end
140
152
  end
141
153
  end
@@ -3,121 +3,73 @@ require 'chewy/type/adapter/base'
3
3
  module Chewy
4
4
  class Type
5
5
  module Adapter
6
- class Sequel < Base
7
-
8
- attr_reader :default_dataset
6
+ class Sequel < Orm
7
+ attr_reader :default_scope
8
+ alias_method :default_dataset, :default_scope
9
9
 
10
10
  def self.accepts?(target)
11
11
  defined?(::Sequel::Model) && (
12
- target.is_a?(Class) && target < ::Sequel::Model || target.is_a?(::Sequel::Dataset))
12
+ target.is_a?(Class) && target < ::Sequel::Model ||
13
+ target.is_a?(::Sequel::Dataset))
13
14
  end
14
15
 
15
- def initialize(*args)
16
- @options = args.extract_options!
17
-
18
- if dataset? args.first
19
- dataset = args.first
20
- @target = dataset.model
21
- @default_dataset = dataset.unordered.unlimited
16
+ def identify collection
17
+ if collection.is_a?(relation_class)
18
+ pluck_ids(collection)
22
19
  else
23
- model = args.first
24
- @target = model
25
- @default_dataset = model.where(nil)
26
- end
27
- end
28
-
29
- def name
30
- @name ||= (options[:name].presence || target.name).camelize.demodulize
31
- end
32
-
33
- def identify(obj)
34
- if dataset? obj
35
- obj.select_map(target_pk)
36
- else
37
- Array.wrap(obj).map do |item|
38
- model?(item) ? item.pk : item
20
+ Array.wrap(collection).map do |entity|
21
+ entity.is_a?(object_class) ? entity.public_send(primary_key) : entity
39
22
  end
40
23
  end
41
24
  end
42
25
 
43
- def import(*args, &block)
44
- import_options = args.extract_options!
45
- batch_size = import_options[:batch_size] || BATCH_SIZE
26
+ private
46
27
 
47
- if args.empty?
48
- import_dataset(default_dataset, batch_size, &block)
49
- elsif args.one? && dataset?(args.first)
50
- import_dataset(args.first, batch_size, &block)
51
- else
52
- import_models(args.flatten.compact, batch_size, &block)
28
+ def cleanup_default_scope!
29
+ if Chewy.logger && @default_scope != @default_scope.unordered.unlimited
30
+ Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified')
53
31
  end
54
- end
55
-
56
- def load(*args)
57
- load_options = args.extract_options!
58
- index_ids = args.flatten.map(&:id) # args contains index instances
59
-
60
- type_name = load_options[:_type].type_name.to_sym
61
- additional_scope = load_options[type_name].try(:[], :scope) || load_options[:scope]
62
-
63
- dataset = select_by_ids(target, index_ids)
64
32
 
65
- if additional_scope.is_a?(Proc)
66
- index_ids.map!(&:to_s)
67
- dataset.instance_exec(&additional_scope).to_a.select do |model|
68
- index_ids.include? model.pk.to_s
69
- end
70
- else
71
- dataset.to_a
72
- end
33
+ @default_scope = @default_scope.unordered.unlimited
73
34
  end
74
35
 
75
- private
36
+ def import_scope(scope, batch_size)
37
+ scope = scope.unordered.order(::Sequel.asc(primary_key)).limit(batch_size)
76
38
 
77
- def import_dataset(dataset, batch_size)
78
- dataset = dataset.limit(batch_size)
79
-
80
- dataset.db.transaction(isolation: :committed) do
81
- 0.step(Float::INFINITY, batch_size).lazy
82
- .map { |offset| dataset.offset(offset).to_a }
83
- .take_while(&:any?)
84
- .map { |items| yield grouped_objects(items) }
85
- .reduce(:&)
86
- end
87
- end
39
+ ids = pluck_ids(scope)
40
+ result = true
88
41
 
89
- def import_models(objects, batch_size)
90
- objects_by_id = objects.index_by do |item|
91
- model?(item) ? item.pk : item
42
+ while ids.any?
43
+ result &= yield grouped_objects(default_scope_where_ids_in(ids))
44
+ break if ids.size < batch_size
45
+ ids = pluck_ids(scope.where { |o| o.__send__(primary_key) > ids.last })
92
46
  end
93
47
 
94
- indexed = objects_by_id.keys.each_slice(batch_size).map do |ids|
95
- models = select_by_ids(default_dataset, ids).to_a
96
- models.each { |model| objects_by_id.delete(model.pk) }
97
- models.empty? || yield(grouped_objects(models))
98
- end
48
+ result
49
+ end
99
50
 
100
- deleted = objects_by_id.keys.each_slice(batch_size).map do |ids|
101
- yield delete: objects_by_id.values_at(*ids)
102
- end
51
+ def primary_key
52
+ target.primary_key
53
+ end
103
54
 
104
- indexed.all? && deleted.all?
55
+ def pluck_ids(scope)
56
+ scope.distinct.select_map(primary_key)
105
57
  end
106
58
 
107
- def select_by_ids(dataset, ids)
108
- dataset.where(target_pk => Array.wrap(ids))
59
+ def scope_where_ids_in(scope, ids)
60
+ scope.where(primary_key => Array.wrap(ids))
109
61
  end
110
62
 
111
- def target_pk
112
- target.primary_key
63
+ def model_of_relation relation
64
+ relation.model
113
65
  end
114
66
 
115
- def dataset?(obj)
116
- obj.is_a? ::Sequel::Dataset
67
+ def relation_class
68
+ ::Sequel::Dataset
117
69
  end
118
70
 
119
- def model?(obj)
120
- obj.is_a? ::Sequel::Model
71
+ def object_class
72
+ ::Sequel::Model
121
73
  end
122
74
  end
123
75
  end
@@ -22,11 +22,10 @@ module Chewy
22
22
  bulk_options = import_options.reject { |k, v| ![:refresh, :suffix].include?(k) }.reverse_merge!(refresh: true)
23
23
 
24
24
  index.create!(bulk_options.slice(:suffix)) unless index.exists?
25
- build_root unless self.root_object
26
25
 
27
26
  ActiveSupport::Notifications.instrument 'import_objects.chewy', type: self do |payload|
28
27
  adapter.import(*args, import_options) do |action_objects|
29
- indexed_objects = self.root_object.parent_id && fetch_indexed_objects(action_objects.values.flatten)
28
+ indexed_objects = build_root.parent_id && fetch_indexed_objects(action_objects.values.flatten)
30
29
  body = bulk_body(action_objects, indexed_objects)
31
30
 
32
31
  errors = bulk(bulk_options.merge(body: body)) if body.any?
@@ -57,9 +56,10 @@ module Chewy
57
56
  errors = args.last[:errors]
58
57
  end
59
58
  import *args
60
- ActiveSupport::Notifications.unsubscribe(subscriber)
61
59
  raise Chewy::ImportFailed.new(self, errors) if errors.present?
62
60
  true
61
+ ensure
62
+ ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
63
63
  end
64
64
 
65
65
  # Wraps elasticsearch-ruby client indices bulk method.
@@ -86,8 +86,8 @@ module Chewy
86
86
  def delete_bulk_entry(object, indexed_objects = nil, crutches = nil)
87
87
  entry = {}
88
88
 
89
- if self.root_object.id
90
- entry[:_id] = self.root_object.compose_id(object)
89
+ if root_object.id
90
+ entry[:_id] = root_object.compose_id(object)
91
91
  else
92
92
  entry[:_id] = object.id if object.respond_to?(:id)
93
93
  entry[:_id] ||= object[:id] || object['id'] if object.is_a?(Hash)
@@ -95,7 +95,7 @@ module Chewy
95
95
  entry[:_id] = entry[:_id].to_s if defined?(BSON) && entry[:_id].is_a?(BSON::ObjectId)
96
96
  end
97
97
 
98
- if self.root_object.parent_id
98
+ if root_object.parent_id
99
99
  existing_object = entry[:_id].present? && indexed_objects && indexed_objects[entry[:_id].to_s]
100
100
  entry.merge!(parent: existing_object[:parent]) if existing_object
101
101
  end
@@ -106,8 +106,8 @@ module Chewy
106
106
  def index_bulk_entry(object, indexed_objects = nil, crutches = nil)
107
107
  entry = {}
108
108
 
109
- if self.root_object.id
110
- entry[:_id] = self.root_object.compose_id(object)
109
+ if root_object.id
110
+ entry[:_id] = root_object.compose_id(object)
111
111
  else
112
112
  entry[:_id] = object.id if object.respond_to?(:id)
113
113
  entry[:_id] ||= object[:id] || object['id'] if object.is_a?(Hash)
@@ -115,8 +115,8 @@ module Chewy
115
115
  end
116
116
  entry.delete(:_id) if entry[:_id].blank?
117
117
 
118
- if self.root_object.parent_id
119
- entry[:parent] = self.root_object.compose_parent(object)
118
+ if root_object.parent_id
119
+ entry[:parent] = root_object.compose_parent(object)
120
120
  existing_object = entry[:_id].present? && indexed_objects && indexed_objects[entry[:_id].to_s]
121
121
  end
122
122
 
@@ -150,7 +150,7 @@ module Chewy
150
150
  end
151
151
 
152
152
  def object_data object, crutches = nil
153
- (self.root_object ||= build_root).compose(object, crutches)[type_name.to_sym]
153
+ build_root.compose(object, crutches)[type_name.to_sym]
154
154
  end
155
155
 
156
156
  def extract_errors result