gummi 0.1.2 → 0.2.0
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.
- data/.gitignore +1 -0
- data/gummi.gemspec +7 -6
- data/lib/gummi.rb +32 -26
- data/lib/gummi/api.rb +3 -1
- data/lib/gummi/db_layer/default_index.rb +15 -0
- data/lib/gummi/db_layer/document.rb +206 -0
- data/lib/gummi/db_layer/document/attributes.rb +40 -0
- data/lib/gummi/db_layer/document/object.rb +15 -0
- data/lib/gummi/db_layer/document/search/filtered.rb +42 -0
- data/lib/gummi/db_layer/document/search/raw.rb +12 -0
- data/lib/gummi/db_layer/document/search/result.rb +34 -0
- data/lib/gummi/db_layer/document/search/searching.rb +51 -0
- data/lib/gummi/db_layer/fields/boolean.rb +13 -0
- data/lib/gummi/db_layer/fields/integer.rb +16 -0
- data/lib/gummi/db_layer/fields/keyword.rb +15 -0
- data/lib/gummi/db_layer/fields/ngram_and_plain.rb +20 -0
- data/lib/gummi/db_layer/fields/path_hierarchy.rb +15 -0
- data/lib/gummi/db_layer/fields/positive_integer.rb +21 -0
- data/lib/gummi/db_layer/fields/sanitized_string.rb +30 -0
- data/lib/gummi/db_layer/fields/string.rb +17 -0
- data/lib/gummi/db_layer/fields/time.rb +17 -0
- data/lib/gummi/db_layer/index.rb +150 -0
- data/lib/gummi/entity_layer/entity.rb +22 -0
- data/lib/gummi/errors.rb +7 -0
- data/lib/gummi/repository_layer/repository.rb +39 -0
- data/lib/gummi/repository_layer/repository/result.rb +42 -0
- data/lib/gummi/version.rb +1 -1
- data/lib/repobahn/repository.rb +25 -33
- data/lib/repobahn/repository/active_record.rb +17 -0
- data/spec/fixtures/admin/auto.rb +6 -0
- data/spec/fixtures/admin/cars.rb +12 -0
- data/spec/fixtures/admin/countries.rb +9 -0
- data/spec/fixtures/admin/country.rb +6 -0
- data/spec/fixtures/admin/db/country.rb +7 -0
- data/spec/fixtures/admin/db/vehicle.rb +7 -0
- data/spec/fixtures/cities.rb +7 -0
- data/spec/fixtures/city.rb +6 -0
- data/spec/fixtures/db/animal.rb +9 -0
- data/spec/fixtures/db/boat.rb +9 -0
- data/spec/fixtures/db/car.rb +9 -0
- data/spec/fixtures/db/city.rb +8 -0
- data/spec/fixtures/db/enemy.rb +10 -0
- data/spec/fixtures/db/game.rb +7 -0
- data/spec/fixtures/db/person.rb +15 -0
- data/spec/fixtures/db/rating.rb +11 -0
- data/spec/fixtures/db/ship.rb +18 -0
- data/spec/{models → fixtures}/people.rb +6 -2
- data/spec/{models → fixtures}/person.rb +3 -2
- data/spec/lib/gummi/db_layer/document_spec.rb +124 -0
- data/spec/lib/gummi/{entity_spec.rb → entity_layer/entity_spec.rb} +3 -1
- data/spec/lib/gummi/repository_layer/repository_spec.rb +63 -0
- data/spec/lib/repobahn/repository_spec.rb +72 -0
- data/spec/spec_helper.rb +37 -9
- metadata +87 -37
- data/lib/gummi/default_index.rb +0 -13
- data/lib/gummi/document.rb +0 -139
- data/lib/gummi/document/attributes.rb +0 -28
- data/lib/gummi/document/object.rb +0 -12
- data/lib/gummi/document/search/filtered.rb +0 -39
- data/lib/gummi/document/search/raw.rb +0 -9
- data/lib/gummi/document/search/result.rb +0 -25
- data/lib/gummi/document/search/searching.rb +0 -45
- data/lib/gummi/entity.rb +0 -20
- data/lib/gummi/fields/boolean.rb +0 -10
- data/lib/gummi/fields/integer.rb +0 -14
- data/lib/gummi/fields/keyword.rb +0 -13
- data/lib/gummi/fields/ngram_and_plain.rb +0 -18
- data/lib/gummi/fields/path_hierarchy.rb +0 -13
- data/lib/gummi/fields/positive_integer.rb +0 -19
- data/lib/gummi/fields/sanitized_string.rb +0 -28
- data/lib/gummi/fields/string.rb +0 -15
- data/lib/gummi/fields/time.rb +0 -15
- data/lib/gummi/index.rb +0 -146
- data/lib/gummi/repository.rb +0 -38
- data/lib/gummi/repository/result.rb +0 -30
- data/spec/lib/gummi/document_spec.rb +0 -73
- data/spec/lib/gummi/repository/result_spec.rb +0 -18
- data/spec/lib/gummi/repository_spec.rb +0 -81
- data/spec/models/db/person.rb +0 -15
@@ -0,0 +1,39 @@
|
|
1
|
+
module Gummi
|
2
|
+
module RepositoryLayer
|
3
|
+
module Repository
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
include Repobahn::Repository
|
8
|
+
after_conversion :set_id_and_version
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def get(id)
|
14
|
+
document = db_class.get id
|
15
|
+
db_instance_to_entity document if document
|
16
|
+
end
|
17
|
+
|
18
|
+
def search(&block)
|
19
|
+
search = db_class.new_filtered_search
|
20
|
+
yield search
|
21
|
+
Repository::Result.new search.execute, self
|
22
|
+
end
|
23
|
+
|
24
|
+
def overwrite(entity)
|
25
|
+
return false unless entity.valid?
|
26
|
+
document = db_class.new(entity.attributes)
|
27
|
+
document.overwrite
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_id_and_version(entity, db_instance)
|
31
|
+
entity.id = db_instance.id
|
32
|
+
entity.version = db_instance.version
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Gummi
|
2
|
+
module RepositoryLayer
|
3
|
+
module Repository
|
4
|
+
class Result
|
5
|
+
|
6
|
+
attr_reader :took, :total, :hits
|
7
|
+
|
8
|
+
def initialize(search_result, converter)
|
9
|
+
@search_result = search_result
|
10
|
+
@took = @search_result.took
|
11
|
+
@documents = @search_result.documents
|
12
|
+
@converter = converter
|
13
|
+
end
|
14
|
+
|
15
|
+
def facets
|
16
|
+
@facets ||= begin
|
17
|
+
response.facets.each_with_object({}) do |(name, content), facets|
|
18
|
+
facets[name] = Hash[content.terms.map(&:values)]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def total
|
24
|
+
documents.total_entries
|
25
|
+
end
|
26
|
+
|
27
|
+
def records
|
28
|
+
@records ||= begin
|
29
|
+
# Passing through the Leaflet Collection, but converting the records.
|
30
|
+
documents.map! { |document| converter.db_instance_to_entity(document) }
|
31
|
+
documents
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :search_result, :converter, :documents
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/gummi/version.rb
CHANGED
data/lib/repobahn/repository.rb
CHANGED
@@ -2,56 +2,48 @@ module Repobahn
|
|
2
2
|
module Repository
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
|
6
|
-
include Hooks
|
7
|
-
define_hook :after_conversion
|
8
|
-
end
|
5
|
+
include ::Repobahn::Repository::ActiveRecord
|
9
6
|
|
7
|
+
included do
|
8
|
+
include Hooks
|
9
|
+
define_hook :after_conversion
|
10
|
+
end
|
10
11
|
|
11
12
|
module ClassMethods
|
12
13
|
|
13
|
-
def
|
14
|
-
@
|
15
|
-
|
16
|
-
|
17
|
-
def entity_model=(klass)
|
18
|
-
@entity_model = klass
|
19
|
-
end
|
20
|
-
|
21
|
-
def db_model
|
22
|
-
@db_model || default_db_model
|
14
|
+
def db_class(*args)
|
15
|
+
@db_class = args.first unless args.empty?
|
16
|
+
@db_class || default_db_class
|
23
17
|
end
|
24
18
|
|
25
|
-
def
|
26
|
-
@
|
19
|
+
def entity_class(*args)
|
20
|
+
@entity_class = args.first unless args.empty?
|
21
|
+
@entity_class || default_entity_class
|
27
22
|
end
|
28
23
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
24
|
+
def db_instances_to_entities(db_instances)
|
25
|
+
entities = Array(db_instances).map { |db_instance| db_instance_to_entity(db_instance) }
|
26
|
+
entities.length > 1 ? entities : entities.first
|
32
27
|
end
|
33
28
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
entity
|
39
|
-
end
|
40
|
-
entities.length > 1 ? entities : entities.first
|
29
|
+
def db_instance_to_entity(db_instance)
|
30
|
+
entity = entity_class.new(db_instance.attributes)
|
31
|
+
run_hook :after_conversion, entity, db_instance
|
32
|
+
entity
|
41
33
|
end
|
42
34
|
|
43
35
|
private
|
44
36
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
full_name.join('::').constantize
|
37
|
+
def default_db_class
|
38
|
+
parts = default_entity_class.to_s.split('::')
|
39
|
+
parts.insert -2, 'DB'
|
40
|
+
parts.join('::').constantize
|
50
41
|
end
|
51
42
|
|
52
|
-
def
|
53
|
-
|
43
|
+
def default_entity_class
|
44
|
+
name.singularize.constantize
|
54
45
|
end
|
46
|
+
|
55
47
|
end
|
56
48
|
end
|
57
49
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Repobahn
|
2
|
+
module Repository
|
3
|
+
module ActiveRecord
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
def find(id)
|
9
|
+
record = document_class.find id.to_i
|
10
|
+
document_to_entity record if record
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# example db model
|
2
|
+
|
3
|
+
module DB
|
4
|
+
class Person
|
5
|
+
include Gummi::DbLayer::Document
|
6
|
+
|
7
|
+
attribute :name, Gummi::DbLayer::Fields::String
|
8
|
+
attribute :computed_name, Gummi::DbLayer::Fields::String
|
9
|
+
attribute :born_at, Gummi::DbLayer::Fields::Time
|
10
|
+
|
11
|
+
def computed_name
|
12
|
+
name.upcase if name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Various attribute field types
|
2
|
+
|
3
|
+
require 'db/boat'
|
4
|
+
|
5
|
+
module DB
|
6
|
+
class Ship
|
7
|
+
include Gummi::DbLayer::Document
|
8
|
+
|
9
|
+
attribute :name, Gummi::DbLayer::Fields::String
|
10
|
+
attribute :tags, Gummi::DbLayer::Fields::Keyword
|
11
|
+
attribute :category, Gummi::DbLayer::Fields::PathHierarchy
|
12
|
+
attribute :height, Gummi::DbLayer::Fields::PositiveInteger
|
13
|
+
attribute :unsinkable, Gummi::DbLayer::Fields::Boolean
|
14
|
+
attribute :freetext, Gummi::DbLayer::Fields::NgramAndPlain
|
15
|
+
attribute :boat, Boat
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -1,9 +1,13 @@
|
|
1
|
+
require 'db/person'
|
2
|
+
require 'person'
|
3
|
+
|
1
4
|
class People
|
2
|
-
include Gummi::Repository
|
5
|
+
include Gummi::RepositoryLayer::Repository
|
3
6
|
|
4
7
|
after_conversion :convert_name
|
5
8
|
|
6
9
|
def self.convert_name(entity, db)
|
7
10
|
entity.converted_name = db.name.reverse
|
8
11
|
end
|
9
|
-
|
12
|
+
|
13
|
+
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# example entity model
|
2
|
+
|
2
3
|
class Person
|
3
4
|
|
4
5
|
class Car
|
5
|
-
include Gummi::Entity
|
6
|
+
include Gummi::EntityLayer::Entity
|
6
7
|
|
7
8
|
attribute :model, String
|
8
9
|
end
|
9
10
|
|
10
|
-
include Gummi::Entity
|
11
|
+
include Gummi::EntityLayer::Entity
|
11
12
|
|
12
13
|
attribute :name, String
|
13
14
|
attribute :converted_name, String
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'db/animal'
|
4
|
+
require 'db/car'
|
5
|
+
require 'db/enemy'
|
6
|
+
require 'db/game'
|
7
|
+
require 'db/person'
|
8
|
+
require 'db/rating'
|
9
|
+
require 'db/ship'
|
10
|
+
|
11
|
+
describe Gummi::DbLayer::Document do
|
12
|
+
|
13
|
+
context 'included' do
|
14
|
+
it 'adds accessors for id and version' do
|
15
|
+
model = DB::Ship.new
|
16
|
+
model.should respond_to :id
|
17
|
+
model.should respond_to :version
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'adds default attributes methods' do
|
21
|
+
model = DB::Ship.new name: 'Joe'
|
22
|
+
model.name.should == 'Joe'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'does not accept attributes without explicit type definition' do
|
26
|
+
expect { DB::Enemy.sync_mapping! }.to raise_error(Gummi::Errors::ImplicitMappingForbidden)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '.index' do
|
31
|
+
context 'without being specified' do
|
32
|
+
it 'defaults to the default index' do
|
33
|
+
DB::Game.index.should == Gummi::DbLayer::DefaultIndex
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'explicitly specified' do
|
38
|
+
it 'accepts the specification' do
|
39
|
+
DB::Car.index.should == Struct
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '.document_type' do
|
45
|
+
context 'without being specified' do
|
46
|
+
it 'defaults to the demodulized name' do
|
47
|
+
DB::Game.document_type.should == :game
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'explicitly specified' do
|
52
|
+
it 'accepts the specification' do
|
53
|
+
DB::Animal.document_type.should == :wild_animal
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'attributes' do
|
59
|
+
|
60
|
+
context 'date times' do
|
61
|
+
it 'coerces from elastics strings to real Time' do
|
62
|
+
time = Time.now
|
63
|
+
person = DB::Person.new(born_at: time)
|
64
|
+
person.overwrite
|
65
|
+
person_from_es = DB::Person.get person.id
|
66
|
+
person_from_es.born_at.should be_a Time
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'always stores time in UTC' do
|
70
|
+
time = Time.now.in_time_zone 'CET'
|
71
|
+
|
72
|
+
person = DB::Person.new(born_at: time)
|
73
|
+
person.born_at.zone.should == 'UTC'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'computed_attributes' do
|
78
|
+
|
79
|
+
let(:person) { DB::Person.new }
|
80
|
+
|
81
|
+
it 'adds them to the attributes hash' do
|
82
|
+
person.name = 'olof palme'
|
83
|
+
person.attributes[:computed_name].should == 'OLOF PALME'
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'computes every time' do
|
87
|
+
person.name = 'olof palme'
|
88
|
+
person.computed_name.should == person.name.upcase
|
89
|
+
person.name = 'carl bildt'
|
90
|
+
person.computed_name.should == person.name.upcase
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'provides a mapping' do
|
94
|
+
DB::Person.mapping.should include(computed_name: { type: 'string' })
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'getting from elastic' do
|
100
|
+
let(:person) { DB::Person.create(name: 'Buzz Lightyear') }
|
101
|
+
|
102
|
+
it 'returns an instance of the document_class' do
|
103
|
+
person_from_es = DB::Person.get(person.id)
|
104
|
+
person_from_es.should be_a DB::Person
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'child documents' do
|
109
|
+
let(:person) { DB::Person.create name: 'Superman' }
|
110
|
+
let(:rating) { DB::Rating.create person_id: person.id, stars: 5 }
|
111
|
+
|
112
|
+
it 'creates and retrieves child documents' do
|
113
|
+
persisted_rating = DB::Rating.get(rating.id, person.id)
|
114
|
+
persisted_rating.person_id.should == person.id
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#get' do
|
118
|
+
it 'demands the parent_id' do
|
119
|
+
expect { DB::Rating.get(rating.id) }.to raise_error(ArgumentError)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|