perpetuity 0.7.3 → 1.0.0.beta

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile +3 -0
  4. data/README.md +18 -8
  5. data/lib/perpetuity.rb +4 -4
  6. data/lib/perpetuity/attribute.rb +9 -0
  7. data/lib/perpetuity/attribute_set.rb +4 -6
  8. data/lib/perpetuity/data_injectable.rb +1 -1
  9. data/lib/perpetuity/duplicator.rb +27 -0
  10. data/lib/perpetuity/mapper.rb +9 -14
  11. data/lib/perpetuity/version.rb +1 -1
  12. data/perpetuity.gemspec +0 -1
  13. data/spec/integration/associations_spec.rb +2 -6
  14. data/spec/integration/indexing_spec.rb +1 -1
  15. data/spec/integration/persistence_spec.rb +3 -2
  16. data/spec/integration/retrieval_spec.rb +5 -13
  17. data/spec/perpetuity/attribute_set_spec.rb +1 -1
  18. data/spec/perpetuity/attribute_spec.rb +6 -1
  19. data/spec/perpetuity/duplicator_spec.rb +35 -0
  20. data/spec/perpetuity/mapper_spec.rb +21 -2
  21. data/spec/perpetuity_spec.rb +2 -2
  22. data/spec/spec_helper.rb +8 -2
  23. data/spec/support/test_classes.rb +22 -26
  24. data/spec/support/test_classes/topic.rb +5 -0
  25. data/spec/support/test_classes/user.rb +1 -1
  26. metadata +7 -55
  27. data/lib/perpetuity/mongodb.rb +0 -230
  28. data/lib/perpetuity/mongodb/index.rb +0 -52
  29. data/lib/perpetuity/mongodb/nil_query.rb +0 -11
  30. data/lib/perpetuity/mongodb/query.rb +0 -33
  31. data/lib/perpetuity/mongodb/query_attribute.rb +0 -66
  32. data/lib/perpetuity/mongodb/query_expression.rb +0 -94
  33. data/lib/perpetuity/mongodb/query_intersection.rb +0 -16
  34. data/lib/perpetuity/mongodb/query_union.rb +0 -16
  35. data/lib/perpetuity/mongodb/serializer.rb +0 -174
  36. data/lib/perpetuity/validations.rb +0 -1
  37. data/lib/perpetuity/validations/length.rb +0 -36
  38. data/lib/perpetuity/validations/presence.rb +0 -14
  39. data/lib/perpetuity/validations/validation_set.rb +0 -28
  40. data/spec/integration/mongodb_spec.rb +0 -218
  41. data/spec/integration/validations_spec.rb +0 -17
  42. data/spec/perpetuity/mongodb/index_spec.rb +0 -44
  43. data/spec/perpetuity/mongodb/query_attribute_spec.rb +0 -58
  44. data/spec/perpetuity/mongodb/query_expression_spec.rb +0 -67
  45. data/spec/perpetuity/mongodb/query_intersection_spec.rb +0 -16
  46. data/spec/perpetuity/mongodb/query_spec.rb +0 -79
  47. data/spec/perpetuity/mongodb/query_union_spec.rb +0 -16
  48. data/spec/perpetuity/mongodb/serializer_spec.rb +0 -212
  49. data/spec/perpetuity/validations/length_spec.rb +0 -53
  50. data/spec/perpetuity/validations/presence_spec.rb +0 -30
  51. data/spec/perpetuity/validations_spec.rb +0 -87
@@ -1 +0,0 @@
1
- require 'perpetuity/validations/validation_set'
@@ -1,36 +0,0 @@
1
- module Perpetuity
2
- module Validations
3
- class Length
4
- def initialize attribute, options
5
- @attribute = attribute
6
- @at_least = nil
7
- @at_most = nil
8
- options.each do |option, value|
9
- send option, value
10
- end
11
- end
12
-
13
- def pass? object
14
- length = object.send(@attribute).length
15
-
16
- return false unless @at_least.nil? or @at_least <= length
17
- return false unless @at_most.nil? or @at_most >= length
18
-
19
- true
20
- end
21
-
22
- def at_least value
23
- @at_least = value
24
- end
25
-
26
- def at_most value
27
- @at_most = value
28
- end
29
-
30
- def between range
31
- at_least range.min
32
- at_most range.max
33
- end
34
- end
35
- end
36
- end
@@ -1,14 +0,0 @@
1
- module Perpetuity
2
- module Validations
3
- class Presence
4
- def initialize attribute
5
- @attribute = attribute
6
- end
7
-
8
- def pass? object
9
- !object.send(@attribute).nil? &&
10
- object.send(@attribute).strip != ''
11
- end
12
- end
13
- end
14
- end
@@ -1,28 +0,0 @@
1
- require 'perpetuity/validations/length'
2
- require 'perpetuity/validations/presence'
3
- require 'set'
4
-
5
- module Perpetuity
6
- class ValidationSet < Set
7
-
8
- def valid? object
9
- each do |validation|
10
- return false unless validation.pass?(object)
11
- end
12
-
13
- true
14
- end
15
-
16
- def invalid? object
17
- !valid? object
18
- end
19
-
20
- def present attribute
21
- self << Perpetuity::Validations::Presence.new(attribute)
22
- end
23
-
24
- def length attribute, options = {}
25
- self << Perpetuity::Validations::Length.new(attribute, options)
26
- end
27
- end
28
- end
@@ -1,218 +0,0 @@
1
- require 'perpetuity/mongodb'
2
- require 'date'
3
-
4
- module Perpetuity
5
- describe MongoDB do
6
- let(:mongo) { MongoDB.new db: 'perpetuity_gem_test' }
7
- let(:klass) { String }
8
- subject { mongo }
9
-
10
- it 'is not connected when instantiated' do
11
- mongo.should_not be_connected
12
- end
13
-
14
- it 'connects to its host' do
15
- mongo.connect
16
- mongo.should be_connected
17
- end
18
-
19
- it 'connects automatically when accessing the database' do
20
- mongo.database
21
- mongo.should be_connected
22
- end
23
-
24
- describe 'initialization params' do
25
- let(:host) { double('host') }
26
- let(:port) { double('port') }
27
- let(:db) { double('db') }
28
- let(:pool_size) { double('pool size') }
29
- let(:username) { double('username') }
30
- let(:password) { double('password') }
31
- let(:mongo) do
32
- MongoDB.new(
33
- host: host,
34
- port: port,
35
- db: db,
36
- pool_size: pool_size,
37
- username: username,
38
- password: password
39
- )
40
- end
41
- subject { mongo }
42
-
43
- its(:host) { should == host }
44
- its(:port) { should == port }
45
- its(:db) { should == db }
46
- its(:pool_size) { should == pool_size }
47
- its(:username) { should == username }
48
- its(:password) { should == password }
49
- end
50
-
51
- it 'inserts documents into a collection' do
52
- expect { mongo.insert klass, name: 'foo' }.to change { mongo.count klass }.by 1
53
- end
54
-
55
- it 'inserts multiple documents into a collection' do
56
- expect { mongo.insert klass, [{name: 'foo'}, {name: 'bar'}] }
57
- .to change { mongo.count klass }.by 2
58
- end
59
-
60
- it 'removes all documents from a collection' do
61
- mongo.insert klass, {}
62
- mongo.delete_all klass
63
- mongo.count(klass).should == 0
64
- end
65
-
66
- it 'counts the documents in a collection' do
67
- mongo.delete_all klass
68
- 3.times do
69
- mongo.insert klass, {}
70
- end
71
- mongo.count(klass).should == 3
72
- end
73
-
74
- it 'counts the documents matching a query' do
75
- mongo.delete_all klass
76
- 1.times { mongo.insert klass, { name: 'bar' } }
77
- 3.times { mongo.insert klass, { name: 'foo' } }
78
- mongo.count(klass) { |o| o.name == 'foo' }.should == 3
79
- end
80
-
81
- it 'gets the first document in a collection' do
82
- value = {value: 1}
83
- mongo.insert klass, value
84
- mongo.first(klass)[:hypothetical_value].should == value['value']
85
- end
86
-
87
- it 'gets all of the documents in a collection' do
88
- values = [{value: 1}, {value: 2}]
89
- mongo.should_receive(:retrieve).with(Object, mongo.nil_query, {})
90
- .and_return(values)
91
- mongo.all(Object).should == values
92
- end
93
-
94
- it 'retrieves by id if the id is a string' do
95
- time = Time.now.utc
96
- id = mongo.insert Object, {inserted: time}
97
-
98
- object = mongo.retrieve(Object, mongo.query{|o| o.id == id.to_s }).first
99
- retrieved_time = object["inserted"]
100
- retrieved_time.to_f.should be_within(0.001).of time.to_f
101
- end
102
-
103
- describe 'serialization' do
104
- let(:object) { Object.new }
105
- let(:foo_attribute) { double('Attribute', name: :foo) }
106
- let(:baz_attribute) { double('Attribute', name: :baz) }
107
- let(:mapper) { double('Mapper',
108
- mapped_class: Object,
109
- mapper_registry: {},
110
- attribute_set: Set[foo_attribute, baz_attribute],
111
- data_source: mongo,
112
- ) }
113
-
114
- before do
115
- object.instance_variable_set :@foo, 'bar'
116
- object.instance_variable_set :@baz, 'quux'
117
- end
118
-
119
- it 'serializes objects' do
120
- mongo.serialize(object, mapper).should == {
121
- 'foo' => 'bar',
122
- 'baz' => 'quux'
123
- }
124
- end
125
-
126
- it 'can serialize only modified attributes of objects' do
127
- updated = object.dup
128
- updated.instance_variable_set :@foo, 'foo'
129
-
130
- serialized = mongo.serialize_changed_attributes(updated, object, mapper)
131
- serialized.should == { 'foo' => 'foo' }
132
- end
133
- end
134
-
135
- describe 'serializable objects' do
136
- let(:serializable_values) { [nil, true, false, 1, 1.2, '', [], {}, Time.now] }
137
-
138
- it 'can insert serializable values' do
139
- serializable_values.each do |value|
140
- mongo.insert(Object, {value: value}).should be_a Moped::BSON::ObjectId
141
- mongo.can_serialize?(value).should be_true
142
- end
143
- end
144
- end
145
-
146
- it 'generates a new query DSL object' do
147
- mongo.query { |object| object.whatever == 1 }.should respond_to :to_db
148
- end
149
-
150
- describe 'indexing' do
151
- let(:collection) { Object }
152
- let(:key) { 'object_id' }
153
-
154
- before { mongo.index collection, key }
155
- after { mongo.drop_collection collection }
156
-
157
- it 'adds indexes for the specified key on the specified collection' do
158
- indexes = mongo.indexes(collection).select{ |index| index.attribute == 'object_id' }
159
- indexes.should_not be_empty
160
- indexes.first.order.should be :ascending
161
- end
162
-
163
- it 'adds descending-order indexes' do
164
- index = mongo.index collection, 'hash', order: :descending
165
- index.order.should be :descending
166
- end
167
-
168
- it 'creates indexes on the database collection' do
169
- mongo.delete_all collection
170
- index = mongo.index collection, 'real_index', order: :descending, unique: true
171
- mongo.activate_index! index
172
-
173
- mongo.active_indexes(collection).should include index
174
- end
175
-
176
- it 'removes indexes' do
177
- mongo.drop_collection collection
178
- index = mongo.index collection, 'real_index', order: :descending, unique: true
179
- mongo.activate_index! index
180
- mongo.remove_index index
181
- mongo.active_indexes(collection).should_not include index
182
- end
183
- end
184
-
185
- describe 'atomic operations' do
186
- after(:all) { mongo.delete_all klass }
187
-
188
- it 'increments the value of an attribute' do
189
- id = mongo.insert klass, count: 1
190
- mongo.increment klass, id, :count
191
- mongo.increment klass, id, :count, 10
192
- query = mongo.query { |o| o.id == id }
193
- mongo.retrieve(klass, query).first['count'].should be == 12
194
- mongo.increment klass, id, :count, -1
195
- mongo.retrieve(klass, query).first['count'].should be == 11
196
- end
197
- end
198
-
199
- describe 'operation errors' do
200
- let(:data) { { foo: 'bar' } }
201
- let(:index) { mongo.index Object, :foo, unique: true }
202
-
203
- before do
204
- mongo.delete_all Object
205
- mongo.activate_index! index
206
- end
207
-
208
- after { mongo.drop_collection Object }
209
-
210
- it 'raises an exception when insertion fails' do
211
- mongo.insert Object, data
212
-
213
- expect { mongo.insert Object, data }.to raise_error DuplicateKeyError,
214
- 'Tried to insert Object with duplicate unique index: foo => "bar"'
215
- end
216
- end
217
- end
218
- end
@@ -1,17 +0,0 @@
1
- require 'spec_helper'
2
- require 'support/test_classes'
3
-
4
- describe 'validations' do
5
- let(:car_mapper) { Perpetuity[Car] }
6
-
7
- it 'raises an exception when inserting an invalid object' do
8
- car = Car.new
9
- expect { car_mapper.insert car }.to raise_error
10
- end
11
-
12
- it 'does not raise an exception when validations are met' do
13
- car = Car.new
14
- car.make = "Volkswagen"
15
- expect { car_mapper.insert car }.not_to raise_error
16
- end
17
- end
@@ -1,44 +0,0 @@
1
- require 'perpetuity/mongodb/index'
2
-
3
- module Perpetuity
4
- class MongoDB
5
- describe Index do
6
- let(:attribute) { double(name: 'name') }
7
- let(:index) { Index.new(Object, attribute) }
8
-
9
- it 'is not active by default' do
10
- index.should_not be_active
11
- end
12
-
13
- it 'can be activated' do
14
- index.activate!
15
- index.should be_active
16
- end
17
-
18
- it 'can be unique' do
19
- index = Index.new(Object, attribute, unique: true)
20
- index.should be_unique
21
- end
22
-
23
- it 'is not unique by default' do
24
- index.should_not be_unique
25
- end
26
-
27
- describe 'index ordering' do
28
- it 'can be ordered in ascending order' do
29
- index = Index.new(Object, attribute, order: :ascending)
30
- index.order.should be :ascending
31
- end
32
-
33
- it 'is ordered ascending by default' do
34
- index.order.should be :ascending
35
- end
36
-
37
- it 'can be ordered in descending order' do
38
- index = Index.new(Object, attribute, order: :descending)
39
- index.order.should be :descending
40
- end
41
- end
42
- end
43
- end
44
- end
@@ -1,58 +0,0 @@
1
- require 'perpetuity/mongodb/query_attribute'
2
-
3
- module Perpetuity
4
- describe MongoDB::QueryAttribute do
5
- let(:attribute) { MongoDB::QueryAttribute.new :attribute_name }
6
- subject { attribute }
7
-
8
- its(:name) { should == :attribute_name }
9
-
10
- it 'allows checking subattributes' do
11
- attribute.title.name.should == :'attribute_name.title'
12
- end
13
-
14
- it 'wraps .id subattribute in metadata' do
15
- attribute.id.name.should == :'attribute_name.__metadata__.id'
16
- end
17
-
18
- it 'wraps .klass subattribute in metadata' do
19
- attribute.klass.name.should == :'attribute_name.__metadata__.class'
20
- end
21
-
22
- it 'checks for equality' do
23
- (attribute == 1).should be_a MongoDB::QueryExpression
24
- end
25
-
26
- it 'checks for less than' do
27
- (attribute < 1).should be_a MongoDB::QueryExpression
28
- end
29
-
30
- it 'checks for <=' do
31
- (attribute <= 1).should be_a MongoDB::QueryExpression
32
- end
33
-
34
- it 'checks for greater than' do
35
- (attribute > 1).should be_a MongoDB::QueryExpression
36
- end
37
-
38
- it 'checks for >=' do
39
- (attribute >= 1).should be_a MongoDB::QueryExpression
40
- end
41
-
42
- it 'checks for inequality' do
43
- (attribute != 1).should be_a MongoDB::QueryExpression
44
- end
45
-
46
- it 'checks for regexp matches' do
47
- (attribute =~ /value/).should be_a MongoDB::QueryExpression
48
- end
49
-
50
- it 'checks for inclusion' do
51
- (attribute.in [1, 2, 3]).should be_a MongoDB::QueryExpression
52
- end
53
-
54
- it 'checks for its own truthiness' do
55
- attribute.to_db.should == ((attribute != false) & (attribute != nil)).to_db
56
- end
57
- end
58
- end
@@ -1,67 +0,0 @@
1
- require 'perpetuity/mongodb/query_expression'
2
-
3
- module Perpetuity
4
- describe MongoDB::QueryExpression do
5
- let(:expression) { MongoDB::QueryExpression.new :attribute, :equals, :value }
6
- subject { expression }
7
-
8
- describe 'translation to Mongo expressions' do
9
- it 'equality expression' do
10
- expression.to_db.should == { attribute: :value }
11
- end
12
-
13
- it 'less-than expression' do
14
- expression.comparator = :less_than
15
- expression.to_db.should == { attribute: { '$lt' => :value } }
16
- end
17
-
18
- it 'less-than-or-equal-to expression' do
19
- expression.comparator = :lte
20
- expression.to_db.should == { attribute: { '$lte' => :value } }
21
- end
22
-
23
- it 'greater-than expression' do
24
- expression.comparator = :greater_than
25
- expression.to_db.should == { attribute: { '$gt' => :value } }
26
- end
27
-
28
- it 'greater-than-or-equal-to expression' do
29
- expression.comparator = :gte
30
- expression.to_db.should == { attribute: { '$gte' => :value } }
31
- end
32
-
33
- it 'not-equal' do
34
- expression.comparator = :not_equal
35
- expression.to_db.should == { attribute: { '$ne' => :value } }
36
- end
37
-
38
- it 'checks for inclusion' do
39
- expression.comparator = :in
40
- expression.to_db.should == { attribute: { '$in' => :value } }
41
- end
42
-
43
- it 'checks for regexp matching' do
44
- expression.comparator = :matches
45
- expression.to_db.should == { attribute: :value }
46
- end
47
- end
48
-
49
- describe 'unions' do
50
- let(:lhs) { MongoDB::QueryExpression.new :first, :equals, :one }
51
- let(:rhs) { MongoDB::QueryExpression.new :second, :equals, :two }
52
-
53
- it 'converts | to an $or query' do
54
- (lhs | rhs).to_db.should == { '$or' => [{first: :one}, {second: :two}] }
55
- end
56
- end
57
-
58
- describe 'intersections' do
59
- let(:lhs) { MongoDB::QueryExpression.new :first, :equals, :one }
60
- let(:rhs) { MongoDB::QueryExpression.new :second, :equals, :two }
61
-
62
- it 'converts & to an $and query' do
63
- (lhs & rhs).to_db.should == { '$and' => [{first: :one}, {second: :two}] }
64
- end
65
- end
66
- end
67
- end