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