elasticsearch-persistence 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.txt +10 -19
  3. data/README.md +432 -14
  4. data/Rakefile +56 -0
  5. data/elasticsearch-persistence.gemspec +45 -17
  6. data/examples/sinatra/.gitignore +7 -0
  7. data/examples/sinatra/Gemfile +28 -0
  8. data/examples/sinatra/README.markdown +36 -0
  9. data/examples/sinatra/application.rb +238 -0
  10. data/examples/sinatra/config.ru +7 -0
  11. data/examples/sinatra/test.rb +118 -0
  12. data/lib/elasticsearch/persistence.rb +88 -2
  13. data/lib/elasticsearch/persistence/client.rb +51 -0
  14. data/lib/elasticsearch/persistence/repository.rb +75 -0
  15. data/lib/elasticsearch/persistence/repository/class.rb +71 -0
  16. data/lib/elasticsearch/persistence/repository/find.rb +73 -0
  17. data/lib/elasticsearch/persistence/repository/naming.rb +115 -0
  18. data/lib/elasticsearch/persistence/repository/response/results.rb +90 -0
  19. data/lib/elasticsearch/persistence/repository/search.rb +60 -0
  20. data/lib/elasticsearch/persistence/repository/serialize.rb +31 -0
  21. data/lib/elasticsearch/persistence/repository/store.rb +95 -0
  22. data/lib/elasticsearch/persistence/version.rb +1 -1
  23. data/test/integration/repository/custom_class_test.rb +85 -0
  24. data/test/integration/repository/customized_class_test.rb +82 -0
  25. data/test/integration/repository/default_class_test.rb +108 -0
  26. data/test/integration/repository/virtus_model_test.rb +114 -0
  27. data/test/test_helper.rb +46 -0
  28. data/test/unit/persistence_test.rb +32 -0
  29. data/test/unit/repository_class_test.rb +51 -0
  30. data/test/unit/repository_client_test.rb +32 -0
  31. data/test/unit/repository_find_test.rb +375 -0
  32. data/test/unit/repository_indexing_test.rb +37 -0
  33. data/test/unit/repository_module_test.rb +144 -0
  34. data/test/unit/repository_naming_test.rb +146 -0
  35. data/test/unit/repository_response_results_test.rb +98 -0
  36. data/test/unit/repository_search_test.rb +97 -0
  37. data/test/unit/repository_serialize_test.rb +57 -0
  38. data/test/unit/repository_store_test.rb +287 -0
  39. metadata +288 -20
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ module Elasticsearch
4
+ module Persistence
5
+ class RepositoryCustomizedClassIntegrationTest < Elasticsearch::Test::IntegrationTestCase
6
+
7
+ module ::My
8
+ class Note
9
+ attr_reader :attributes
10
+
11
+ def initialize(attributes={})
12
+ @attributes = attributes
13
+ end
14
+
15
+ def to_hash
16
+ @attributes
17
+ end
18
+ end
19
+ end
20
+
21
+ context "A custom repository class" do
22
+ setup do
23
+ @repository = Elasticsearch::Persistence::Repository.new do
24
+ index 'my_notes'
25
+ type 'my_note'
26
+ klass My::Note
27
+
28
+ settings number_of_shards: 1 do
29
+ mapping do
30
+ indexes :title, analyzer: 'snowball'
31
+ end
32
+ end
33
+
34
+ create_index!
35
+ end
36
+
37
+ @repository.client.cluster.health wait_for_status: 'yellow'
38
+ end
39
+
40
+ should "save the object under a correct index and type" do
41
+ @repository.save My::Note.new(id: '1', title: 'Test')
42
+
43
+ assert_instance_of My::Note, @repository.find(1)
44
+ assert_not_nil Elasticsearch::Persistence.client.get index: 'my_notes', type: 'my_note', id: '1'
45
+ end
46
+
47
+ should "update the document" do
48
+ @repository.save Note.new(id: 1, title: 'Test')
49
+
50
+ @repository.update 1, doc: { title: 'UPDATED' }
51
+ assert_equal 'UPDATED', @repository.find(1).attributes['title']
52
+ end
53
+
54
+ should "update the document with a script" do
55
+ @repository.save Note.new(id: 1, title: 'Test')
56
+
57
+ @repository.update 1, script: 'ctx._source.title = "UPDATED"'
58
+ assert_equal 'UPDATED', @repository.find(1).attributes['title']
59
+ end
60
+
61
+ should "delete the object" do
62
+ note = My::Note.new id: 1, title: 'Test'
63
+ @repository.save note
64
+
65
+ assert_not_nil @repository.find(1)
66
+
67
+ @repository.delete(note)
68
+ assert_raise(Elasticsearch::Persistence::Repository::DocumentNotFound) { @repository.find(1) }
69
+ end
70
+
71
+ should "create the index with correct mapping" do
72
+ note = My::Note.new title: 'Testing'
73
+ @repository.save note, refresh: true
74
+
75
+ results = @repository.search query: { match: { title: 'Test' } }
76
+ assert_equal 'Testing', results.first.attributes['title']
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,108 @@
1
+ require 'test_helper'
2
+
3
+ module Elasticsearch
4
+ module Persistence
5
+ class RepositoryDefaultClassIntegrationTest < Elasticsearch::Test::IntegrationTestCase
6
+
7
+ class ::Note
8
+ attr_reader :attributes
9
+
10
+ def initialize(attributes={})
11
+ @attributes = attributes
12
+ end
13
+
14
+ def to_hash
15
+ @attributes
16
+ end
17
+ end
18
+
19
+ context "The default repository class" do
20
+ setup do
21
+ @repository = Elasticsearch::Persistence::Repository.new
22
+ @repository.client.cluster.health wait_for_status: 'yellow'
23
+ end
24
+
25
+ should "save the object with a custom ID and find it" do
26
+ @repository.save Note.new(id: '1', title: 'Test')
27
+
28
+ assert_equal 'Test', @repository.find(1).attributes['title']
29
+ end
30
+
31
+ should "save the object with an auto-generated ID and find it" do
32
+ response = @repository.save Note.new(title: 'Test')
33
+
34
+ assert_equal 'Test', @repository.find(response['_id']).attributes['title']
35
+ end
36
+
37
+ should "update the document" do
38
+ @repository.save Note.new(id: 1, title: 'Test')
39
+
40
+ @repository.update 1, type: 'note', doc: { title: 'UPDATED' }
41
+ assert_equal 'UPDATED', @repository.find(1).attributes['title']
42
+ end
43
+
44
+ should "update the document with a script" do
45
+ @repository.save Note.new(id: 1, title: 'Test')
46
+
47
+ @repository.update 1, type: 'note', script: 'ctx._source.title = "UPDATED"'
48
+ assert_equal 'UPDATED', @repository.find(1).attributes['title']
49
+ end
50
+
51
+ should "save the document with an upsert" do
52
+ @repository.update 1, type: 'note', script: 'ctx._source.clicks += 1', upsert: { clicks: 1 }
53
+ assert_equal 1, @repository.find(1).attributes['clicks']
54
+ end
55
+
56
+ should "delete an object" do
57
+ note = Note.new(id: '1', title: 'Test')
58
+
59
+ @repository.save(note)
60
+ assert_not_nil @repository.find(1)
61
+ @repository.delete(note)
62
+ assert_raise(Elasticsearch::Persistence::Repository::DocumentNotFound) { @repository.find(1) }
63
+ end
64
+
65
+ should "find multiple objects" do
66
+ (1..5).each { |i| @repository.save Note.new(id: i, title: "Test #{i}") }
67
+
68
+ assert_equal 5, @repository.find(1, 2, 3, 4, 5).size
69
+ assert_equal 5, @repository.find([1, 2, 3, 4, 5]).size
70
+ end
71
+
72
+ should "pass options to save and find" do
73
+ note = Note.new(id: '1', title: 'Test')
74
+ @repository.save note, routing: 'ABC'
75
+
76
+ assert_raise Elasticsearch::Persistence::Repository::DocumentNotFound do
77
+ @repository.find(1, routing: 'DEF')
78
+ end
79
+
80
+ assert_nothing_raised do
81
+ note = @repository.find(1, routing: 'ABC')
82
+ assert_instance_of Note, note
83
+ end
84
+ end
85
+
86
+ should "find notes with full text search" do
87
+ @repository.save Note.new(title: 'Test')
88
+ @repository.save Note.new(title: 'Test Test')
89
+ @repository.save Note.new(title: 'Crust')
90
+ @repository.client.indices.refresh index: @repository.index_name
91
+
92
+ results = @repository.search 'test'
93
+ assert_equal 2, results.size
94
+
95
+ results = @repository.search query: { match: { title: 'Test' } }
96
+ assert_equal 2, results.size
97
+ end
98
+
99
+ should "save and find a plain hash" do
100
+ @repository.save id: 1, title: 'Hash'
101
+ result = @repository.find(1)
102
+ assert_equal 'Hash', result['_source']['title']
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,114 @@
1
+ require 'test_helper'
2
+
3
+ require 'virtus'
4
+
5
+ module Elasticsearch
6
+ module Persistence
7
+ class RepositoryWithVirtusIntegrationTest < Elasticsearch::Test::IntegrationTestCase
8
+
9
+ class ::Page
10
+ include Virtus.model
11
+
12
+ attribute :id, String, writer: :private
13
+ attribute :title, String
14
+ attribute :views, Integer, default: 0
15
+ attribute :published, Boolean, default: false
16
+ attribute :slug, String, default: lambda { |page, attr| page.title.downcase.gsub(' ', '-') }
17
+
18
+ def set_id(id)
19
+ self.id = id
20
+ end
21
+ end
22
+
23
+ context "The repository with a Virtus model" do
24
+ setup do
25
+ @repository = Elasticsearch::Persistence::Repository.new do
26
+ index :pages
27
+ klass Page
28
+
29
+ def deserialize(document)
30
+ page = klass.new document['_source']
31
+ page.set_id document['_id']
32
+ page
33
+ end
34
+ end
35
+ end
36
+
37
+ should "save and find the object" do
38
+ page = Page.new title: 'Test Page'
39
+
40
+ response = @repository.save page
41
+ id = response['_id']
42
+
43
+ result = @repository.find(id)
44
+
45
+ assert_instance_of Page, result
46
+ assert_equal 'Test Page', result.title
47
+ assert_equal 0, result.views
48
+
49
+ assert_not_nil Elasticsearch::Persistence.client.get index: 'pages',
50
+ type: 'page',
51
+ id: id
52
+ end
53
+
54
+ should "update the object with a partial document" do
55
+ response = @repository.save Page.new(title: 'Test')
56
+ id = response['_id']
57
+
58
+ page = @repository.find(id)
59
+
60
+ assert_equal 'Test', page.title
61
+
62
+ @repository.update page.id, doc: { title: 'UPDATE' }
63
+
64
+ page = @repository.find(id)
65
+ assert_equal 'UPDATE', page.title
66
+ end
67
+
68
+ should "update the object with a Hash" do
69
+ response = @repository.save Page.new(title: 'Test')
70
+ id = response['_id']
71
+
72
+ page = @repository.find(id)
73
+
74
+ assert_equal 'Test', page.title
75
+
76
+ @repository.update id: page.id, title: 'UPDATE'
77
+
78
+ page = @repository.find(id)
79
+ assert_equal 'UPDATE', page.title
80
+ end
81
+
82
+ should "update the object with a script" do
83
+ response = @repository.save Page.new(title: 'Test Page')
84
+ id = response['_id']
85
+
86
+ page = @repository.find(id)
87
+
88
+ assert_not_nil page.id
89
+ assert_equal 0, page.views
90
+
91
+ @repository.update page.id, script: 'ctx._source.views += 1'
92
+
93
+ page = @repository.find(id)
94
+ assert_equal 1, page.views
95
+
96
+ @repository.update id: page.id, script: 'ctx._source.views += 1'
97
+
98
+ page = @repository.find(id)
99
+ assert_equal 2, page.views
100
+ end
101
+
102
+ should "update the object with a script and params" do
103
+ response = @repository.save Page.new(title: 'Test Page')
104
+
105
+ @repository.update id: response['_id'], script: 'ctx._source.views += count', params: { count: 3 }
106
+
107
+ page = @repository.find(response['_id'])
108
+ assert_equal 3, page.views
109
+ end
110
+ end
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,46 @@
1
+ RUBY_1_8 = defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
2
+
3
+ exit(0) if RUBY_1_8
4
+
5
+ require 'simplecov' and SimpleCov.start { add_filter "/test|test_/" } if ENV["COVERAGE"]
6
+
7
+ # Register `at_exit` handler for integration tests shutdown.
8
+ # MUST be called before requiring `test/unit`.
9
+ at_exit { Elasticsearch::Test::IntegrationTestCase.__run_at_exit_hooks } if ENV['SERVER']
10
+
11
+ require 'test/unit'
12
+ require 'shoulda-context'
13
+ require 'mocha/setup'
14
+ require 'turn' unless ENV["TM_FILEPATH"] || ENV["NOTURN"] || RUBY_1_8
15
+
16
+ require 'ansi'
17
+ require 'oj'
18
+
19
+ require 'elasticsearch/extensions/test/cluster'
20
+ require 'elasticsearch/extensions/test/startup_shutdown'
21
+
22
+ require 'elasticsearch/persistence'
23
+
24
+ module Elasticsearch
25
+ module Test
26
+ class IntegrationTestCase < ::Test::Unit::TestCase
27
+ extend Elasticsearch::Extensions::Test::StartupShutdown
28
+
29
+ startup { Elasticsearch::Extensions::Test::Cluster.start(nodes: 1) if ENV['SERVER'] and not Elasticsearch::Extensions::Test::Cluster.running? }
30
+ shutdown { Elasticsearch::Extensions::Test::Cluster.stop if ENV['SERVER'] && started? }
31
+ context "IntegrationTest" do; should "noop on Ruby 1.8" do; end; end if RUBY_1_8
32
+
33
+ def setup
34
+ tracer = ::Logger.new(STDERR)
35
+ tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n }.ansi(:faint)}\n" }
36
+ Elasticsearch::Persistence.client = Elasticsearch::Client.new \
37
+ host: "localhost:#{(ENV['TEST_CLUSTER_PORT'] || 9250)}",
38
+ tracer: (ENV['QUIET'] ? nil : tracer)
39
+ end
40
+
41
+ def teardown
42
+ Elasticsearch::Persistence.client.indices.delete index: '_all'
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class Elasticsearch::Persistence::ModuleTest < Test::Unit::TestCase
4
+ context "The Persistence module" do
5
+
6
+ context "client" do
7
+ should "have a default client" do
8
+ client = Elasticsearch::Persistence.client
9
+ assert_not_nil client
10
+ assert_instance_of Elasticsearch::Transport::Client, client
11
+ end
12
+
13
+ should "allow to set a client" do
14
+ begin
15
+ Elasticsearch::Persistence.client = "Foobar"
16
+ assert_equal "Foobar", Elasticsearch::Persistence.client
17
+ ensure
18
+ Elasticsearch::Persistence.client = nil
19
+ end
20
+ end
21
+
22
+ should "allow to set a client with DSL" do
23
+ begin
24
+ Elasticsearch::Persistence.client "Foobar"
25
+ assert_equal "Foobar", Elasticsearch::Persistence.client
26
+ ensure
27
+ Elasticsearch::Persistence.client = nil
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,51 @@
1
+ require 'test_helper'
2
+
3
+ class Elasticsearch::Persistence::RepositoryClassTest < Test::Unit::TestCase
4
+ context "The default repository class" do
5
+
6
+ context "when initialized" do
7
+ should "be created from the module" do
8
+ repository = Elasticsearch::Persistence::Repository.new
9
+ assert_instance_of Elasticsearch::Persistence::Repository::Class, repository
10
+ end
11
+
12
+ should "store and access the options" do
13
+ repository = Elasticsearch::Persistence::Repository::Class.new foo: 'bar'
14
+ assert_equal 'bar', repository.options[:foo]
15
+ end
16
+
17
+ should "instance eval a passed block" do
18
+ $foo = 100
19
+ repository = Elasticsearch::Persistence::Repository::Class.new() { $foo += 1 }
20
+ assert_equal 101, $foo
21
+ end
22
+
23
+ should "call a passed block with self" do
24
+ foo = 100
25
+ repository = Elasticsearch::Persistence::Repository::Class.new do |r|
26
+ assert_instance_of Elasticsearch::Persistence::Repository::Class, r
27
+ foo += 1
28
+ end
29
+ assert_equal 101, foo
30
+ end
31
+
32
+ should "configure the index name based on options" do
33
+ repository = Elasticsearch::Persistence::Repository::Class.new index: 'foobar'
34
+ assert_equal 'foobar', repository.index_name
35
+ end
36
+ end
37
+
38
+ should "include the repository methods" do
39
+ repository = Elasticsearch::Persistence::Repository::Class.new
40
+
41
+ %w( index_name document_type klass
42
+ mappings settings client client=
43
+ create_index! delete_index! refresh_index!
44
+ save delete serialize deserialize
45
+ exists? find search ).each do |method|
46
+ assert_respond_to repository, method
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class Elasticsearch::Persistence::RepositoryClientTest < Test::Unit::TestCase
4
+ context "The repository client" do
5
+ setup do
6
+ @shoulda_subject = Class.new() { include Elasticsearch::Persistence::Repository::Client }.new
7
+ end
8
+
9
+ should "have a default client" do
10
+ assert_not_nil subject.client
11
+ assert_instance_of Elasticsearch::Transport::Client, subject.client
12
+ end
13
+
14
+ should "allow to set a client" do
15
+ begin
16
+ subject.client = "Foobar"
17
+ assert_equal "Foobar", subject.client
18
+ ensure
19
+ subject.client = nil
20
+ end
21
+ end
22
+
23
+ should "allow to set the client with DSL" do
24
+ begin
25
+ subject.client "Foobar"
26
+ assert_equal "Foobar", subject.client
27
+ ensure
28
+ subject.client = nil
29
+ end
30
+ end
31
+ end
32
+ end