chewy 0.0.1

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +3 -0
  4. data/.rvmrc +1 -0
  5. data/.travis.yml +7 -0
  6. data/Gemfile +12 -0
  7. data/Guardfile +24 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +208 -0
  10. data/Rakefile +6 -0
  11. data/chewy.gemspec +32 -0
  12. data/lib/chewy.rb +55 -0
  13. data/lib/chewy/config.rb +48 -0
  14. data/lib/chewy/fields/base.rb +49 -0
  15. data/lib/chewy/fields/default.rb +10 -0
  16. data/lib/chewy/fields/root.rb +10 -0
  17. data/lib/chewy/index.rb +71 -0
  18. data/lib/chewy/index/actions.rb +43 -0
  19. data/lib/chewy/index/client.rb +13 -0
  20. data/lib/chewy/index/search.rb +26 -0
  21. data/lib/chewy/query.rb +141 -0
  22. data/lib/chewy/query/criteria.rb +81 -0
  23. data/lib/chewy/query/loading.rb +27 -0
  24. data/lib/chewy/query/pagination.rb +39 -0
  25. data/lib/chewy/rspec.rb +1 -0
  26. data/lib/chewy/rspec/update_index.rb +121 -0
  27. data/lib/chewy/type.rb +22 -0
  28. data/lib/chewy/type/adapter/active_record.rb +27 -0
  29. data/lib/chewy/type/adapter/object.rb +22 -0
  30. data/lib/chewy/type/base.rb +41 -0
  31. data/lib/chewy/type/import.rb +67 -0
  32. data/lib/chewy/type/mapping.rb +50 -0
  33. data/lib/chewy/type/observe.rb +37 -0
  34. data/lib/chewy/type/wrapper.rb +35 -0
  35. data/lib/chewy/version.rb +3 -0
  36. data/spec/chewy/config_spec.rb +50 -0
  37. data/spec/chewy/fields/base_spec.rb +70 -0
  38. data/spec/chewy/fields/default_spec.rb +6 -0
  39. data/spec/chewy/fields/root_spec.rb +6 -0
  40. data/spec/chewy/index/actions_spec.rb +53 -0
  41. data/spec/chewy/index/client_spec.rb +18 -0
  42. data/spec/chewy/index/search_spec.rb +54 -0
  43. data/spec/chewy/index_spec.rb +65 -0
  44. data/spec/chewy/query/criteria_spec.rb +73 -0
  45. data/spec/chewy/query/loading_spec.rb +37 -0
  46. data/spec/chewy/query/pagination_spec.rb +40 -0
  47. data/spec/chewy/query_spec.rb +110 -0
  48. data/spec/chewy/rspec/update_index_spec.rb +149 -0
  49. data/spec/chewy/type/import_spec.rb +68 -0
  50. data/spec/chewy/type/mapping_spec.rb +54 -0
  51. data/spec/chewy/type/observe_spec.rb +55 -0
  52. data/spec/chewy/type/wrapper_spec.rb +35 -0
  53. data/spec/chewy/type_spec.rb +43 -0
  54. data/spec/chewy_spec.rb +36 -0
  55. data/spec/spec_helper.rb +48 -0
  56. data/spec/support/class_helpers.rb +16 -0
  57. data/spec/support/fail_helpers.rb +13 -0
  58. metadata +249 -0
@@ -0,0 +1,35 @@
1
+ module Chewy
2
+ module Type
3
+ module Wrapper
4
+ extend ActiveSupport::Concern
5
+
6
+ attr_accessor :attributes
7
+
8
+ def initialize(attributes = {})
9
+ @attributes = attributes.stringify_keys
10
+ end
11
+
12
+ def ==(other)
13
+ if other.is_a?(Chewy::Type::Base)
14
+ self.class == other.class && (respond_to?(:id) ? id == other.id : attributes == other.attributes)
15
+ elsif other.respond_to?(:id)
16
+ id.to_s == other.id.to_s
17
+ else
18
+ false
19
+ end
20
+ end
21
+
22
+ def method_missing(method, *args, &block)
23
+ if @attributes.key?(method.to_s)
24
+ @attributes[method.to_s]
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def respond_to_missing?(method, _)
31
+ @attributes.key?(method.to_s) || super
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module Chewy
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Config do
4
+ include ClassHelpers
5
+ subject { described_class.send(:new) }
6
+
7
+ its(:observing_enabled) { should be_true }
8
+
9
+ describe '#atomic?' do
10
+ its(:atomic?) { should be_false }
11
+ specify { subject.atomic { subject.atomic?.should be_true } }
12
+ specify { subject.atomic { }; subject.atomic?.should be_false }
13
+ end
14
+
15
+ describe '#atomic' do
16
+ before do
17
+ stub_index(:dummies) do
18
+ define_type :dummy
19
+ end
20
+ end
21
+ let(:dummy_type) { DummiesIndex::Dummy }
22
+
23
+ specify { subject.atomic { 42 }.should == 42 }
24
+ specify { expect { subject.atomic { subject.atomic_stash Class.new, 42 } }.to raise_error ArgumentError }
25
+ specify { subject.atomic { subject.atomic { subject.atomic_stash.should == [{}, {}] } } }
26
+
27
+ specify do
28
+ expect(dummy_type).to receive(:import).with([1,2,3]).once
29
+ subject.atomic do
30
+ subject.atomic_stash dummy_type, 1, 2
31
+ subject.atomic_stash dummy_type, [2, 3]
32
+ end
33
+ end
34
+
35
+ specify do
36
+ expect(dummy_type).to receive(:import).with([2,3]).once
37
+ expect(dummy_type).to receive(:import).with([1,2]).once
38
+ subject.atomic do
39
+ subject.atomic_stash dummy_type, [2, 3]
40
+ subject.atomic do
41
+ subject.atomic_stash dummy_type, 1, 2
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#atomic_stash' do
48
+ specify { subject.atomic { subject.atomic_stash.should == [{}] } }
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Fields::Base do
4
+ specify { described_class.new('name').name.should == :name }
5
+ specify { described_class.new('name', type: 'integer').options[:type].should == 'integer' }
6
+
7
+ describe '#compose' do
8
+ let(:field) { described_class.new(:name, value: ->(o){ o.value }) }
9
+
10
+ specify { field.compose(double(value: 'hello')).should == {name: 'hello'} }
11
+ specify { field.compose(double(value: ['hello', 'world'])).should == {name: ['hello', 'world']} }
12
+
13
+ specify { described_class.new(:name).compose(double(name: 'hello')).should == {name: 'hello'} }
14
+
15
+ context do
16
+ before do
17
+ field.nested(described_class.new(:subname1, value: ->(o){ o.subvalue1 }))
18
+ field.nested(described_class.new(:subname2))
19
+ end
20
+
21
+ specify { field.compose(double(value: double(subvalue1: 'hello', subname2: 'world')))
22
+ .should == {name: {'subname1' => 'hello', 'subname2' => 'world'}} }
23
+ specify { field.compose(double(value: [double(subvalue1: 'hello1', subname2: 'world1'), double(subvalue1: 'hello2', subname2: 'world2')]))
24
+ .should == {name: [{'subname1' => 'hello1', 'subname2' => 'world1'}, {'subname1' => 'hello2', 'subname2' => 'world2'}]} }
25
+ end
26
+
27
+ context do
28
+ let(:field) { described_class.new(:name, type: 'multi_field') }
29
+ before do
30
+ field.nested(described_class.new(:name))
31
+ field.nested(described_class.new(:untouched))
32
+ end
33
+
34
+ specify { field.compose(double(name: 'Alex')).should == {name: 'Alex'} }
35
+ end
36
+ end
37
+
38
+ describe '#nested' do
39
+ let(:field) { described_class.new(:name) }
40
+
41
+ specify { expect { field.nested(described_class.new(:name1)) }
42
+ .to change { field.nested[:name1] }.from(nil).to(an_instance_of(described_class)) }
43
+ end
44
+
45
+ describe '#mappings_hash' do
46
+ let(:field) { described_class.new(:name, type: 'string') }
47
+ let(:fields1) { 2.times.map { |i| described_class.new("name#{i+1}", type: "string#{i+1}") } }
48
+ let(:fields2) { 2.times.map { |i| described_class.new("name#{i+3}", type: "string#{i+3}") } }
49
+ before do
50
+ fields1.each { |m| field.nested(m) }
51
+ fields2.each { |m| fields1[0].nested(m) }
52
+ end
53
+
54
+ specify { field.mappings_hash.should == {name: {type: 'string', properties: {
55
+ name1: {type: 'string1', properties: {
56
+ name3: {type: 'string3'}, name4: {type: 'string4'}
57
+ }}, name2: {type: 'string2'}
58
+ }}} }
59
+
60
+ context do
61
+ let(:field) { described_class.new(:name, type: 'multi_field') }
62
+
63
+ specify { field.mappings_hash.should == {name: {type: 'multi_field', fields: {
64
+ name1: {type: 'string1', properties: {
65
+ name3: {type: 'string3'}, name4: {type: 'string4'}
66
+ }}, name2: {type: 'string2'}
67
+ }}} }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Fields::Default do
4
+ specify { described_class.new('name').options[:type].should == 'string' }
5
+ # TODO: add 'should_behave_like base_field'
6
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Fields::Root do
4
+ specify { described_class.new('name').value.should be_a(Proc) }
5
+ # TODO: add 'should_behave_like base_field'
6
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Index::Actions do
4
+ include ClassHelpers
5
+ before { Chewy::Index.client.indices.delete }
6
+
7
+ before { stub_index :dummies }
8
+
9
+ describe '.index_exists?' do
10
+ specify { DummiesIndex.index_exists?.should be_false }
11
+
12
+ context do
13
+ before { DummiesIndex.index_create }
14
+ specify { DummiesIndex.index_exists?.should be_true }
15
+ end
16
+ end
17
+
18
+ describe '.index_create' do
19
+ specify { DummiesIndex.index_create.should be_true }
20
+
21
+ context do
22
+ before { DummiesIndex.index_create }
23
+ specify { DummiesIndex.index_create.should be_false }
24
+ end
25
+ end
26
+
27
+ describe '.index_create!' do
28
+ specify { expect { DummiesIndex.index_create! }.not_to raise_error }
29
+
30
+ context do
31
+ before { DummiesIndex.index_create }
32
+ specify { expect { DummiesIndex.index_create! }.to raise_error }
33
+ end
34
+ end
35
+
36
+ describe '.index_delete' do
37
+ specify { DummiesIndex.index_delete.should be_false }
38
+
39
+ context do
40
+ before { DummiesIndex.index_create }
41
+ specify { DummiesIndex.index_delete.should be_true }
42
+ end
43
+ end
44
+
45
+ describe '.index_delete!' do
46
+ specify { expect { DummiesIndex.index_delete! }.to raise_error }
47
+
48
+ context do
49
+ before { DummiesIndex.index_create }
50
+ specify { expect { DummiesIndex.index_delete! }.not_to raise_error }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Index::Client do
4
+ include ClassHelpers
5
+
6
+ describe '.client' do
7
+ specify { stub_index(:dummies1).client.should == stub_index(:dummies2).client }
8
+
9
+ context do
10
+ before do
11
+ stub_index(:dummies1)
12
+ stub_index(:dummies2, Dummies1Index)
13
+ end
14
+
15
+ specify { Dummies1Index.client.should == Dummies2Index.client }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Index::Search do
4
+ include ClassHelpers
5
+
6
+ before do
7
+ stub_index(:products) do
8
+ define_type :product
9
+ define_type :product2
10
+ end
11
+ end
12
+
13
+ let(:product) { ProductsIndex.product }
14
+
15
+ describe '.search' do
16
+ specify do
17
+ product.search.should be_a Chewy::Query
18
+ end
19
+ end
20
+
21
+ describe '.search_string' do
22
+ specify do
23
+ expect(ProductsIndex.client).to receive(:search).with(hash_including(q: 'hello')).twice
24
+ ProductsIndex.search_string('hello')
25
+ product.search_string('hello')
26
+ end
27
+
28
+ specify do
29
+ expect(ProductsIndex.client).to receive(:search).with(hash_including(explain: true)).twice
30
+ ProductsIndex.search_string('hello', explain: true)
31
+ product.search_string('hello', explain: true)
32
+ end
33
+
34
+ specify do
35
+ expect(ProductsIndex.client).to receive(:search).with(hash_including(index: 'products', type: ['product', 'product2']))
36
+ ProductsIndex.search_string('hello')
37
+ end
38
+
39
+ specify do
40
+ expect(ProductsIndex.client).to receive(:search).with(hash_including(index: 'products', type: 'product'))
41
+ product.search_string('hello')
42
+ end
43
+ end
44
+
45
+ describe '.search_index' do
46
+ specify { ProductsIndex.search_index.should == ProductsIndex }
47
+ specify { product.search_index.should == ProductsIndex }
48
+ end
49
+
50
+ describe '.search_type' do
51
+ specify { ProductsIndex.search_type.should == ['product', 'product2'] }
52
+ specify { product.search_type.should == 'product' }
53
+ end
54
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Index do
4
+ include ClassHelpers
5
+
6
+ describe '.define_type' do
7
+ context 'blank name' do
8
+ before do
9
+ stub_index(:dummies) do
10
+ define_type :dummy
11
+ end
12
+ end
13
+
14
+ specify { DummiesIndex.types.should have_key 'dummy' }
15
+ specify { DummiesIndex.types['dummy'].should be < Chewy::Type::Base }
16
+ specify { DummiesIndex.types['dummy'].type_name.should == 'dummy' }
17
+ end
18
+ end
19
+
20
+ describe '.index_name' do
21
+ specify { expect { Class.new(Chewy::Index).index_name }.to raise_error Chewy::UndefinedIndex }
22
+ specify { Class.new(Chewy::Index) { index_name :myindex }.index_name.should == 'myindex' }
23
+ specify { stub_const('DeveloperIndex', Class.new(Chewy::Index)).index_name.should == 'developer' }
24
+ specify { stub_const('DevelopersIndex', Class.new(Chewy::Index)).index_name.should == 'developers' }
25
+ end
26
+
27
+ describe '.index_params' do
28
+ specify { stub_index(:documents).index_params.should == {} }
29
+ specify { stub_index(:documents) { settings number_of_shards: 1 }.index_params.keys.should == [:settings] }
30
+ specify { stub_index(:documents) do
31
+ define_type :document do
32
+ field :name, type: 'string'
33
+ end
34
+ end.index_params.keys.should == [:mappings] }
35
+ specify { stub_index(:documents) do
36
+ settings number_of_shards: 1
37
+ define_type :document do
38
+ field :name, type: 'string'
39
+ end
40
+ end.index_params.keys.should =~ [:mappings, :settings] }
41
+ end
42
+
43
+ describe '.settings_hash' do
44
+ specify { stub_index(:documents).settings_hash.should == {} }
45
+ specify { stub_index(:documents) { settings number_of_shards: 1 }.settings_hash.should == {settings: {number_of_shards: 1}} }
46
+ end
47
+
48
+ describe '.mappings_hash' do
49
+ specify { stub_index(:documents).mappings_hash.should == {} }
50
+ specify { stub_index(:documents) { define_type :document }.mappings_hash.should == {} }
51
+ specify { stub_index(:documents) do
52
+ define_type :document do
53
+ field :name, type: 'string'
54
+ end
55
+ end.mappings_hash.should == {mappings: {document: {properties: {name: {type: 'string'}}}}} }
56
+ specify { stub_index(:documents) do
57
+ define_type :document do
58
+ field :name, type: 'string'
59
+ end
60
+ define_type :document2 do
61
+ field :name, type: 'string'
62
+ end
63
+ end.mappings_hash[:mappings].keys.should =~ [:document, :document2] }
64
+ end
65
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Chewy::Query::Criteria do
4
+ include ClassHelpers
5
+
6
+ subject { described_class.new }
7
+
8
+ its(:search) { should == {} }
9
+ its(:query) { should == {} }
10
+ its(:facets) { should == {} }
11
+ its(:filters) { should == [] }
12
+ its(:sort) { should == [] }
13
+ its(:fields) { should == [] }
14
+
15
+ its(:search?) { should be_false }
16
+ its(:query?) { should be_false }
17
+ its(:facets?) { should be_false }
18
+ its(:filters?) { should be_false }
19
+ its(:sort?) { should be_false }
20
+ its(:fields?) { should be_false }
21
+
22
+ describe '#update_search' do
23
+ specify { expect { subject.update_search(field: 'hello') }.to change { subject.search? }.to(true) }
24
+ specify { expect { subject.update_search(field: 'hello') }.to change { subject.search }.to(field: 'hello') }
25
+ end
26
+
27
+ describe '#update_query' do
28
+ specify { expect { subject.update_query(field: 'hello') }.to change { subject.query? }.to(true) }
29
+ specify { expect { subject.update_query(field: 'hello') }.to change { subject.query }.to(field: 'hello') }
30
+ end
31
+
32
+ describe '#update_facets' do
33
+ specify { expect { subject.update_facets(field: 'hello') }.to change { subject.facets? }.to(true) }
34
+ specify { expect { subject.update_facets(field: 'hello') }.to change { subject.facets }.to(field: 'hello') }
35
+ end
36
+
37
+ describe '#update_filters' do
38
+ specify { expect { subject.update_filters(field: 'hello') }.to change { subject.filters? }.to(true) }
39
+ specify { expect { subject.update_filters(field: 'hello') }.to change { subject.filters }.to([{field: 'hello'}]) }
40
+ specify { expect { subject.update_filters(field: 'hello'); subject.update_filters(field: 'world') }
41
+ .to change { subject.filters }.to([{field: 'hello'}, {field: 'world'}]) }
42
+ specify { expect { subject.update_filters([{field: 'hello'}, {field: 'world'}, nil]) }
43
+ .to change { subject.filters }.to([{field: 'hello'}, {field: 'world'}]) }
44
+ end
45
+
46
+ describe '#update_sort' do
47
+ specify { expect { subject.update_sort(:field) }.to change { subject.sort? }.to(true) }
48
+
49
+ specify { expect { subject.update_sort([:field]) }.to change { subject.sort }.to([:field]) }
50
+ specify { expect { subject.update_sort([:field1, :field2]) }.to change { subject.sort }.to([:field1, :field2]) }
51
+ specify { expect { subject.update_sort([{field: :asc}]) }.to change { subject.sort }.to([{field: :asc}]) }
52
+ specify { expect { subject.update_sort([:field1, field2: {order: :asc}]) }.to change { subject.sort }.to([:field1, {field2: {order: :asc}}]) }
53
+ specify { expect { subject.update_sort([{field1: {order: :asc}}, :field2]) }.to change { subject.sort }.to([{field1: {order: :asc}}, :field2]) }
54
+ specify { expect { subject.update_sort([field1: :asc, field2: {order: :asc}]) }.to change { subject.sort }.to([{field1: :asc}, {field2: {order: :asc}}]) }
55
+ specify { expect { subject.update_sort([{field1: {order: :asc}}, :field2, :field3]) }.to change { subject.sort }.to([{field1: {order: :asc}}, :field2, :field3]) }
56
+ specify { expect { subject.update_sort([{field1: {order: :asc}}, [:field2, :field3]]) }.to change { subject.sort }.to([{field1: {order: :asc}}, :field2, :field3]) }
57
+ specify { expect { subject.update_sort([{field1: {order: :asc}}, [:field2], :field3]) }.to change { subject.sort }.to([{field1: {order: :asc}}, :field2, :field3]) }
58
+ specify { expect { subject.update_sort([{field1: {order: :asc}, field2: :desc}, [:field3], :field4]) }.to change { subject.sort }.to([{field1: {order: :asc}}, {field2: :desc}, :field3, :field4]) }
59
+ specify { expect { subject.tap { |s| s.update_sort([field1: {order: :asc}, field2: :desc]) }.update_sort([[:field3], :field4]) }.to change { subject.sort }.to([{field1: {order: :asc}}, {field2: :desc}, :field3, :field4]) }
60
+ specify { expect { subject.tap { |s| s.update_sort([field1: {order: :asc}, field2: :desc]) }.update_sort([[:field3], :field4], purge: true) }.to change { subject.sort }.to([:field3, :field4]) }
61
+ end
62
+
63
+ describe '#update_fields' do
64
+ specify { expect { subject.update_fields(:field) }.to change { subject.fields? }.to(true) }
65
+ specify { expect { subject.update_fields(:field) }.to change { subject.fields }.to(['field']) }
66
+ specify { expect { subject.update_fields([:field, :field]) }.to change { subject.fields }.to(['field']) }
67
+ specify { expect { subject.update_fields([:field1, :field2]) }.to change { subject.fields }.to(['field1', 'field2']) }
68
+ specify { expect { subject.tap { |s| s.update_fields(:field1) }.update_fields([:field2, :field3]) }
69
+ .to change { subject.fields }.to(['field1', 'field2', 'field3']) }
70
+ specify { expect { subject.tap { |s| s.update_fields(:field1) }.update_fields([:field2, :field3], purge: true) }
71
+ .to change { subject.fields }.to(['field2', 'field3']) }
72
+ end
73
+ end