gummi 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +1 -0
  2. data/gummi.gemspec +7 -6
  3. data/lib/gummi.rb +32 -26
  4. data/lib/gummi/api.rb +3 -1
  5. data/lib/gummi/db_layer/default_index.rb +15 -0
  6. data/lib/gummi/db_layer/document.rb +206 -0
  7. data/lib/gummi/db_layer/document/attributes.rb +40 -0
  8. data/lib/gummi/db_layer/document/object.rb +15 -0
  9. data/lib/gummi/db_layer/document/search/filtered.rb +42 -0
  10. data/lib/gummi/db_layer/document/search/raw.rb +12 -0
  11. data/lib/gummi/db_layer/document/search/result.rb +34 -0
  12. data/lib/gummi/db_layer/document/search/searching.rb +51 -0
  13. data/lib/gummi/db_layer/fields/boolean.rb +13 -0
  14. data/lib/gummi/db_layer/fields/integer.rb +16 -0
  15. data/lib/gummi/db_layer/fields/keyword.rb +15 -0
  16. data/lib/gummi/db_layer/fields/ngram_and_plain.rb +20 -0
  17. data/lib/gummi/db_layer/fields/path_hierarchy.rb +15 -0
  18. data/lib/gummi/db_layer/fields/positive_integer.rb +21 -0
  19. data/lib/gummi/db_layer/fields/sanitized_string.rb +30 -0
  20. data/lib/gummi/db_layer/fields/string.rb +17 -0
  21. data/lib/gummi/db_layer/fields/time.rb +17 -0
  22. data/lib/gummi/db_layer/index.rb +150 -0
  23. data/lib/gummi/entity_layer/entity.rb +22 -0
  24. data/lib/gummi/errors.rb +7 -0
  25. data/lib/gummi/repository_layer/repository.rb +39 -0
  26. data/lib/gummi/repository_layer/repository/result.rb +42 -0
  27. data/lib/gummi/version.rb +1 -1
  28. data/lib/repobahn/repository.rb +25 -33
  29. data/lib/repobahn/repository/active_record.rb +17 -0
  30. data/spec/fixtures/admin/auto.rb +6 -0
  31. data/spec/fixtures/admin/cars.rb +12 -0
  32. data/spec/fixtures/admin/countries.rb +9 -0
  33. data/spec/fixtures/admin/country.rb +6 -0
  34. data/spec/fixtures/admin/db/country.rb +7 -0
  35. data/spec/fixtures/admin/db/vehicle.rb +7 -0
  36. data/spec/fixtures/cities.rb +7 -0
  37. data/spec/fixtures/city.rb +6 -0
  38. data/spec/fixtures/db/animal.rb +9 -0
  39. data/spec/fixtures/db/boat.rb +9 -0
  40. data/spec/fixtures/db/car.rb +9 -0
  41. data/spec/fixtures/db/city.rb +8 -0
  42. data/spec/fixtures/db/enemy.rb +10 -0
  43. data/spec/fixtures/db/game.rb +7 -0
  44. data/spec/fixtures/db/person.rb +15 -0
  45. data/spec/fixtures/db/rating.rb +11 -0
  46. data/spec/fixtures/db/ship.rb +18 -0
  47. data/spec/{models → fixtures}/people.rb +6 -2
  48. data/spec/{models → fixtures}/person.rb +3 -2
  49. data/spec/lib/gummi/db_layer/document_spec.rb +124 -0
  50. data/spec/lib/gummi/{entity_spec.rb → entity_layer/entity_spec.rb} +3 -1
  51. data/spec/lib/gummi/repository_layer/repository_spec.rb +63 -0
  52. data/spec/lib/repobahn/repository_spec.rb +72 -0
  53. data/spec/spec_helper.rb +37 -9
  54. metadata +87 -37
  55. data/lib/gummi/default_index.rb +0 -13
  56. data/lib/gummi/document.rb +0 -139
  57. data/lib/gummi/document/attributes.rb +0 -28
  58. data/lib/gummi/document/object.rb +0 -12
  59. data/lib/gummi/document/search/filtered.rb +0 -39
  60. data/lib/gummi/document/search/raw.rb +0 -9
  61. data/lib/gummi/document/search/result.rb +0 -25
  62. data/lib/gummi/document/search/searching.rb +0 -45
  63. data/lib/gummi/entity.rb +0 -20
  64. data/lib/gummi/fields/boolean.rb +0 -10
  65. data/lib/gummi/fields/integer.rb +0 -14
  66. data/lib/gummi/fields/keyword.rb +0 -13
  67. data/lib/gummi/fields/ngram_and_plain.rb +0 -18
  68. data/lib/gummi/fields/path_hierarchy.rb +0 -13
  69. data/lib/gummi/fields/positive_integer.rb +0 -19
  70. data/lib/gummi/fields/sanitized_string.rb +0 -28
  71. data/lib/gummi/fields/string.rb +0 -15
  72. data/lib/gummi/fields/time.rb +0 -15
  73. data/lib/gummi/index.rb +0 -146
  74. data/lib/gummi/repository.rb +0 -38
  75. data/lib/gummi/repository/result.rb +0 -30
  76. data/spec/lib/gummi/document_spec.rb +0 -73
  77. data/spec/lib/gummi/repository/result_spec.rb +0 -18
  78. data/spec/lib/gummi/repository_spec.rb +0 -81
  79. data/spec/models/db/person.rb +0 -15
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ spec/reports
16
16
  test/tmp
17
17
  test/version_tmp
18
18
  tmp
19
+ tags
data/gummi.gemspec CHANGED
@@ -17,12 +17,13 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency('virtus', '~> 1.0.0')
21
- spec.add_dependency('elasticsearch', '~> 0.4.0')
22
- spec.add_dependency('activesupport', '>= 3.0')
23
- spec.add_dependency('activemodel', '>= 3.0')
24
- spec.add_dependency('hooks', '~>0.3.3')
25
- spec.add_dependency('leaflet')
20
+ spec.add_dependency 'virtus', '~> 1.0.0'
21
+ spec.add_dependency 'elasticsearch', '~> 0.4.0'
22
+ spec.add_dependency 'activesupport', '>= 3.0'
23
+ spec.add_dependency 'activemodel', '>= 3.0'
24
+ spec.add_dependency 'hooks', '~>0.3.3'
25
+ spec.add_dependency 'leaflet'
26
+ spec.add_dependency 'hashie', '>= 2.0.0'
26
27
 
27
28
  spec.add_development_dependency('bundler', '~> 1.3')
28
29
  spec.add_development_dependency('pry')
data/lib/gummi.rb CHANGED
@@ -4,40 +4,46 @@ require 'active_support/core_ext'
4
4
  require 'active_model'
5
5
  require 'hooks'
6
6
  require 'leaflet'
7
+ require 'hashie/mash'
7
8
 
8
- require "repobahn/repository"
9
- require "repobahn/entity"
9
+ require 'repobahn/repository/active_record'
10
+ require 'repobahn/repository'
11
+ require 'repobahn/entity'
10
12
 
11
- require "gummi/version"
12
- require "gummi/api"
13
- require "gummi/document/attributes"
14
- require "gummi/document"
15
- require "gummi/entity"
16
- require "gummi/index"
17
- require "gummi/document/object"
18
- require "gummi/repository"
19
- require "gummi/repository/result"
20
- require "gummi/fields/boolean"
21
- require "gummi/fields/time"
22
- require "gummi/fields/integer"
23
- require "gummi/fields/positive_integer"
24
- require "gummi/fields/keyword"
25
- require "gummi/fields/ngram_and_plain"
26
- require "gummi/fields/path_hierarchy"
27
- require "gummi/fields/string"
28
- require "gummi/fields/sanitized_string"
29
- require "gummi/default_index"
30
- require "gummi/document/search/searching"
31
- require "gummi/document/search/filtered"
32
- require "gummi/document/search/raw"
33
- require "gummi/document/search/result"
13
+ require 'gummi/version'
14
+ require 'gummi/errors'
15
+ require 'gummi/api'
16
+
17
+ require 'gummi/db_layer/index'
18
+ require 'gummi/db_layer/document/attributes'
19
+ require 'gummi/db_layer/document/object'
20
+ require 'gummi/db_layer/document'
21
+ require 'gummi/db_layer/fields/boolean'
22
+ require 'gummi/db_layer/fields/time'
23
+ require 'gummi/db_layer/fields/integer'
24
+ require 'gummi/db_layer/fields/positive_integer'
25
+ require 'gummi/db_layer/fields/keyword'
26
+ require 'gummi/db_layer/fields/ngram_and_plain'
27
+ require 'gummi/db_layer/fields/path_hierarchy'
28
+ require 'gummi/db_layer/fields/string'
29
+ require 'gummi/db_layer/fields/sanitized_string'
30
+ require 'gummi/db_layer/default_index'
31
+ require 'gummi/db_layer/document/search/searching'
32
+ require 'gummi/db_layer/document/search/filtered'
33
+ require 'gummi/db_layer/document/search/raw'
34
+ require 'gummi/db_layer/document/search/result'
35
+
36
+ require 'gummi/repository_layer/repository'
37
+ require 'gummi/repository_layer/repository/result'
38
+
39
+ require 'gummi/entity_layer/entity'
34
40
 
35
41
  module Gummi
36
42
  def self.env
37
43
  if defined? Rails
38
44
  Rails.env
39
45
  else
40
- RAILS_ENV || "development"
46
+ RAILS_ENV || 'development'
41
47
  end
42
48
  end
43
49
  end
data/lib/gummi/api.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  module Gummi
2
2
  module API
3
+
3
4
  def self.client
4
5
  @client ||= ::Elasticsearch::Client.new log: false
5
6
  end
7
+
6
8
  end
7
- end
9
+ end
@@ -0,0 +1,15 @@
1
+ module Gummi
2
+ module DbLayer
3
+ class DefaultIndex
4
+ include Gummi::DbLayer::Index
5
+
6
+ def self.name
7
+ if defined? Rails
8
+ "#{Rails.application.class.name.deconstantize.underscore}_#{Rails.env}"
9
+ else
10
+ "gummi_#{Gummi.env}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,206 @@
1
+ module Gummi
2
+ module DbLayer
3
+ module Document
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include Virtus.model
8
+ include Gummi::DbLayer::Document::Attributes
9
+ end
10
+
11
+ # –––––––––––––
12
+ # Class Methods
13
+ # –––––––––––––
14
+
15
+ module ClassMethods
16
+
17
+ # ––––––––––––––––––––––
18
+ # Public Persistence API
19
+ # ––––––––––––––––––––––
20
+
21
+ def create(*args)
22
+ instance = new(*args)
23
+ instance.create ? instance : nil
24
+ end
25
+
26
+ def get(*args)
27
+ get! *args
28
+ rescue ::Elasticsearch::Transport::Transport::Errors::NotFound
29
+ nil
30
+ end
31
+
32
+ # –––––––––––––––––––––
33
+ # Public Conversion API
34
+ # –––––––––––––––––––––
35
+
36
+ def hits_to_documents(hits)
37
+ documents = [hits].flatten.map { |hit| hit_to_document(hit) }
38
+ documents.length > 1 ? documents : documents.first
39
+ end
40
+
41
+ def hit_to_document(hit)
42
+ attributes = { id: hit._id, version: hit._version }
43
+ attributes.merge!(parent_id_attribute_name => hit.fields._parent) if hit.fields && hit.fields._parent
44
+ attributes.merge! hit._source if hit._source
45
+ self.new attributes
46
+ end
47
+
48
+ # ––––––––––––––––––––––––––––––
49
+ # Index and Document definitions
50
+ # ––––––––––––––––––––––––––––––
51
+
52
+ def index(*args)
53
+ @index = args.first unless args.empty?
54
+ @index || Gummi::DbLayer::DefaultIndex
55
+ end
56
+
57
+ def document_type(*args)
58
+ @document_type = args.first.to_sym unless args.empty?
59
+ @document_type || name.demodulize.underscore.to_sym
60
+ end
61
+
62
+ def parent(model)
63
+ parent_document_type model.document_type
64
+ end
65
+
66
+ def parent_document_type(*args)
67
+ @parent_document_type = args.first unless args.empty?
68
+ parent_id_attribute_name "#{@parent_document_type}_id".to_sym if @parent_document_type && !parent_id_attribute_name
69
+ @parent_document_type
70
+ end
71
+
72
+ def parent_id_attribute_name(*args)
73
+ unless args.empty?
74
+ @parent_id_attribute_name = args.first
75
+ attr_accessor @parent_id_attribute_name
76
+ end
77
+ @parent_id_attribute_name
78
+ end
79
+
80
+ # ––––––––––––––––
81
+ # Public Index API
82
+ # ––––––––––––––––
83
+
84
+ def sync_mapping!
85
+ client.indices.put_mapping creation_options
86
+ end
87
+
88
+ def creation_options
89
+ result = {
90
+ index: index.name,
91
+ type: document_type,
92
+ body: {
93
+ document_type => {
94
+ properties: mapping,
95
+ }
96
+ }
97
+ }
98
+ result[:body][document_type].merge!(_parent: { type: parent_document_type }) if parent_document_type.present?
99
+ result
100
+ end
101
+
102
+ # –––––––––––––––––
103
+ # Public Search API
104
+ # –––––––––––––––––
105
+
106
+ def new_filtered_search(options = {})
107
+ Gummi::DbLayer::Document::Search::Filtered.new default_search_options.merge(options)
108
+ end
109
+
110
+ def new_raw_search(options = {})
111
+ Gummi::DbLayer::Document::Search::Raw.new default_search_options.merge(options)
112
+ end
113
+
114
+ def default_search_options
115
+ {
116
+ document_class: self,
117
+ index: index.name,
118
+ type: document_type,
119
+ }
120
+ end
121
+
122
+ # –––––––––––––––––––––––––––
123
+ # Internal Backend Connection
124
+ # –––––––––––––––––––––––––––
125
+
126
+ def client
127
+ Gummi::API.client
128
+ end
129
+
130
+ private
131
+
132
+ # ––––––––––––––––––––––––
133
+ # Internal Persistence API
134
+ # ––––––––––––––––––––––––
135
+
136
+ def get!(id, parent_id = nil)
137
+ options = { index: index.name, type: document_type, id: id, fields: %w{ _source _parent } }
138
+ if parent_id
139
+ options.merge! parent: parent_id
140
+ elsif parent_document_type
141
+ raise ArgumentError, "The parent_id attribute is required for getting #{name} from Elastic Search"
142
+ end
143
+ response = Hashie::Mash.new client.get options
144
+ hit_to_document response
145
+ end
146
+
147
+ end
148
+
149
+ # ––––––––––––––––
150
+ # Instance Methods
151
+ # ––––––––––––––––
152
+
153
+ attr_accessor :id
154
+ attr_accessor :version
155
+
156
+ # ––––––––––––––––––––––
157
+ # Public Persistence API
158
+ # ––––––––––––––––––––––
159
+
160
+ def create(method = :create)
161
+ attributes = self.attributes
162
+ if parent_id_attribute_name && parent_id = self.send(parent_id_attribute_name)
163
+ options = { parent: parent_id }
164
+ else
165
+ options = {}
166
+ end
167
+ raise ArgumentError unless [:create, :index].include?(method)
168
+ response = Hashie::Mash.new client.send(method, options.merge(index: index.name, type: document_type, id: self.id, body: attributes))
169
+ if response.ok
170
+ self.id = response._id
171
+ self.version = response._version
172
+ true
173
+ else
174
+ false
175
+ end
176
+ end
177
+
178
+ def overwrite
179
+ create :index
180
+ end
181
+
182
+ private
183
+
184
+ # ––––––––––––––––––––
185
+ # Class method proxies
186
+ # ––––––––––––––––––––
187
+
188
+ def index
189
+ self.class.index
190
+ end
191
+
192
+ def document_type
193
+ self.class.document_type
194
+ end
195
+
196
+ def parent_id_attribute_name
197
+ self.class.parent_id_attribute_name
198
+ end
199
+
200
+ def client
201
+ self.class.client
202
+ end
203
+
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,40 @@
1
+ module Gummi
2
+ module DbLayer
3
+ module Document
4
+ module Attributes
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def mapping_for_attribute(attribute)
10
+ if attribute.is_a? Virtus::Attribute::EmbeddedValue
11
+ { properties: attribute.primitive.mapping }
12
+ elsif attribute.is_a? Virtus::Attribute::Collection
13
+ mapping_for_attribute(attribute.member_type)
14
+ else
15
+ begin
16
+ attribute.mapping
17
+ rescue NoMethodError => exception
18
+ if exception.message.include?("`mapping'")
19
+ raise Errors::ImplicitMappingForbidden, "Sorry, you have to explicitly define the attribute type for #{attribute.instance_variable_name rescue nil} in #{self} or maybe you tried to use Array[] where it is not allowed. Original Exception: #{exception.message}"
20
+ else
21
+ raise exception
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def mapping
28
+ result = {}
29
+ attribute_set.each do |attribute|
30
+ result.merge! attribute.name => mapping_for_attribute(attribute)
31
+ end
32
+ result
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ module Gummi
2
+ module DbLayer
3
+ module Document
4
+ module Object
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include Virtus.model
9
+ include Gummi::DbLayer::Document::Attributes
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ module Gummi
2
+ module DbLayer
3
+ module Document
4
+ module Search
5
+ class Filtered
6
+ include Gummi::DbLayer::Document::Search::Searching
7
+
8
+ attribute :query_string, Gummi::DbLayer::Fields::SanitizedString
9
+ attribute :query_filters, Array[Hash], default: []
10
+ attribute :facets, Hash, default: {}
11
+
12
+ def to_client_args
13
+ args = super
14
+ args[:body] = { query: filtered, facets: facets }
15
+ args
16
+ end
17
+
18
+ def query
19
+ if query_string.present?
20
+ {query_string: { query: query_string}}
21
+ else
22
+ {match_all: {}}
23
+ end
24
+ end
25
+
26
+ def filtered
27
+ { 'filtered' => { 'query' => query, 'filter' => process_query_filters }}
28
+ end
29
+
30
+ def process_query_filters
31
+ if query_filters.length > 1
32
+ {and: query_filters}
33
+ else
34
+ query_filters.first
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ module Gummi
2
+ module DbLayer
3
+ module Document
4
+ module Search
5
+ class Raw
6
+ include Gummi::DbLayer::Document::Search::Searching
7
+
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end