chewy 0.8.2 → 0.8.3
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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Appraisals +2 -2
- data/CHANGELOG.md +22 -0
- data/gemfiles/{sequel.4.23.gemfile → sequel.4.28.gemfile} +1 -1
- data/lib/chewy.rb +0 -14
- data/lib/chewy/railtie.rb +1 -1
- data/lib/chewy/rspec/update_index.rb +1 -1
- data/lib/chewy/strategy/atomic.rb +1 -1
- data/lib/chewy/type/adapter/active_record.rb +4 -8
- data/lib/chewy/type/adapter/base.rb +1 -6
- data/lib/chewy/type/adapter/mongoid.rb +1 -1
- data/lib/chewy/type/adapter/orm.rb +21 -9
- data/lib/chewy/type/adapter/sequel.rb +38 -86
- data/lib/chewy/type/import.rb +11 -11
- data/lib/chewy/type/mapping.rb +4 -5
- data/lib/chewy/version.rb +1 -1
- data/lib/sequel/plugins/chewy_observe.rb +8 -1
- data/spec/chewy/query/criteria_spec.rb +4 -4
- data/spec/chewy/strategy/atomic_spec.rb +59 -0
- data/spec/chewy/type/adapter/active_record_spec.rb +19 -43
- data/spec/chewy/type/adapter/mongoid_spec.rb +17 -41
- data/spec/chewy/type/adapter/object_spec.rb +0 -13
- data/spec/chewy/type/adapter/sequel_spec.rb +295 -21
- data/spec/chewy/type/import_spec.rb +11 -0
- data/spec/chewy_spec.rb +0 -15
- data/spec/support/class_helpers.rb +4 -0
- data/spec/support/sequel.rb +7 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 366a83f019d42b9edab700ebfa189d949f5937fb
|
4
|
+
data.tar.gz: 65c60e5fa14b6f96b9cd13e49ba752ad64b7a271
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbee3534a08ddc5c0a3080d159602c1d1d334657abc321f5ef87fdfdc2729e13a97febd9686193f578b1845b083556893865df05dbd058cfa9874819af46d3b8
|
7
|
+
data.tar.gz: 0257820ba35319dc0b8a1bd9b21f15acec62ca57701abbf35a49f0fc37a5999ee0875fc8dc043d1bc844a44ca0b7f36b636c3408ff2db01d35e78124e229b4e1
|
data/.travis.yml
CHANGED
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -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
|
data/lib/chewy.rb
CHANGED
@@ -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
|
data/lib/chewy/railtie.rb
CHANGED
@@ -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
|
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].
|
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.
|
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(
|
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.
|
103
|
+
end.index_by { |object| object.public_send(primary_key).to_s }
|
104
104
|
|
105
|
-
objects.map { |object| loaded_objects[object.
|
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.
|
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.
|
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 <
|
7
|
-
|
8
|
-
|
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 ||
|
12
|
+
target.is_a?(Class) && target < ::Sequel::Model ||
|
13
|
+
target.is_a?(::Sequel::Dataset))
|
13
14
|
end
|
14
15
|
|
15
|
-
def
|
16
|
-
|
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
|
-
|
24
|
-
|
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
|
-
|
44
|
-
import_options = args.extract_options!
|
45
|
-
batch_size = import_options[:batch_size] || BATCH_SIZE
|
26
|
+
private
|
46
27
|
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
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
|
-
|
36
|
+
def import_scope(scope, batch_size)
|
37
|
+
scope = scope.unordered.order(::Sequel.asc(primary_key)).limit(batch_size)
|
76
38
|
|
77
|
-
|
78
|
-
|
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
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
95
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
51
|
+
def primary_key
|
52
|
+
target.primary_key
|
53
|
+
end
|
103
54
|
|
104
|
-
|
55
|
+
def pluck_ids(scope)
|
56
|
+
scope.distinct.select_map(primary_key)
|
105
57
|
end
|
106
58
|
|
107
|
-
def
|
108
|
-
|
59
|
+
def scope_where_ids_in(scope, ids)
|
60
|
+
scope.where(primary_key => Array.wrap(ids))
|
109
61
|
end
|
110
62
|
|
111
|
-
def
|
112
|
-
|
63
|
+
def model_of_relation relation
|
64
|
+
relation.model
|
113
65
|
end
|
114
66
|
|
115
|
-
def
|
116
|
-
|
67
|
+
def relation_class
|
68
|
+
::Sequel::Dataset
|
117
69
|
end
|
118
70
|
|
119
|
-
def
|
120
|
-
|
71
|
+
def object_class
|
72
|
+
::Sequel::Model
|
121
73
|
end
|
122
74
|
end
|
123
75
|
end
|
data/lib/chewy/type/import.rb
CHANGED
@@ -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 =
|
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
|
90
|
-
entry[:_id] =
|
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
|
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
|
110
|
-
entry[:_id] =
|
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
|
119
|
-
entry[:parent] =
|
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
|
-
|
153
|
+
build_root.compose(object, crutches)[type_name.to_sym]
|
154
154
|
end
|
155
155
|
|
156
156
|
def extract_errors result
|