chewy 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +26 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile +3 -1
- data/README.md +2 -10
- data/chewy.gemspec +0 -1
- data/gemfiles/Gemfile.rails-3.2.active_record +6 -0
- data/gemfiles/Gemfile.rails-3.2.active_record.kaminari +7 -0
- data/gemfiles/Gemfile.rails-3.2.active_record.will_paginate +7 -0
- data/gemfiles/Gemfile.rails-4.0.active_record +6 -0
- data/gemfiles/Gemfile.rails-4.0.active_record.kaminari +7 -0
- data/gemfiles/Gemfile.rails-4.0.active_record.will_paginate +7 -0
- data/gemfiles/Gemfile.rails-4.0.mongoid +6 -0
- data/gemfiles/Gemfile.rails-4.0.mongoid.kaminari +7 -0
- data/gemfiles/Gemfile.rails-4.0.mongoid.will_paginate +7 -0
- data/gemfiles/Gemfile.rails-4.1.active_record +6 -0
- data/gemfiles/Gemfile.rails-4.1.active_record.kaminari +7 -0
- data/gemfiles/Gemfile.rails-4.1.active_record.will_paginate +7 -0
- data/gemfiles/Gemfile.rails-4.1.mongoid +6 -0
- data/gemfiles/Gemfile.rails-4.1.mongoid.kaminari +7 -0
- data/gemfiles/Gemfile.rails-4.1.mongoid.will_paginate +7 -0
- data/gemfiles/Gemfile.rails-4.2.active_record +6 -0
- data/gemfiles/Gemfile.rails-4.2.active_record.kaminari +7 -0
- data/gemfiles/Gemfile.rails-4.2.active_record.will_paginate +7 -0
- data/gemfiles/Gemfile.rails-4.2.mongoid +6 -0
- data/gemfiles/Gemfile.rails-4.2.mongoid.kaminari +7 -0
- data/gemfiles/Gemfile.rails-4.2.mongoid.will_paginate +7 -0
- data/lib/chewy.rb +33 -5
- data/lib/chewy/config.rb +1 -0
- data/lib/chewy/index/search.rb +6 -3
- data/lib/chewy/query.rb +74 -1
- data/lib/chewy/query/compose.rb +4 -4
- data/lib/chewy/query/pagination.rb +5 -4
- data/lib/chewy/query/pagination/kaminari.rb +1 -1
- data/lib/chewy/query/pagination/will_paginate.rb +27 -0
- data/lib/chewy/type.rb +1 -0
- data/lib/chewy/type/adapter/active_record.rb +2 -2
- data/lib/chewy/type/adapter/mongoid.rb +147 -0
- data/lib/chewy/type/adapter/object.rb +1 -1
- data/lib/chewy/type/import.rb +1 -0
- data/lib/chewy/type/observe.rb +34 -6
- data/lib/chewy/version.rb +1 -1
- data/spec/chewy/config_spec.rb +17 -17
- data/spec/chewy/fields/base_spec.rb +62 -62
- data/spec/chewy/fields/root_spec.rb +5 -5
- data/spec/chewy/index/actions_spec.rb +127 -127
- data/spec/chewy/index/aliases_spec.rb +9 -9
- data/spec/chewy/index/search_spec.rb +4 -4
- data/spec/chewy/index/settings_spec.rb +33 -33
- data/spec/chewy/index_spec.rb +49 -49
- data/spec/chewy/query/criteria_spec.rb +173 -161
- data/spec/chewy/query/filters_spec.rb +76 -76
- data/spec/chewy/query/loading_spec.rb +54 -23
- data/spec/chewy/query/nodes/and_spec.rb +4 -4
- data/spec/chewy/query/nodes/bool_spec.rb +8 -8
- data/spec/chewy/query/nodes/equal_spec.rb +19 -19
- data/spec/chewy/query/nodes/exists_spec.rb +6 -6
- data/spec/chewy/query/nodes/has_child_spec.rb +25 -25
- data/spec/chewy/query/nodes/has_parent_spec.rb +25 -25
- data/spec/chewy/query/nodes/match_all_spec.rb +1 -1
- data/spec/chewy/query/nodes/missing_spec.rb +4 -4
- data/spec/chewy/query/nodes/not_spec.rb +4 -4
- data/spec/chewy/query/nodes/or_spec.rb +4 -4
- data/spec/chewy/query/nodes/prefix_spec.rb +5 -5
- data/spec/chewy/query/nodes/query_spec.rb +2 -2
- data/spec/chewy/query/nodes/range_spec.rb +18 -18
- data/spec/chewy/query/nodes/raw_spec.rb +1 -1
- data/spec/chewy/query/nodes/regexp_spec.rb +18 -18
- data/spec/chewy/query/nodes/script_spec.rb +4 -4
- data/spec/chewy/query/pagination/kaminari_spec.rb +41 -39
- data/spec/chewy/query/pagination/will_paginage_spec.rb +60 -0
- data/spec/chewy/query/pagination_spec.rb +8 -7
- data/spec/chewy/query_spec.rb +166 -167
- data/spec/chewy/rspec/update_index_spec.rb +1 -1
- data/spec/chewy/runtime/version_spec.rb +30 -30
- data/spec/chewy/runtime_spec.rb +3 -3
- data/spec/chewy/type/actions_spec.rb +3 -3
- data/spec/chewy/type/adapter/active_record_spec.rb +143 -143
- data/spec/chewy/type/adapter/mongoid_spec.rb +219 -0
- data/spec/chewy/type/adapter/object_spec.rb +39 -39
- data/spec/chewy/type/import_spec.rb +67 -37
- data/spec/chewy/type/mapping_spec.rb +12 -12
- data/spec/chewy/type/observe_spec.rb +5 -6
- data/spec/chewy/type/wrapper_spec.rb +12 -12
- data/spec/chewy_spec.rb +26 -28
- data/spec/spec_helper.rb +19 -31
- data/spec/support/active_record.rb +52 -0
- data/spec/support/class_helpers.rb +0 -4
- data/spec/support/mongoid.rb +87 -0
- metadata +33 -18
- data/gemfiles/Gemfile.rails-3.2 +0 -15
- data/gemfiles/Gemfile.rails-4.0 +0 -15
data/lib/chewy/query/compose.rb
CHANGED
@@ -30,11 +30,11 @@ module Chewy
|
|
30
30
|
def _queries_join queries, logic
|
31
31
|
queries = queries.compact
|
32
32
|
|
33
|
-
if queries.many?
|
33
|
+
if queries.many? || (queries.any? && logic == :must_not)
|
34
34
|
case logic
|
35
35
|
when :dis_max
|
36
36
|
{ dis_max: { queries: queries } }
|
37
|
-
when :must, :should
|
37
|
+
when :must, :should, :must_not
|
38
38
|
{ bool: { logic => queries } }
|
39
39
|
else
|
40
40
|
if logic.is_a?(Float)
|
@@ -51,11 +51,11 @@ module Chewy
|
|
51
51
|
def _filters_join filters, logic
|
52
52
|
filters = filters.compact
|
53
53
|
|
54
|
-
if filters.many?
|
54
|
+
if filters.many? || (filters.any? && logic == :must_not)
|
55
55
|
case logic
|
56
56
|
when :and, :or
|
57
57
|
{ logic => filters }
|
58
|
-
when :must, :should
|
58
|
+
when :must, :should, :must_not
|
59
59
|
{ bool: { logic => filters } }
|
60
60
|
else
|
61
61
|
{ bool: { should: filters, minimum_should_match: logic } }
|
@@ -3,13 +3,14 @@ module Chewy
|
|
3
3
|
module Pagination
|
4
4
|
# Returns request total found documents count
|
5
5
|
#
|
6
|
-
# PlacesIndex.query(...).filter(...).
|
6
|
+
# PlacesIndex.query(...).filter(...).total
|
7
7
|
#
|
8
|
-
def
|
8
|
+
def total
|
9
9
|
_response['hits'].try(:[], 'total') || 0
|
10
10
|
end
|
11
|
+
|
12
|
+
alias_method :total_count, :total
|
13
|
+
alias_method :total_entries, :total
|
11
14
|
end
|
12
15
|
end
|
13
16
|
end
|
14
|
-
|
15
|
-
require 'chewy/query/pagination/kaminari' if defined?(::Kaminari)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Chewy
|
2
|
+
class Query
|
3
|
+
module Pagination
|
4
|
+
module WillPaginate
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
include ::WillPaginate::CollectionMethods
|
7
|
+
|
8
|
+
attr_reader :current_page, :per_page
|
9
|
+
|
10
|
+
def paginate(options={})
|
11
|
+
@current_page = ::WillPaginate::PageNumber(options[:page] || @current_page || 1)
|
12
|
+
@page_multiplier = @current_page - 1
|
13
|
+
@per_page = (options[:per_page] || @per_page || ::WillPaginate.per_page).to_i
|
14
|
+
|
15
|
+
#call Chewy::Query methods to limit results
|
16
|
+
limit(@per_page).offset(@page_multiplier * @per_page)
|
17
|
+
end
|
18
|
+
|
19
|
+
def page(page)
|
20
|
+
paginate(page: page)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Chewy::Query.send :include, Chewy::Query::Pagination::WillPaginate
|
data/lib/chewy/type.rb
CHANGED
@@ -72,7 +72,7 @@ module Chewy
|
|
72
72
|
result
|
73
73
|
else
|
74
74
|
if collection.all? { |object| object.respond_to?(:id) }
|
75
|
-
collection.
|
75
|
+
collection.each_slice(import_options[:batch_size]).map do |group|
|
76
76
|
block.call grouped_objects(group)
|
77
77
|
end.all?
|
78
78
|
else
|
@@ -112,7 +112,7 @@ module Chewy
|
|
112
112
|
indexed &= block.call(grouped_objects(objects))
|
113
113
|
end
|
114
114
|
|
115
|
-
deleted = ids.
|
115
|
+
deleted = ids.each_slice(import_options[:batch_size]).map do |group|
|
116
116
|
block.call(delete: group)
|
117
117
|
end.all?
|
118
118
|
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'chewy/type/adapter/base'
|
2
|
+
|
3
|
+
module Chewy
|
4
|
+
class Type
|
5
|
+
module Adapter
|
6
|
+
class Mongoid < Base
|
7
|
+
def initialize *args
|
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)
|
68
|
+
|
69
|
+
if collection.is_a?(::Mongoid::Criteria)
|
70
|
+
result = true
|
71
|
+
merged_scope(collection).batch_size(batch_size).no_timeout.each_slice(batch_size) do |batch|
|
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
|
83
|
+
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
|
+
|
92
|
+
scope = scoped_model(objects.map(&:id))
|
93
|
+
loaded_objects = if additional_scope.is_a?(Proc)
|
94
|
+
scope.instance_exec(&additional_scope)
|
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] }
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
attr_reader :model, :scope, :options
|
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)
|
120
|
+
end.all?
|
121
|
+
|
122
|
+
indexed && deleted
|
123
|
+
end
|
124
|
+
|
125
|
+
def grouped_objects(objects)
|
126
|
+
objects.group_by do |object|
|
127
|
+
delete = object.delete_from_index? if object.respond_to?(:delete_from_index?)
|
128
|
+
delete ||= object.destroyed?
|
129
|
+
delete ? :delete : :index
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def merged_scope(target)
|
134
|
+
scope ? scope.clone.merge(target) : target
|
135
|
+
end
|
136
|
+
|
137
|
+
def scoped_model(ids)
|
138
|
+
model.where(:_id.in => ids)
|
139
|
+
end
|
140
|
+
|
141
|
+
def model_all
|
142
|
+
model.all
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -33,7 +33,7 @@ module Chewy
|
|
33
33
|
batch_size = import_options.delete(:batch_size) || BATCH_SIZE
|
34
34
|
objects = args.flatten.compact
|
35
35
|
|
36
|
-
objects.
|
36
|
+
objects.each_slice(batch_size).map do |group|
|
37
37
|
action_groups = group.group_by do |object|
|
38
38
|
raise "Object is not a `#{target}`" if class_target? && !object.is_a?(target)
|
39
39
|
delete = object.delete_from_index? if object.respond_to?(:delete_from_index?)
|
data/lib/chewy/type/import.rb
CHANGED
@@ -84,6 +84,7 @@ module Chewy
|
|
84
84
|
entry = {}
|
85
85
|
|
86
86
|
entry[:_id] = object.respond_to?(:id) ? object.id : object
|
87
|
+
entry[:_id] = entry[:_id].to_s if defined?(BSON) && entry[:_id].is_a?(BSON::ObjectId)
|
87
88
|
entry[:data] = object_data(object) unless action == :delete
|
88
89
|
|
89
90
|
if self.root_object.parent_id
|
data/lib/chewy/type/observe.rb
CHANGED
@@ -3,14 +3,35 @@ module Chewy
|
|
3
3
|
module Observe
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
+
module MongoidMethods
|
7
|
+
def update_index(type_name, *args, &block)
|
8
|
+
options = args.extract_options!
|
9
|
+
method = args.first
|
10
|
+
|
11
|
+
update = Proc.new do
|
12
|
+
backreference = if method && method.to_s == 'self'
|
13
|
+
self
|
14
|
+
elsif method
|
15
|
+
send(method)
|
16
|
+
else
|
17
|
+
instance_eval(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
Chewy.derive_type(type_name).update_index(backreference, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
after_save &update
|
24
|
+
after_destroy &update
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
6
28
|
module ActiveRecordMethods
|
7
29
|
def update_index(type_name, *args, &block)
|
8
30
|
options = args.extract_options!
|
9
31
|
method = args.first
|
10
32
|
|
11
33
|
update = Proc.new do
|
12
|
-
|
13
|
-
clear_association_cache if update_options[:urgent]
|
34
|
+
clear_association_cache if Chewy.urgent_update
|
14
35
|
|
15
36
|
backreference = if method && method.to_s == 'self'
|
16
37
|
self
|
@@ -20,7 +41,7 @@ module Chewy
|
|
20
41
|
instance_eval(&block)
|
21
42
|
end
|
22
43
|
|
23
|
-
Chewy.derive_type(type_name).update_index(backreference,
|
44
|
+
Chewy.derive_type(type_name).update_index(backreference, options)
|
24
45
|
end
|
25
46
|
|
26
47
|
after_save &update
|
@@ -31,14 +52,21 @@ module Chewy
|
|
31
52
|
module ClassMethods
|
32
53
|
def update_index(objects, options = {})
|
33
54
|
if Chewy.atomic?
|
34
|
-
|
55
|
+
relation = (defined?(::ActiveRecord) && objects.is_a?(::ActiveRecord::Relation)) ||
|
56
|
+
(defined?(::Mongoid) && objects.is_a?(::Mongoid::Criteria))
|
57
|
+
|
58
|
+
ids = if relation
|
35
59
|
objects.pluck(:id)
|
36
60
|
else
|
37
61
|
Array.wrap(objects).map { |object| object.respond_to?(:id) ? object.id : object.to_i }
|
38
62
|
end
|
63
|
+
|
39
64
|
Chewy.stash self, ids
|
40
|
-
|
41
|
-
|
65
|
+
elsif options[:urgent]
|
66
|
+
ActiveSupport::Deprecation.warn("`urgent: true` option is deprecated and will be removed soon, use `Chewy.atomic` block instead")
|
67
|
+
import(objects)
|
68
|
+
elsif Chewy.urgent_update
|
69
|
+
import(objects)
|
42
70
|
end if objects
|
43
71
|
|
44
72
|
true
|
data/lib/chewy/version.rb
CHANGED
data/spec/chewy/config_spec.rb
CHANGED
@@ -14,42 +14,42 @@ describe Chewy::Config do
|
|
14
14
|
its(:char_filters) { should == {} }
|
15
15
|
|
16
16
|
describe '#analyzer' do
|
17
|
-
specify { subject.analyzer(:name).
|
17
|
+
specify { expect(subject.analyzer(:name)).to be_nil }
|
18
18
|
|
19
19
|
context do
|
20
20
|
before { subject.analyzer(:name, option: :foo) }
|
21
|
-
specify { subject.analyzer(:name).
|
22
|
-
specify { subject.analyzers.
|
21
|
+
specify { expect(subject.analyzer(:name)).to eq({option: :foo}) }
|
22
|
+
specify { expect(subject.analyzers).to eq({name: {option: :foo}}) }
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
describe '#tokenizer' do
|
27
|
-
specify { subject.tokenizer(:name).
|
27
|
+
specify { expect(subject.tokenizer(:name)).to be_nil }
|
28
28
|
|
29
29
|
context do
|
30
30
|
before { subject.tokenizer(:name, option: :foo) }
|
31
|
-
specify { subject.tokenizer(:name).
|
32
|
-
specify { subject.tokenizers.
|
31
|
+
specify { expect(subject.tokenizer(:name)).to eq({option: :foo}) }
|
32
|
+
specify { expect(subject.tokenizers).to eq({name: {option: :foo}}) }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
describe '#filter' do
|
37
|
-
specify { subject.filter(:name).
|
37
|
+
specify { expect(subject.filter(:name)).to be_nil }
|
38
38
|
|
39
39
|
context do
|
40
40
|
before { subject.filter(:name, option: :foo) }
|
41
|
-
specify { subject.filter(:name).
|
42
|
-
specify { subject.filters.
|
41
|
+
specify { expect(subject.filter(:name)).to eq({option: :foo}) }
|
42
|
+
specify { expect(subject.filters).to eq({name: {option: :foo}}) }
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
describe '#char_filter' do
|
47
|
-
specify { subject.char_filter(:name).
|
47
|
+
specify { expect(subject.char_filter(:name)).to be_nil }
|
48
48
|
|
49
49
|
context do
|
50
50
|
before { subject.char_filter(:name, option: :foo) }
|
51
|
-
specify { subject.char_filter(:name).
|
52
|
-
specify { subject.char_filters.
|
51
|
+
specify { expect(subject.char_filter(:name)).to eq({option: :foo}) }
|
52
|
+
specify { expect(subject.char_filters).to eq({name: {option: :foo}}) }
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -62,8 +62,8 @@ describe Chewy::Config do
|
|
62
62
|
|
63
63
|
describe '#atomic?' do
|
64
64
|
its(:atomic?) { should eq(false) }
|
65
|
-
specify { subject.atomic { subject.atomic
|
66
|
-
specify { subject.atomic { }; subject.atomic
|
65
|
+
specify { subject.atomic { expect(subject.atomic?).to eq(true) } }
|
66
|
+
specify { subject.atomic { }; expect(subject.atomic?).to eq(false) }
|
67
67
|
end
|
68
68
|
|
69
69
|
describe '#atomic' do
|
@@ -74,9 +74,9 @@ describe Chewy::Config do
|
|
74
74
|
end
|
75
75
|
let(:dummy_type) { DummiesIndex::Dummy }
|
76
76
|
|
77
|
-
specify { subject.atomic { 42 }.
|
77
|
+
specify { expect(subject.atomic { 42 }).to eq(42) }
|
78
78
|
specify { expect { subject.atomic { subject.stash Class.new, 42 } }.to raise_error ArgumentError }
|
79
|
-
specify { subject.atomic { subject.atomic { subject.stash.
|
79
|
+
specify { subject.atomic { subject.atomic { expect(subject.stash).to eq([{}, {}]) } } }
|
80
80
|
|
81
81
|
specify do
|
82
82
|
expect(dummy_type).to receive(:import).with([1, 2, 3]).once
|
@@ -107,6 +107,6 @@ describe Chewy::Config do
|
|
107
107
|
end
|
108
108
|
|
109
109
|
describe '#stash' do
|
110
|
-
specify { subject.atomic { subject.stash.
|
110
|
+
specify { subject.atomic { expect(subject.stash).to eq([{}]) } }
|
111
111
|
end
|
112
112
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Chewy::Fields::Base do
|
4
|
-
specify { described_class.new('name').name.
|
5
|
-
specify { described_class.new('name', type: 'integer').options[:type].
|
4
|
+
specify { expect(described_class.new('name').name).to eq(:name) }
|
5
|
+
specify { expect(described_class.new('name', type: 'integer').options[:type]).to eq('integer') }
|
6
6
|
|
7
7
|
describe '#compose' do
|
8
8
|
let(:field) { described_class.new(:name, value: ->(o){ o.value }) }
|
9
9
|
|
10
|
-
specify { field.compose(double(value: 'hello')).
|
11
|
-
specify { field.compose(double(value: ['hello', 'world'])).
|
10
|
+
specify { expect(field.compose(double(value: 'hello'))).to eq({name: 'hello'}) }
|
11
|
+
specify { expect(field.compose(double(value: ['hello', 'world']))).to eq({name: ['hello', 'world']}) }
|
12
12
|
|
13
|
-
specify { described_class.new(:name).compose(double(name: 'hello')).
|
13
|
+
specify { expect(described_class.new(:name).compose(double(name: 'hello'))).to eq({name: 'hello'}) }
|
14
14
|
|
15
15
|
context do
|
16
16
|
before do
|
@@ -19,15 +19,15 @@ describe Chewy::Fields::Base do
|
|
19
19
|
field.nested(described_class.new(:subname3))
|
20
20
|
end
|
21
21
|
|
22
|
-
specify { field.compose(double(value: double(subvalue1: 'hello', subvalue2: 'value', subname3: 'world')))
|
23
|
-
.
|
24
|
-
specify { field.compose(double(value: [
|
22
|
+
specify { expect(field.compose(double(value: double(subvalue1: 'hello', subvalue2: 'value', subname3: 'world'))))
|
23
|
+
.to eq({name: {'subname1' => 'hello', 'subname2' => 'value', 'subname3' => 'world'}}) }
|
24
|
+
specify { expect(field.compose(double(value: [
|
25
25
|
double(subvalue1: 'hello1', subvalue2: 'value1', subname3: 'world1'),
|
26
26
|
double(subvalue1: 'hello2', subvalue2: 'value2', subname3: 'world2')
|
27
|
-
])).
|
27
|
+
]))).to eq({name: [
|
28
28
|
{'subname1' => 'hello1', 'subname2' => 'value1', 'subname3' => 'world1'},
|
29
29
|
{'subname1' => 'hello2', 'subname2' => 'value2', 'subname3' => 'world2'}
|
30
|
-
]} }
|
30
|
+
]}) }
|
31
31
|
end
|
32
32
|
|
33
33
|
context do
|
@@ -37,7 +37,7 @@ describe Chewy::Fields::Base do
|
|
37
37
|
field.nested(described_class.new(:untouched))
|
38
38
|
end
|
39
39
|
|
40
|
-
specify { field.compose(double(name: 'Alex')).
|
40
|
+
specify { expect(field.compose(double(name: 'Alex'))).to eq({name: 'Alex'}) }
|
41
41
|
end
|
42
42
|
|
43
43
|
context do
|
@@ -49,7 +49,7 @@ describe Chewy::Fields::Base do
|
|
49
49
|
field.nested(described_class.new(:key2, value: ->(h){ h[:key2] }))
|
50
50
|
end
|
51
51
|
|
52
|
-
specify{ field.compose(object).
|
52
|
+
specify{ expect(field.compose(object)).to eq({ name: { 'key1' => 'value1', 'key2' => 'value2' } }) }
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -69,21 +69,21 @@ describe Chewy::Fields::Base do
|
|
69
69
|
fields2.each { |m| fields1[0].nested(m) }
|
70
70
|
end
|
71
71
|
|
72
|
-
specify { field.mappings_hash.
|
72
|
+
specify { expect(field.mappings_hash).to eq({name: {type: :object, properties: {
|
73
73
|
name1: {type: 'string1', fields: {
|
74
74
|
name3: {type: 'string3'}, name4: {type: 'string4'}
|
75
75
|
}}, name2: {type: 'string2'}
|
76
|
-
}}} }
|
76
|
+
}}}) }
|
77
77
|
|
78
78
|
context do
|
79
79
|
let(:field) { described_class.new(:name, type: :string) }
|
80
80
|
let(:fields1) { 2.times.map { |i| described_class.new("name#{i+1}") } }
|
81
81
|
|
82
|
-
specify { field.mappings_hash.
|
82
|
+
specify { expect(field.mappings_hash).to eq({name: {type: :string, fields: {
|
83
83
|
name1: {type: 'object', properties: {
|
84
84
|
name3: {type: 'string3'}, name4: {type: 'string4'}
|
85
85
|
}}, name2: {type: 'string'}
|
86
|
-
}}} }
|
86
|
+
}}}) }
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -105,7 +105,7 @@ describe Chewy::Fields::Base do
|
|
105
105
|
end
|
106
106
|
|
107
107
|
specify do
|
108
|
-
EventsIndex::Event.mappings_hash.
|
108
|
+
expect(EventsIndex::Event.mappings_hash).to eq({ event: {
|
109
109
|
properties: {
|
110
110
|
id: { type: 'string' },
|
111
111
|
category: {
|
@@ -116,99 +116,99 @@ describe Chewy::Fields::Base do
|
|
116
116
|
type: 'object',
|
117
117
|
properties: {
|
118
118
|
id: { type: 'string' },
|
119
|
-
name: { type: 'string' } } } } } } } }
|
119
|
+
name: { type: 'string' } } } } } } } })
|
120
120
|
end
|
121
121
|
|
122
122
|
specify do
|
123
|
-
EventsIndex::Event.root_object.compose(
|
123
|
+
expect(EventsIndex::Event.root_object.compose(
|
124
124
|
id: 1, category: { id: 2, licenses: { id: 3, name: 'Name' } }
|
125
|
-
).
|
125
|
+
)).to eq({
|
126
126
|
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}}
|
127
|
-
}
|
127
|
+
})
|
128
128
|
end
|
129
129
|
|
130
130
|
specify do
|
131
|
-
EventsIndex::Event.root_object.compose(id: 1, category: [
|
131
|
+
expect(EventsIndex::Event.root_object.compose(id: 1, category: [
|
132
132
|
{ id: 2, 'licenses' => { id: 3, name: 'Name1' } },
|
133
133
|
{ id: 4, licenses: nil}
|
134
|
-
]).
|
134
|
+
])).to eq({
|
135
135
|
event: { 'id' => 1, 'category' => [
|
136
136
|
{ 'id' => 2, 'licenses' => { 'id' => 3, 'name' => 'Name1' } },
|
137
137
|
{'id' => 4, 'licenses' => nil }
|
138
138
|
] }
|
139
|
-
}
|
139
|
+
})
|
140
140
|
end
|
141
141
|
|
142
142
|
specify do
|
143
|
-
EventsIndex::Event.root_object.compose('id' => 1, category: { id: 2, licenses: [
|
143
|
+
expect(EventsIndex::Event.root_object.compose('id' => 1, category: { id: 2, licenses: [
|
144
144
|
{ id: 3, name: 'Name1' }, { id: 4, name: 'Name2' }
|
145
|
-
] }).
|
145
|
+
] })).to eq({
|
146
146
|
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => [
|
147
147
|
{'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'}
|
148
148
|
] } }
|
149
|
-
}
|
149
|
+
})
|
150
150
|
end
|
151
151
|
|
152
152
|
specify do
|
153
|
-
EventsIndex::Event.root_object.compose(id: 1, category: [
|
153
|
+
expect(EventsIndex::Event.root_object.compose(id: 1, category: [
|
154
154
|
{ id: 2, licenses: [
|
155
155
|
{ id: 3, 'name' => 'Name1' }, { id: 4, name: 'Name2' }
|
156
156
|
] },
|
157
157
|
{ id: 5, licenses: [] }
|
158
|
-
]).
|
158
|
+
])).to eq({
|
159
159
|
event: { 'id' => 1, 'category' => [
|
160
160
|
{ 'id' => 2, 'licenses' => [
|
161
161
|
{ 'id' => 3, 'name' => 'Name1' }, { 'id' => 4, 'name' => 'Name2' }
|
162
162
|
] },
|
163
163
|
{'id' => 5, 'licenses' => [] }
|
164
164
|
] }
|
165
|
-
}
|
165
|
+
})
|
166
166
|
end
|
167
167
|
|
168
168
|
specify do
|
169
|
-
EventsIndex::Event.root_object.compose(
|
169
|
+
expect(EventsIndex::Event.root_object.compose(
|
170
170
|
double(id: 1, category: double(id: 2, licenses: double(id: 3, name: 'Name')))
|
171
|
-
).
|
171
|
+
)).to eq({
|
172
172
|
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}}
|
173
|
-
}
|
173
|
+
})
|
174
174
|
end
|
175
175
|
|
176
176
|
specify do
|
177
|
-
EventsIndex::Event.root_object.compose(double(id: 1, category: [
|
177
|
+
expect(EventsIndex::Event.root_object.compose(double(id: 1, category: [
|
178
178
|
double(id: 2, licenses: double(id: 3, name: 'Name1')),
|
179
179
|
double(id: 4, licenses: nil)
|
180
|
-
])).
|
180
|
+
]))).to eq({
|
181
181
|
event: { 'id' => 1, 'category' => [
|
182
182
|
{ 'id' => 2, 'licenses' => { 'id' => 3, 'name' => 'Name1' } },
|
183
183
|
{'id' => 4, 'licenses' => nil }
|
184
184
|
] }
|
185
|
-
}
|
185
|
+
})
|
186
186
|
end
|
187
187
|
|
188
188
|
specify do
|
189
|
-
EventsIndex::Event.root_object.compose(double(id: 1, category: double(id: 2, licenses: [
|
189
|
+
expect(EventsIndex::Event.root_object.compose(double(id: 1, category: double(id: 2, licenses: [
|
190
190
|
double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2')
|
191
|
-
]))).
|
191
|
+
])))).to eq({
|
192
192
|
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => [
|
193
193
|
{'id' => 3, 'name' => 'Name1'}, {'id' => 4, 'name' => 'Name2'}
|
194
194
|
] } }
|
195
|
-
}
|
195
|
+
})
|
196
196
|
end
|
197
197
|
|
198
198
|
specify do
|
199
|
-
EventsIndex::Event.root_object.compose(double(id: 1, category: [
|
199
|
+
expect(EventsIndex::Event.root_object.compose(double(id: 1, category: [
|
200
200
|
double(id: 2, licenses: [
|
201
201
|
double(id: 3, name: 'Name1'), double(id: 4, name: 'Name2')
|
202
202
|
]),
|
203
203
|
double(id: 5, licenses: [])
|
204
|
-
])).
|
204
|
+
]))).to eq({
|
205
205
|
event: { 'id' => 1, 'category' => [
|
206
206
|
{ 'id' => 2, 'licenses' => [
|
207
207
|
{ 'id' => 3, 'name' => 'Name1' }, { 'id' => 4, 'name' => 'Name2' }
|
208
208
|
] },
|
209
209
|
{'id' => 5, 'licenses' => [] }
|
210
210
|
] }
|
211
|
-
}
|
211
|
+
})
|
212
212
|
end
|
213
213
|
end
|
214
214
|
|
@@ -229,11 +229,11 @@ describe Chewy::Fields::Base do
|
|
229
229
|
end
|
230
230
|
|
231
231
|
specify do
|
232
|
-
EventsIndex::Event.root_object.compose(
|
232
|
+
expect(EventsIndex::Event.root_object.compose(
|
233
233
|
double(id: 1, categories: double(id: 2, license: double(id: 3, name: 'Name')))
|
234
|
-
).
|
234
|
+
)).to eq({
|
235
235
|
event: { 'id' => 1, 'category' => { 'id' => 2, 'licenses' => {'id' => 3, 'name' => 'Name'}}}
|
236
|
-
}
|
236
|
+
})
|
237
237
|
end
|
238
238
|
end
|
239
239
|
|
@@ -251,7 +251,7 @@ describe Chewy::Fields::Base do
|
|
251
251
|
end
|
252
252
|
|
253
253
|
specify do
|
254
|
-
EventsIndex::Event.mappings_hash.
|
254
|
+
expect(EventsIndex::Event.mappings_hash).to eq({ event: {
|
255
255
|
properties: {
|
256
256
|
id: { type: 'string' },
|
257
257
|
name: {
|
@@ -262,28 +262,28 @@ describe Chewy::Fields::Base do
|
|
262
262
|
},
|
263
263
|
category: { type: 'object' }
|
264
264
|
}
|
265
|
-
} }
|
265
|
+
} })
|
266
266
|
end
|
267
267
|
|
268
268
|
specify do
|
269
|
-
EventsIndex::Event.root_object.compose(
|
269
|
+
expect(EventsIndex::Event.root_object.compose(
|
270
270
|
double(id: 1, name: 'Jonny', category: double(id: 2, as_json: {name: 'Borogoves'}))
|
271
|
-
).
|
271
|
+
)).to eq({
|
272
272
|
event: {
|
273
273
|
'id' => 1,
|
274
274
|
'name' => 'Jonny',
|
275
275
|
'category' => { 'name' => 'Borogoves' }
|
276
276
|
}
|
277
|
-
}
|
277
|
+
})
|
278
278
|
end
|
279
279
|
|
280
280
|
specify do
|
281
|
-
EventsIndex::Event.root_object.compose(
|
281
|
+
expect(EventsIndex::Event.root_object.compose(
|
282
282
|
double(id: 1, name: 'Jonny', category: [
|
283
283
|
double(id: 2, as_json: { name: 'Borogoves1' }),
|
284
284
|
double(id: 3, as_json: { name: 'Borogoves2' })
|
285
285
|
])
|
286
|
-
).
|
286
|
+
)).to eq({
|
287
287
|
event: {
|
288
288
|
'id' => 1,
|
289
289
|
'name' => 'Jonny',
|
@@ -292,11 +292,11 @@ describe Chewy::Fields::Base do
|
|
292
292
|
{ 'name' => 'Borogoves2' }
|
293
293
|
]
|
294
294
|
}
|
295
|
-
}
|
295
|
+
})
|
296
296
|
end
|
297
297
|
end
|
298
298
|
|
299
|
-
context 'objects and scopes' do
|
299
|
+
context 'objects and scopes', :orm do
|
300
300
|
before do
|
301
301
|
stub_model(:city) do
|
302
302
|
belongs_to :country
|
@@ -318,13 +318,13 @@ describe Chewy::Fields::Base do
|
|
318
318
|
end
|
319
319
|
|
320
320
|
specify do
|
321
|
-
CountriesIndex::Country.root_object.compose(
|
322
|
-
Country.create!(cities: [City.create!(name: 'City1'), City.create!(name: 'City2')])
|
323
|
-
).
|
321
|
+
expect(CountriesIndex::Country.root_object.compose(
|
322
|
+
Country.create!(id: 1, cities: [City.create!(id: 1, name: 'City1'), City.create!(id: 2, name: 'City2')])
|
323
|
+
)).to eq({
|
324
324
|
country: { 'id' => 1, 'cities' => [
|
325
325
|
{ 'id' => 1, 'name' => 'City1' }, { 'id' => 2, 'name' => 'City2' }
|
326
326
|
] }
|
327
|
-
}
|
327
|
+
})
|
328
328
|
end
|
329
329
|
|
330
330
|
context 'nested object' do
|
@@ -341,11 +341,11 @@ describe Chewy::Fields::Base do
|
|
341
341
|
end
|
342
342
|
|
343
343
|
specify do
|
344
|
-
CitiesIndex::City.root_object.compose(
|
345
|
-
City.create!(country: Country.create!(name: 'Country'))
|
346
|
-
).
|
344
|
+
expect(CitiesIndex::City.root_object.compose(
|
345
|
+
City.create!(id: 1, country: Country.create!(id: 1, name: 'Country'))
|
346
|
+
)).to eq({
|
347
347
|
city: { 'id' => 1, 'country' => { 'id' => 1, 'name' => 'Country' } }
|
348
|
-
}
|
348
|
+
})
|
349
349
|
end
|
350
350
|
end
|
351
351
|
end
|