elasticsearch-persistence 0.0.0 → 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 (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