elasticsearch-persistence-queryable 0.1.8

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/CHANGELOG.md +16 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +13 -0
  6. data/README.md +678 -0
  7. data/Rakefile +57 -0
  8. data/elasticsearch-persistence.gemspec +57 -0
  9. data/examples/music/album.rb +34 -0
  10. data/examples/music/artist.rb +50 -0
  11. data/examples/music/artists/_form.html.erb +8 -0
  12. data/examples/music/artists/artists_controller.rb +67 -0
  13. data/examples/music/artists/artists_controller_test.rb +53 -0
  14. data/examples/music/artists/index.html.erb +57 -0
  15. data/examples/music/artists/show.html.erb +51 -0
  16. data/examples/music/assets/application.css +226 -0
  17. data/examples/music/assets/autocomplete.css +48 -0
  18. data/examples/music/assets/blank_cover.png +0 -0
  19. data/examples/music/assets/form.css +113 -0
  20. data/examples/music/index_manager.rb +60 -0
  21. data/examples/music/search/index.html.erb +93 -0
  22. data/examples/music/search/search_controller.rb +41 -0
  23. data/examples/music/search/search_controller_test.rb +9 -0
  24. data/examples/music/search/search_helper.rb +15 -0
  25. data/examples/music/suggester.rb +45 -0
  26. data/examples/music/template.rb +392 -0
  27. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.css +7 -0
  28. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.js +6 -0
  29. data/examples/notes/.gitignore +7 -0
  30. data/examples/notes/Gemfile +28 -0
  31. data/examples/notes/README.markdown +36 -0
  32. data/examples/notes/application.rb +238 -0
  33. data/examples/notes/config.ru +7 -0
  34. data/examples/notes/test.rb +118 -0
  35. data/lib/elasticsearch/per_thread_registry.rb +53 -0
  36. data/lib/elasticsearch/persistence/client.rb +51 -0
  37. data/lib/elasticsearch/persistence/inheritence.rb +9 -0
  38. data/lib/elasticsearch/persistence/model/base.rb +95 -0
  39. data/lib/elasticsearch/persistence/model/callbacks.rb +37 -0
  40. data/lib/elasticsearch/persistence/model/errors.rb +9 -0
  41. data/lib/elasticsearch/persistence/model/find.rb +155 -0
  42. data/lib/elasticsearch/persistence/model/gateway_delegation.rb +23 -0
  43. data/lib/elasticsearch/persistence/model/hash_wrapper.rb +17 -0
  44. data/lib/elasticsearch/persistence/model/rails.rb +39 -0
  45. data/lib/elasticsearch/persistence/model/store.rb +271 -0
  46. data/lib/elasticsearch/persistence/model.rb +148 -0
  47. data/lib/elasticsearch/persistence/null_relation.rb +56 -0
  48. data/lib/elasticsearch/persistence/query_cache.rb +68 -0
  49. data/lib/elasticsearch/persistence/querying.rb +21 -0
  50. data/lib/elasticsearch/persistence/relation/delegation.rb +130 -0
  51. data/lib/elasticsearch/persistence/relation/finder_methods.rb +39 -0
  52. data/lib/elasticsearch/persistence/relation/merger.rb +179 -0
  53. data/lib/elasticsearch/persistence/relation/query_builder.rb +279 -0
  54. data/lib/elasticsearch/persistence/relation/query_methods.rb +362 -0
  55. data/lib/elasticsearch/persistence/relation/search_option_methods.rb +44 -0
  56. data/lib/elasticsearch/persistence/relation/spawn_methods.rb +61 -0
  57. data/lib/elasticsearch/persistence/relation.rb +110 -0
  58. data/lib/elasticsearch/persistence/repository/class.rb +71 -0
  59. data/lib/elasticsearch/persistence/repository/find.rb +73 -0
  60. data/lib/elasticsearch/persistence/repository/naming.rb +115 -0
  61. data/lib/elasticsearch/persistence/repository/response/results.rb +105 -0
  62. data/lib/elasticsearch/persistence/repository/search.rb +156 -0
  63. data/lib/elasticsearch/persistence/repository/serialize.rb +31 -0
  64. data/lib/elasticsearch/persistence/repository/store.rb +94 -0
  65. data/lib/elasticsearch/persistence/repository.rb +77 -0
  66. data/lib/elasticsearch/persistence/scoping/default.rb +137 -0
  67. data/lib/elasticsearch/persistence/scoping/named.rb +70 -0
  68. data/lib/elasticsearch/persistence/scoping.rb +52 -0
  69. data/lib/elasticsearch/persistence/version.rb +5 -0
  70. data/lib/elasticsearch/persistence.rb +157 -0
  71. data/lib/elasticsearch/rails_compatibility.rb +17 -0
  72. data/lib/rails/generators/elasticsearch/model/model_generator.rb +21 -0
  73. data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +9 -0
  74. data/lib/rails/generators/elasticsearch_generator.rb +2 -0
  75. data/lib/rails/instrumentation/railtie.rb +31 -0
  76. data/lib/rails/instrumentation.rb +10 -0
  77. data/test/integration/model/model_basic_test.rb +157 -0
  78. data/test/integration/repository/custom_class_test.rb +85 -0
  79. data/test/integration/repository/customized_class_test.rb +82 -0
  80. data/test/integration/repository/default_class_test.rb +114 -0
  81. data/test/integration/repository/virtus_model_test.rb +114 -0
  82. data/test/test_helper.rb +53 -0
  83. data/test/unit/model_base_test.rb +48 -0
  84. data/test/unit/model_find_test.rb +148 -0
  85. data/test/unit/model_gateway_test.rb +99 -0
  86. data/test/unit/model_rails_test.rb +88 -0
  87. data/test/unit/model_store_test.rb +514 -0
  88. data/test/unit/persistence_test.rb +32 -0
  89. data/test/unit/repository_class_test.rb +51 -0
  90. data/test/unit/repository_client_test.rb +32 -0
  91. data/test/unit/repository_find_test.rb +388 -0
  92. data/test/unit/repository_indexing_test.rb +37 -0
  93. data/test/unit/repository_module_test.rb +146 -0
  94. data/test/unit/repository_naming_test.rb +146 -0
  95. data/test/unit/repository_response_results_test.rb +98 -0
  96. data/test/unit/repository_search_test.rb +117 -0
  97. data/test/unit/repository_serialize_test.rb +57 -0
  98. data/test/unit/repository_store_test.rb +303 -0
  99. metadata +487 -0
@@ -0,0 +1,148 @@
1
+ require 'test_helper'
2
+
3
+ require 'active_model'
4
+ require 'virtus'
5
+
6
+ require 'elasticsearch/persistence/model/errors'
7
+ require 'elasticsearch/persistence/model/find'
8
+
9
+ class Elasticsearch::Persistence::ModelFindTest < Test::Unit::TestCase
10
+ context "The model find module," do
11
+
12
+ class DummyFindModel
13
+ include ActiveModel::Naming
14
+ include ActiveModel::Conversion
15
+ include ActiveModel::Serialization
16
+ include ActiveModel::Serializers::JSON
17
+ include ActiveModel::Validations
18
+
19
+ include Virtus.model
20
+
21
+ extend Elasticsearch::Persistence::Model::Find::ClassMethods
22
+
23
+ extend ActiveModel::Callbacks
24
+ define_model_callbacks :create, :save, :update, :destroy
25
+ define_model_callbacks :find, :touch, only: :after
26
+
27
+ attribute :title, String
28
+ attribute :count, Integer, default: 0
29
+ attribute :created_at, DateTime, default: lambda { |o,a| Time.now.utc }
30
+ attribute :updated_at, DateTime, default: lambda { |o,a| Time.now.utc }
31
+ end
32
+
33
+ setup do
34
+ @gateway = stub(client: stub(), index_name: 'foo', document_type: 'bar')
35
+ DummyFindModel.stubs(:gateway).returns(@gateway)
36
+
37
+ @response = MultiJson.load <<-JSON
38
+ {
39
+ "took": 14,
40
+ "timed_out": false,
41
+ "_shards": {
42
+ "total": 5,
43
+ "successful": 5,
44
+ "failed": 0
45
+ },
46
+ "hits": {
47
+ "total": 1,
48
+ "max_score": 1.0,
49
+ "hits": [
50
+ {
51
+ "_index": "dummy",
52
+ "_type": "dummy",
53
+ "_id": "abc123",
54
+ "_score": 1.0,
55
+ "_source": {
56
+ "name": "TEST"
57
+ }
58
+ }
59
+ ]
60
+ }
61
+ }
62
+ JSON
63
+ end
64
+
65
+ should "find all records" do
66
+ @gateway
67
+ .expects(:search)
68
+ .with({ query: { match_all: {} }, size: 10_000 })
69
+ .returns(@response)
70
+
71
+ DummyFindModel.all
72
+ end
73
+
74
+ should "pass options when finding all records" do
75
+ @gateway
76
+ .expects(:search)
77
+ .with({ query: { match: { title: 'test' } }, size: 10_000, routing: 'abc123' })
78
+ .returns(@response)
79
+
80
+ DummyFindModel.all( { query: { match: { title: 'test' } }, routing: 'abc123' } )
81
+ end
82
+
83
+ context "finding via scan/scroll" do
84
+ setup do
85
+ @gateway
86
+ .expects(:deserialize)
87
+ .with('_source' => {'foo' => 'bar'})
88
+ .returns('_source' => {'foo' => 'bar'})
89
+
90
+ @gateway.client
91
+ .expects(:search)
92
+ .with do |arguments|
93
+ assert_equal 'scan', arguments[:search_type]
94
+ assert_equal 'foo', arguments[:index]
95
+ assert_equal 'bar', arguments[:type]
96
+ true
97
+ end
98
+ .returns(MultiJson.load('{"_scroll_id":"abc123==", "hits":{"hits":[]}}'))
99
+
100
+ @gateway.client
101
+ .expects(:scroll)
102
+ .twice
103
+ .returns(MultiJson.load('{"_scroll_id":"abc456==", "hits":{"hits":[{"_source":{"foo":"bar"}}]}}'))
104
+ .then
105
+ .returns(MultiJson.load('{"_scroll_id":"abc789==", "hits":{"hits":[]}}'))
106
+ end
107
+
108
+ should "find all records in batches" do
109
+ @doc = nil
110
+ result = DummyFindModel.find_in_batches { |batch| @doc = batch.first['_source']['foo'] }
111
+
112
+ assert_equal 'abc789==', result
113
+ assert_equal 'bar', @doc
114
+ end
115
+
116
+ should "return an Enumerator for find in batches" do
117
+ @doc = nil
118
+ assert_nothing_raised do
119
+ e = DummyFindModel.find_in_batches
120
+ assert_instance_of Enumerator, e
121
+
122
+ e.each { |batch| @doc = batch.first['_source']['foo'] }
123
+ assert_equal 'bar', @doc
124
+ end
125
+ end
126
+
127
+ should "find each" do
128
+ @doc = nil
129
+ result = DummyFindModel.find_each { |doc| @doc = doc['_source']['foo'] }
130
+
131
+ assert_equal 'abc789==', result
132
+ assert_equal 'bar', @doc
133
+ end
134
+
135
+ should "return an Enumerator for find each" do
136
+ @doc = nil
137
+ assert_nothing_raised do
138
+ e = DummyFindModel.find_each
139
+ assert_instance_of Enumerator, e
140
+
141
+ e.each { |doc| @doc = doc['_source']['foo'] }
142
+ assert_equal 'bar', @doc
143
+ end
144
+ end
145
+ end
146
+
147
+ end
148
+ end
@@ -0,0 +1,99 @@
1
+ require 'test_helper'
2
+
3
+ require 'elasticsearch/persistence/model'
4
+ require 'elasticsearch/persistence/model/rails'
5
+
6
+ class Elasticsearch::Persistence::ModelGatewayTest < Test::Unit::TestCase
7
+ context "The model gateway" do
8
+ setup do
9
+ class DummyGatewayModel
10
+ include Elasticsearch::Persistence::Model
11
+ end
12
+ end
13
+
14
+ teardown do
15
+ Elasticsearch::Persistence::ModelGatewayTest.__send__ :remove_const, :DummyGatewayModel \
16
+ rescue NameError; nil
17
+ end
18
+
19
+ should "be accessible" do
20
+ assert_instance_of Elasticsearch::Persistence::Repository::Class, DummyGatewayModel.gateway
21
+
22
+ $a = 0
23
+ DummyGatewayModel.gateway { $a += 1 }
24
+ assert_equal 1, $a
25
+
26
+ @b = 0
27
+ def run!; DummyGatewayModel.gateway { |g| @b += 1 }; end
28
+ run!
29
+ assert_equal 1, @b
30
+
31
+ assert_equal DummyGatewayModel, DummyGatewayModel.gateway.klass
32
+ end
33
+
34
+ should "define common attributes" do
35
+ d = DummyGatewayModel.new
36
+
37
+ assert_respond_to d, :updated_at
38
+ assert_respond_to d, :created_at
39
+ end
40
+
41
+ should "allow to configure settings" do
42
+ DummyGatewayModel.settings(number_of_shards: 1)
43
+
44
+ assert_equal 1, DummyGatewayModel.settings.to_hash[:number_of_shards]
45
+ end
46
+
47
+ should "allow to configure mappings" do
48
+ DummyGatewayModel.mapping { indexes :name, analyzer: 'snowball' }
49
+
50
+ assert_equal 'snowball',
51
+ DummyGatewayModel.mapping.to_hash[:dummy_gateway_model][:properties][:name][:analyzer]
52
+ end
53
+
54
+ should "configure the mapping via attribute" do
55
+ DummyGatewayModel.attribute :name, String, mapping: { analyzer: 'snowball' }
56
+
57
+ assert_respond_to DummyGatewayModel, :name
58
+ assert_equal 'snowball',
59
+ DummyGatewayModel.mapping.to_hash[:dummy_gateway_model][:properties][:name][:analyzer]
60
+ end
61
+
62
+ should "configure the mapping via an attribute block" do
63
+ DummyGatewayModel.attribute :name, String do
64
+ indexes :name, analyzer: 'custom'
65
+ end
66
+
67
+ assert_respond_to DummyGatewayModel, :name
68
+ assert_equal 'custom',
69
+ DummyGatewayModel.mapping.to_hash[:dummy_gateway_model][:properties][:name][:analyzer]
70
+ end
71
+
72
+ should "properly look up types for classes" do
73
+ assert_equal 'string', Elasticsearch::Persistence::Model::Utils::lookup_type(String)
74
+ assert_equal 'integer', Elasticsearch::Persistence::Model::Utils::lookup_type(Integer)
75
+ assert_equal 'float', Elasticsearch::Persistence::Model::Utils::lookup_type(Float)
76
+ assert_equal 'date', Elasticsearch::Persistence::Model::Utils::lookup_type(Date)
77
+ assert_equal 'boolean', Elasticsearch::Persistence::Model::Utils::lookup_type(Virtus::Attribute::Boolean)
78
+ end
79
+
80
+ should "remove IDs from hash when serializing" do
81
+ assert_equal( {foo: 'bar'}, DummyGatewayModel.gateway.serialize(id: '123', foo: 'bar') )
82
+ end
83
+
84
+ should "set IDs from hash when deserializing" do
85
+ assert_equal 'abc123', DummyGatewayModel.gateway.deserialize('_id' => 'abc123', '_source' => {}).id
86
+ end
87
+
88
+ should "set @persisted variable from hash when deserializing" do
89
+ assert DummyGatewayModel.gateway.deserialize('_id' => 'abc123', '_source' => {}).instance_variable_get(:@persisted)
90
+ end
91
+
92
+ should "allow to access the raw hit from results as Hashie::Mash" do
93
+ assert_equal 0.42, DummyGatewayModel.gateway.deserialize('_score' => 0.42, '_source' => {}).hit._score
94
+ end
95
+
96
+
97
+
98
+ end
99
+ end
@@ -0,0 +1,88 @@
1
+ require 'test_helper'
2
+
3
+ require 'elasticsearch/persistence/model'
4
+ require 'elasticsearch/persistence/model/rails'
5
+
6
+ require 'rails'
7
+ require 'action_controller/railtie'
8
+ require 'action_view/railtie'
9
+
10
+ class ::MyRailsModel
11
+ include Elasticsearch::Persistence::Model
12
+ include Elasticsearch::Persistence::Model::Rails
13
+
14
+ attribute :name, String, mapping: { analyzer: 'string' }
15
+ attribute :published_at, DateTime
16
+ attribute :published_on, Date
17
+ end
18
+
19
+ class Application < Rails::Application
20
+ config.eager_load = false
21
+ config.root = File.dirname(File.expand_path('../../../tmp', __FILE__))
22
+ config.logger = Logger.new($stderr)
23
+
24
+ routes.append do
25
+ resources :my_rails_models
26
+ end
27
+ end
28
+
29
+ class ApplicationController < ActionController::Base
30
+ include Application.routes.url_helpers
31
+ include ActionController::UrlFor
32
+ end
33
+ ApplicationController.default_url_options = { host: 'localhost' }
34
+ ApplicationController._routes.append { resources :my_rails_models }
35
+
36
+ class MyRailsModelController < ApplicationController; end
37
+
38
+ Application.initialize!
39
+
40
+ class Elasticsearch::Persistence::ModelRailsTest < Test::Unit::TestCase
41
+ context "The model in a Rails application" do
42
+
43
+ should "generate proper URLs and paths" do
44
+ model = MyRailsModel.new name: 'Test'
45
+ model.stubs(:id).returns(1)
46
+ model.stubs(:persisted?).returns(true)
47
+
48
+ controller = MyRailsModelController.new
49
+ controller.request = ActionDispatch::Request.new({})
50
+
51
+ assert_equal 'http://localhost/my_rails_models/1', controller.url_for(model)
52
+ assert_equal '/my_rails_models/1/edit', controller.edit_my_rails_model_path(model)
53
+ end
54
+
55
+ should "generate a link" do
56
+ class MyView; include ActionView::Helpers::UrlHelper; end
57
+
58
+ model = MyRailsModel.new name: 'Test'
59
+ view = MyView.new
60
+ view.expects(:url_for).with(model).returns('foo/bar')
61
+
62
+ assert_equal '<a href="foo/bar">Show</a>', view.link_to('Show', model)
63
+ end
64
+
65
+ should "parse DateTime from Rails forms" do
66
+ params = { "published_at(1i)"=>"2014",
67
+ "published_at(2i)"=>"1",
68
+ "published_at(3i)"=>"1",
69
+ "published_at(4i)"=>"12",
70
+ "published_at(5i)"=>"00"
71
+ }
72
+
73
+ m = MyRailsModel.new params
74
+ assert_equal "2014-01-01T12:00:00+00:00", m.published_at.iso8601
75
+ end
76
+
77
+ should "parse Date from Rails forms" do
78
+ params = { "published_on(1i)"=>"2014",
79
+ "published_on(2i)"=>"1",
80
+ "published_on(3i)"=>"1"
81
+ }
82
+
83
+ m = MyRailsModel.new params
84
+ assert_equal "2014-01-01", m.published_on.iso8601
85
+ end
86
+
87
+ end
88
+ end