chewy 0.6.2 → 0.7.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +35 -29
- data/Appraisals +37 -0
- data/CHANGELOG.md +115 -4
- data/Gemfile +2 -3
- data/README.md +135 -40
- data/chewy.gemspec +4 -3
- data/gemfiles/rails.3.2.activerecord.gemfile +13 -0
- data/gemfiles/rails.3.2.activerecord.kaminari.gemfile +14 -0
- data/gemfiles/rails.3.2.activerecord.will_paginate.gemfile +14 -0
- data/gemfiles/rails.4.0.activerecord.gemfile +13 -0
- data/gemfiles/rails.4.0.activerecord.kaminari.gemfile +14 -0
- data/gemfiles/rails.4.0.activerecord.will_paginate.gemfile +14 -0
- data/gemfiles/rails.4.0.mongoid.gemfile +13 -0
- data/gemfiles/rails.4.0.mongoid.kaminari.gemfile +14 -0
- data/gemfiles/rails.4.0.mongoid.will_paginate.gemfile +14 -0
- data/gemfiles/rails.4.1.activerecord.gemfile +13 -0
- data/gemfiles/rails.4.1.activerecord.kaminari.gemfile +14 -0
- data/gemfiles/rails.4.1.activerecord.will_paginate.gemfile +14 -0
- data/gemfiles/rails.4.1.mongoid.gemfile +13 -0
- data/gemfiles/rails.4.1.mongoid.kaminari.gemfile +14 -0
- data/gemfiles/rails.4.1.mongoid.will_paginate.gemfile +14 -0
- data/gemfiles/rails.4.2.activerecord.gemfile +13 -0
- data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +14 -0
- data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +14 -0
- data/gemfiles/rails.4.2.mongoid.gemfile +13 -0
- data/gemfiles/rails.4.2.mongoid.kaminari.gemfile +14 -0
- data/gemfiles/rails.4.2.mongoid.will_paginate.gemfile +14 -0
- data/lib/chewy.rb +65 -0
- data/lib/chewy/config.rb +44 -93
- data/lib/chewy/errors.rb +14 -5
- data/lib/chewy/fields/base.rb +8 -7
- data/lib/chewy/fields/root.rb +2 -2
- data/lib/chewy/index.rb +7 -9
- data/lib/chewy/log_subscriber.rb +34 -0
- data/lib/chewy/query.rb +41 -27
- data/lib/chewy/query/criteria.rb +28 -23
- data/lib/chewy/query/scoping.rb +20 -0
- data/lib/chewy/railtie.rb +51 -13
- data/lib/chewy/repository.rb +61 -0
- data/lib/chewy/rspec/update_index.rb +3 -6
- data/lib/chewy/search.rb +28 -7
- data/lib/chewy/strategy.rb +60 -0
- data/lib/chewy/strategy/atomic.rb +31 -0
- data/lib/chewy/strategy/base.rb +27 -0
- data/lib/chewy/strategy/bypass.rb +15 -0
- data/lib/chewy/strategy/urgent.rb +17 -0
- data/lib/chewy/type.rb +19 -5
- data/lib/chewy/type/adapter/active_record.rb +28 -117
- data/lib/chewy/type/adapter/base.rb +35 -0
- data/lib/chewy/type/adapter/mongoid.rb +23 -123
- data/lib/chewy/type/adapter/object.rb +41 -19
- data/lib/chewy/type/adapter/orm.rb +142 -0
- data/lib/chewy/type/import.rb +43 -16
- data/lib/chewy/type/observe.rb +8 -21
- data/lib/chewy/version.rb +1 -1
- data/lib/tasks/chewy.rake +8 -4
- data/spec/chewy/config_spec.rb +20 -97
- data/spec/chewy/fields/base_spec.rb +24 -11
- data/spec/chewy/fields/time_fields_spec.rb +27 -0
- data/spec/chewy/index/settings_spec.rb +2 -1
- data/spec/chewy/index_spec.rb +98 -79
- data/spec/chewy/query/criteria_spec.rb +14 -0
- data/spec/chewy/query_spec.rb +1 -1
- data/spec/chewy/repository_spec.rb +50 -0
- data/spec/chewy/search_spec.rb +100 -0
- data/spec/chewy/strategy_spec.rb +109 -0
- data/spec/chewy/type/adapter/active_record_spec.rb +110 -46
- data/spec/chewy/type/adapter/mongoid_spec.rb +123 -74
- data/spec/chewy/type/adapter/object_spec.rb +51 -34
- data/spec/chewy/type/import_spec.rb +21 -21
- data/spec/chewy/type/observe_spec.rb +26 -29
- data/spec/chewy/type_spec.rb +19 -0
- data/spec/chewy_spec.rb +19 -3
- data/spec/spec_helper.rb +1 -1
- data/spec/support/active_record.rb +2 -1
- data/spec/support/mongoid.rb +29 -38
- metadata +85 -55
- data/gemfiles/Gemfile.rails-3.2.active_record +0 -6
- data/gemfiles/Gemfile.rails-3.2.active_record.kaminari +0 -7
- data/gemfiles/Gemfile.rails-3.2.active_record.will_paginate +0 -7
- data/gemfiles/Gemfile.rails-4.0.active_record +0 -6
- data/gemfiles/Gemfile.rails-4.0.active_record.kaminari +0 -7
- data/gemfiles/Gemfile.rails-4.0.active_record.will_paginate +0 -7
- data/gemfiles/Gemfile.rails-4.0.mongoid +0 -6
- data/gemfiles/Gemfile.rails-4.0.mongoid.kaminari +0 -7
- data/gemfiles/Gemfile.rails-4.0.mongoid.will_paginate +0 -7
- data/gemfiles/Gemfile.rails-4.1.active_record +0 -6
- data/gemfiles/Gemfile.rails-4.1.active_record.kaminari +0 -7
- data/gemfiles/Gemfile.rails-4.1.active_record.will_paginate +0 -7
- data/gemfiles/Gemfile.rails-4.1.mongoid +0 -6
- data/gemfiles/Gemfile.rails-4.1.mongoid.kaminari +0 -7
- data/gemfiles/Gemfile.rails-4.1.mongoid.will_paginate +0 -7
- data/gemfiles/Gemfile.rails-4.2.active_record +0 -6
- data/gemfiles/Gemfile.rails-4.2.active_record.kaminari +0 -7
- data/gemfiles/Gemfile.rails-4.2.active_record.will_paginate +0 -7
- data/gemfiles/Gemfile.rails-4.2.mongoid +0 -6
- data/gemfiles/Gemfile.rails-4.2.mongoid.kaminari +0 -7
- data/gemfiles/Gemfile.rails-4.2.mongoid.will_paginate +0 -7
- data/spec/chewy/index/search_spec.rb +0 -46
|
@@ -5,6 +5,8 @@ module Chewy
|
|
|
5
5
|
class Base
|
|
6
6
|
BATCH_SIZE = 1000
|
|
7
7
|
|
|
8
|
+
attr_reader :target, :options
|
|
9
|
+
|
|
8
10
|
# Camelcased name, used as type class constant name.
|
|
9
11
|
# For returned value 'Product' will be generated class name `ProductsIndex::Product`
|
|
10
12
|
#
|
|
@@ -20,6 +22,14 @@ module Chewy
|
|
|
20
22
|
@type_name ||= name.underscore
|
|
21
23
|
end
|
|
22
24
|
|
|
25
|
+
# Returns shortest identifies for further postponed importing.
|
|
26
|
+
# For ORM/ODM it will be an array of ids for simple objects -
|
|
27
|
+
# just objects themselves
|
|
28
|
+
#
|
|
29
|
+
def identify collection
|
|
30
|
+
raise NotImplementedError
|
|
31
|
+
end
|
|
32
|
+
|
|
23
33
|
# Splits passed objects to groups according to `:batch_size` options.
|
|
24
34
|
# For every group crates hash with action keys. Example:
|
|
25
35
|
#
|
|
@@ -40,6 +50,31 @@ module Chewy
|
|
|
40
50
|
def load *args
|
|
41
51
|
raise NotImplementedError
|
|
42
52
|
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def grouped_objects(objects)
|
|
57
|
+
objects.group_by do |object|
|
|
58
|
+
delete_from_index?(object) ? :delete : :index
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def delete_from_index?(object)
|
|
63
|
+
if object.respond_to?(:delete_from_index?)
|
|
64
|
+
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`')
|
|
65
|
+
delete = object.delete_from_index?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
delete_if = options[:delete_if]
|
|
69
|
+
delete ||= case delete_if
|
|
70
|
+
when Symbol, String
|
|
71
|
+
object.send delete_if
|
|
72
|
+
when Proc
|
|
73
|
+
delete_if.arity == 1 ? delete_if.call(object) : object.instance_exec(&delete_if)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
!!delete
|
|
77
|
+
end
|
|
43
78
|
end
|
|
44
79
|
end
|
|
45
80
|
end
|
|
@@ -1,145 +1,45 @@
|
|
|
1
|
-
require 'chewy/type/adapter/
|
|
1
|
+
require 'chewy/type/adapter/orm'
|
|
2
2
|
|
|
3
3
|
module Chewy
|
|
4
4
|
class Type
|
|
5
5
|
module Adapter
|
|
6
|
-
class Mongoid <
|
|
7
|
-
|
|
8
|
-
@options = args.extract_options!
|
|
9
|
-
subject = args.first
|
|
10
|
-
if subject.is_a?(::Mongoid::Criteria)
|
|
11
|
-
@model = subject.klass
|
|
12
|
-
@scope = subject
|
|
13
|
-
else
|
|
14
|
-
@model = subject
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def name
|
|
19
|
-
@name ||= (options[:name].present? ? options[:name].to_s.camelize : model.model_name.to_s).demodulize
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Import method for Mongoid takes import data and import options
|
|
23
|
-
#
|
|
24
|
-
# Import data types:
|
|
25
|
-
#
|
|
26
|
-
# * Nothing passed - imports all the model data
|
|
27
|
-
# * ActiveRecord scope
|
|
28
|
-
# * Objects collection
|
|
29
|
-
# * Ids collection
|
|
30
|
-
#
|
|
31
|
-
# Import options:
|
|
32
|
-
#
|
|
33
|
-
# <tt>:batch_size</tt> - import batch size, 1000 objects by default
|
|
34
|
-
#
|
|
35
|
-
# Method handles destroyed objects as well. In case of objects AcriveRecord::Relation
|
|
36
|
-
# or array passed, objects, responding with true to `destroyed?` method will be deleted
|
|
37
|
-
# from index. In case of ids array passed - documents with missing records ids will be
|
|
38
|
-
# deleted from index:
|
|
39
|
-
#
|
|
40
|
-
# users = User.all
|
|
41
|
-
# users.each { |user| user.destroy if user.incative? }
|
|
42
|
-
# UsersIndex::User.import users # inactive users will be deleted from index
|
|
43
|
-
# # or
|
|
44
|
-
# UsersIndex::User.import users.map(&:id) # deleted user ids will be deleted from index
|
|
45
|
-
#
|
|
46
|
-
# Also there is custom API method `delete_from_index?`. It it returns `true`
|
|
47
|
-
# object will be deleted from index. Note that if this method is defined and
|
|
48
|
-
# return `false` Chewy will still check `destroyed?` method. This is useful
|
|
49
|
-
# for paranoid objects sdeleting implementation.
|
|
50
|
-
#
|
|
51
|
-
# class User
|
|
52
|
-
# alias_method :delete_from_index?, :deleted_at?
|
|
53
|
-
# end
|
|
54
|
-
#
|
|
55
|
-
# users = User.all
|
|
56
|
-
# users.each { |user| user.deleted_at = Time.now }
|
|
57
|
-
# UsersIndex::User.import users # paranoid deleted users will be deleted from index
|
|
58
|
-
# # or
|
|
59
|
-
# UsersIndex::User.import users.map(&:id) # user ids will be deleted from index
|
|
60
|
-
#
|
|
61
|
-
def import *args, &block
|
|
62
|
-
import_options = args.extract_options!
|
|
63
|
-
import_options[:batch_size] ||= BATCH_SIZE
|
|
64
|
-
batch_size = import_options[:batch_size]
|
|
65
|
-
|
|
66
|
-
collection = args.none? ? model_all :
|
|
67
|
-
(args.one? && args.first.is_a?(::Mongoid::Criteria) ? args.first : args.flatten.compact)
|
|
6
|
+
class Mongoid < Orm
|
|
7
|
+
private
|
|
68
8
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
result &= block.call grouped_objects(batch)
|
|
73
|
-
end
|
|
74
|
-
result
|
|
75
|
-
else
|
|
76
|
-
if collection.all? { |object| object.respond_to?(:id) }
|
|
77
|
-
collection.each_slice(batch_size).map do |group|
|
|
78
|
-
block.call grouped_objects(group)
|
|
79
|
-
end.all?
|
|
80
|
-
else
|
|
81
|
-
import_ids(collection, import_options, &block)
|
|
82
|
-
end
|
|
9
|
+
def cleanup_default_scope!
|
|
10
|
+
if Chewy.logger && @default_scope.options.values_at(:sort, :limit, :skip).compact.present?
|
|
11
|
+
Chewy.logger.warn('Default type scope order, limit and offest are ignored and will be nullified')
|
|
83
12
|
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def load *args
|
|
87
|
-
load_options = args.extract_options!
|
|
88
|
-
objects = args.flatten
|
|
89
|
-
|
|
90
|
-
additional_scope = load_options[load_options[:_type].type_name.to_sym].try(:[], :scope) || load_options[:scope]
|
|
91
13
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
elsif additional_scope.is_a?(::Mongoid::Criteria)
|
|
96
|
-
scope.merge(additional_scope)
|
|
97
|
-
else
|
|
98
|
-
scope
|
|
99
|
-
end.index_by { |object| object.id.to_s }
|
|
100
|
-
|
|
101
|
-
objects.map { |object| loaded_objects[object.id.to_s] }
|
|
14
|
+
@default_scope = @default_scope.reorder(nil)
|
|
15
|
+
@default_scope.options.delete(:limit)
|
|
16
|
+
@default_scope.options.delete(:skip)
|
|
102
17
|
end
|
|
103
18
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def import_ids(ids, import_options = {}, &block)
|
|
109
|
-
ids.uniq!
|
|
110
|
-
batch_size = import_options[:batch_size] || BATCH_SIZE
|
|
111
|
-
|
|
112
|
-
indexed = true
|
|
113
|
-
merged_scope(scoped_model(ids)).batch_size(batch_size).no_timeout.each_slice(batch_size) do |batch|
|
|
114
|
-
ids -= batch.map(&:id)
|
|
115
|
-
indexed &= block.call(grouped_objects(batch))
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
deleted = ids.each_slice(batch_size).map do |group|
|
|
119
|
-
block.call(delete: group)
|
|
19
|
+
def import_scope(scope, batch_size)
|
|
20
|
+
scope.batch_size(batch_size).no_timeout.pluck(:_id).each_slice(batch_size).map do |ids|
|
|
21
|
+
yield grouped_objects(default_scope_where_ids_in(ids))
|
|
120
22
|
end.all?
|
|
23
|
+
end
|
|
121
24
|
|
|
122
|
-
|
|
25
|
+
def pluck_ids(scope)
|
|
26
|
+
scope.pluck(:_id)
|
|
123
27
|
end
|
|
124
28
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
delete = object.delete_from_index? if object.respond_to?(:delete_from_index?)
|
|
128
|
-
delete ||= object.destroyed?
|
|
129
|
-
delete ? :delete : :index
|
|
130
|
-
end
|
|
29
|
+
def scope_where_ids_in(scope, ids)
|
|
30
|
+
scope.where(:_id.in => ids)
|
|
131
31
|
end
|
|
132
32
|
|
|
133
|
-
def
|
|
134
|
-
|
|
33
|
+
def all_scope
|
|
34
|
+
target.all
|
|
135
35
|
end
|
|
136
36
|
|
|
137
|
-
def
|
|
138
|
-
|
|
37
|
+
def relation_class
|
|
38
|
+
::Mongoid::Criteria
|
|
139
39
|
end
|
|
140
40
|
|
|
141
|
-
def
|
|
142
|
-
|
|
41
|
+
def object_class
|
|
42
|
+
::Mongoid::Document
|
|
143
43
|
end
|
|
144
44
|
end
|
|
145
45
|
end
|
|
@@ -10,7 +10,11 @@ module Chewy
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def name
|
|
13
|
-
@name ||= (options[:name] || target).to_s.camelize.demodulize
|
|
13
|
+
@name ||= (options[:name] || @target).to_s.camelize.demodulize
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def identify collection
|
|
17
|
+
Array.wrap(collection)
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
# Imports passed data with options
|
|
@@ -23,31 +27,30 @@ module Chewy
|
|
|
23
27
|
#
|
|
24
28
|
# <tt>:batch_size</tt> - import batch size, 1000 objects by default
|
|
25
29
|
#
|
|
26
|
-
# If
|
|
27
|
-
#
|
|
28
|
-
# destroyed objects need to respond to `id` method as well, so
|
|
29
|
-
# could know which one to delete.
|
|
30
|
+
# If method `destroyed?` is defined for object and returns true or object
|
|
31
|
+
# satisfy `delete_if` type option then object will be deleted from index.
|
|
32
|
+
# But to be destroyed objects need to respond to `id` method as well, so
|
|
33
|
+
# ElasticSearch could know which one to delete.
|
|
30
34
|
#
|
|
31
35
|
def import *args, &block
|
|
32
36
|
import_options = args.extract_options!
|
|
33
37
|
batch_size = import_options.delete(:batch_size) || BATCH_SIZE
|
|
34
|
-
objects = args.flatten.compact
|
|
35
38
|
|
|
36
|
-
objects.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
delete ||= object.destroyed? if object.respond_to?(:destroyed?)
|
|
41
|
-
delete ? :delete : :index
|
|
42
|
-
end
|
|
43
|
-
block.call action_groups
|
|
44
|
-
end.all?
|
|
39
|
+
objects = args.empty? && @target.respond_to?(import_all_method) ?
|
|
40
|
+
@target.send(import_all_method) : args.flatten.compact
|
|
41
|
+
|
|
42
|
+
import_objects(objects, batch_size, &block)
|
|
45
43
|
end
|
|
46
44
|
|
|
47
45
|
def load *args
|
|
48
46
|
load_options = args.extract_options!
|
|
49
47
|
objects = args.flatten
|
|
50
|
-
if
|
|
48
|
+
if target.respond_to?(load_all_method)
|
|
49
|
+
target.send(load_all_method, objects)
|
|
50
|
+
elsif target.respond_to?(load_one_method)
|
|
51
|
+
objects.map { |object| target.send(load_one_method, object) }
|
|
52
|
+
elsif target.respond_to?(:wrap)
|
|
53
|
+
ActiveSupport::Deprecation.warn('Loading with `wrap` method is deprecated. Rename it to `load_one` or pass `load_one_method: :my_load_method` option to `define_type`')
|
|
51
54
|
objects.map { |object| target.wrap(object) }
|
|
52
55
|
else
|
|
53
56
|
objects
|
|
@@ -56,10 +59,29 @@ module Chewy
|
|
|
56
59
|
|
|
57
60
|
private
|
|
58
61
|
|
|
59
|
-
|
|
62
|
+
def import_objects(objects, batch_size)
|
|
63
|
+
objects.each_slice(batch_size).map do |group|
|
|
64
|
+
yield grouped_objects(group)
|
|
65
|
+
end.all?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def delete_from_index?(object)
|
|
69
|
+
delete = super
|
|
70
|
+
delete ||= object.destroyed? if object.respond_to?(:destroyed?)
|
|
71
|
+
delete ||= object[:_destroyed] || object['_destroyed'] if object.is_a?(Hash)
|
|
72
|
+
!!delete
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def import_all_method
|
|
76
|
+
@import_all_method ||= options[:import_all_method] || :call
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def load_all_method
|
|
80
|
+
@load_all_method ||= options[:load_all_method] || :load_all
|
|
81
|
+
end
|
|
60
82
|
|
|
61
|
-
def
|
|
62
|
-
@
|
|
83
|
+
def load_one_method
|
|
84
|
+
@load_one_method ||= options[:load_one_method] || :load_one
|
|
63
85
|
end
|
|
64
86
|
end
|
|
65
87
|
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
require 'chewy/type/adapter/base'
|
|
2
|
+
|
|
3
|
+
module Chewy
|
|
4
|
+
class Type
|
|
5
|
+
module Adapter
|
|
6
|
+
class Orm < Base
|
|
7
|
+
attr_reader :default_scope
|
|
8
|
+
|
|
9
|
+
def initialize *args
|
|
10
|
+
@options = args.extract_options!
|
|
11
|
+
class_or_relation = args.first
|
|
12
|
+
if class_or_relation.is_a?(relation_class)
|
|
13
|
+
@target = class_or_relation.klass
|
|
14
|
+
@default_scope = class_or_relation
|
|
15
|
+
else
|
|
16
|
+
@target = class_or_relation
|
|
17
|
+
@default_scope = all_scope
|
|
18
|
+
end
|
|
19
|
+
cleanup_default_scope!
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def name
|
|
23
|
+
@name ||= (options[:name].present? ? options[:name].to_s.camelize : target.model_name.to_s).demodulize
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def identify collection
|
|
27
|
+
ids = if collection.is_a?(relation_class)
|
|
28
|
+
pluck_ids(collection)
|
|
29
|
+
else
|
|
30
|
+
Array.wrap(collection).map do |entity|
|
|
31
|
+
entity.is_a?(object_class) ? entity.id : entity
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Import method for ORM takes import data and import options
|
|
37
|
+
#
|
|
38
|
+
# Import data types:
|
|
39
|
+
#
|
|
40
|
+
# * Nothing passed - imports all the model data according to type
|
|
41
|
+
# default scope
|
|
42
|
+
# * ORM scope
|
|
43
|
+
# * Objects collection
|
|
44
|
+
# * Ids collection
|
|
45
|
+
#
|
|
46
|
+
# Import options:
|
|
47
|
+
#
|
|
48
|
+
# <tt>:batch_size</tt> - import batch size, 1000 objects by default
|
|
49
|
+
#
|
|
50
|
+
# Method handles destroyed objects as well. In case of objects ORM scope
|
|
51
|
+
# or array passed, objects, responding with true to `destroyed?` method will be deleted
|
|
52
|
+
# from index. In case of ids array passed - documents with missing records ids will be
|
|
53
|
+
# deleted from index:
|
|
54
|
+
#
|
|
55
|
+
# users = User.all
|
|
56
|
+
# users.each { |user| user.destroy if user.incative? }
|
|
57
|
+
# UsersIndex::User.import users # inactive users will be deleted from index
|
|
58
|
+
# # or
|
|
59
|
+
# UsersIndex::User.import users.map(&:id) # deleted user ids will be deleted from index
|
|
60
|
+
#
|
|
61
|
+
# Also there is custom type option `delete_if`. It it returns `true`
|
|
62
|
+
# object will be deleted from index. Note that if this option is defined and
|
|
63
|
+
# return `false` Chewy will still check `destroyed?` method. This is useful
|
|
64
|
+
# for paranoid objects deleting implementation.
|
|
65
|
+
#
|
|
66
|
+
# define_type User, delete_if: ->{ deleted_at } do
|
|
67
|
+
# ...
|
|
68
|
+
# end
|
|
69
|
+
#
|
|
70
|
+
# users = User.all
|
|
71
|
+
# users.each { |user| user.deleted_at = Time.now }
|
|
72
|
+
# UsersIndex::User.import users # paranoid deleted users will be deleted from index
|
|
73
|
+
# # or
|
|
74
|
+
# UsersIndex::User.import users.map(&:id) # user ids will be deleted from index
|
|
75
|
+
#
|
|
76
|
+
def import *args, &block
|
|
77
|
+
import_options = args.extract_options!
|
|
78
|
+
batch_size = import_options[:batch_size] || BATCH_SIZE
|
|
79
|
+
|
|
80
|
+
collection = args.empty? ? default_scope :
|
|
81
|
+
(args.one? && args.first.is_a?(relation_class) ? args.first : args.flatten.compact)
|
|
82
|
+
|
|
83
|
+
if collection.is_a?(relation_class)
|
|
84
|
+
import_scope(collection, batch_size, &block)
|
|
85
|
+
else
|
|
86
|
+
import_objects(collection, batch_size, &block)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def load *args
|
|
91
|
+
load_options = args.extract_options!
|
|
92
|
+
objects = args.flatten
|
|
93
|
+
|
|
94
|
+
additional_scope = load_options[load_options[:_type].type_name.to_sym].try(:[], :scope) || load_options[:scope]
|
|
95
|
+
|
|
96
|
+
scope = all_scope_where_ids_in(objects.map(&:id))
|
|
97
|
+
loaded_objects = if additional_scope.is_a?(Proc)
|
|
98
|
+
scope.instance_exec(&additional_scope)
|
|
99
|
+
elsif additional_scope.is_a?(relation_class)
|
|
100
|
+
scope.merge(additional_scope)
|
|
101
|
+
else
|
|
102
|
+
scope
|
|
103
|
+
end.index_by { |object| object.id.to_s }
|
|
104
|
+
|
|
105
|
+
objects.map { |object| loaded_objects[object.id.to_s] }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def import_objects(collection, batch_size)
|
|
111
|
+
hash = collection.index_by do |entity|
|
|
112
|
+
entity.is_a?(object_class) ? entity.id : entity
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
indexed = hash.keys.each_slice(batch_size).map do |ids|
|
|
116
|
+
batch = default_scope_where_ids_in(ids)
|
|
117
|
+
if batch.empty?
|
|
118
|
+
true
|
|
119
|
+
else
|
|
120
|
+
batch.each { |object| hash.delete(object.id) }
|
|
121
|
+
yield grouped_objects(batch)
|
|
122
|
+
end
|
|
123
|
+
end.all?
|
|
124
|
+
|
|
125
|
+
deleted = hash.keys.each_slice(batch_size).map do |group|
|
|
126
|
+
yield delete: hash.values_at(*group)
|
|
127
|
+
end.all?
|
|
128
|
+
|
|
129
|
+
indexed && deleted
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def default_scope_where_ids_in(ids)
|
|
133
|
+
scope_where_ids_in(default_scope, ids)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def all_scope_where_ids_in(ids)
|
|
137
|
+
scope_where_ids_in(all_scope, ids)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|