sbf-dm-core 1.3.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.
- checksums.yaml +7 -0
- data/.autotest +29 -0
- data/.document +5 -0
- data/.gitignore +44 -0
- data/.rspec +1 -0
- data/.rubocop.yml +468 -0
- data/.travis.yml +57 -0
- data/.yardopts +1 -0
- data/Gemfile +70 -0
- data/LICENSE +20 -0
- data/README.md +269 -0
- data/Rakefile +4 -0
- data/dm-core.gemspec +21 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +233 -0
- data/lib/dm-core/adapters/in_memory_adapter.rb +110 -0
- data/lib/dm-core/adapters.rb +249 -0
- data/lib/dm-core/associations/many_to_many.rb +477 -0
- data/lib/dm-core/associations/many_to_one.rb +282 -0
- data/lib/dm-core/associations/one_to_many.rb +332 -0
- data/lib/dm-core/associations/one_to_one.rb +84 -0
- data/lib/dm-core/associations/relationship.rb +650 -0
- data/lib/dm-core/backwards.rb +11 -0
- data/lib/dm-core/collection.rb +1486 -0
- data/lib/dm-core/core_ext/kernel.rb +21 -0
- data/lib/dm-core/core_ext/pathname.rb +4 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +6 -0
- data/lib/dm-core/model/hook.rb +99 -0
- data/lib/dm-core/model/is.rb +30 -0
- data/lib/dm-core/model/property.rb +244 -0
- data/lib/dm-core/model/relationship.rb +366 -0
- data/lib/dm-core/model/scope.rb +87 -0
- data/lib/dm-core/model.rb +876 -0
- data/lib/dm-core/property/binary.rb +19 -0
- data/lib/dm-core/property/boolean.rb +35 -0
- data/lib/dm-core/property/class.rb +23 -0
- data/lib/dm-core/property/date.rb +45 -0
- data/lib/dm-core/property/date_time.rb +44 -0
- data/lib/dm-core/property/decimal.rb +47 -0
- data/lib/dm-core/property/discriminator.rb +40 -0
- data/lib/dm-core/property/float.rb +27 -0
- data/lib/dm-core/property/integer.rb +32 -0
- data/lib/dm-core/property/invalid_value_error.rb +17 -0
- data/lib/dm-core/property/lookup.rb +26 -0
- data/lib/dm-core/property/numeric.rb +35 -0
- data/lib/dm-core/property/object.rb +33 -0
- data/lib/dm-core/property/serial.rb +13 -0
- data/lib/dm-core/property/string.rb +47 -0
- data/lib/dm-core/property/text.rb +12 -0
- data/lib/dm-core/property/time.rb +46 -0
- data/lib/dm-core/property/typecast/numeric.rb +32 -0
- data/lib/dm-core/property/typecast/time.rb +33 -0
- data/lib/dm-core/property.rb +856 -0
- data/lib/dm-core/property_set.rb +177 -0
- data/lib/dm-core/query/conditions/comparison.rb +886 -0
- data/lib/dm-core/query/conditions/operation.rb +710 -0
- data/lib/dm-core/query/direction.rb +33 -0
- data/lib/dm-core/query/operator.rb +34 -0
- data/lib/dm-core/query/path.rb +113 -0
- data/lib/dm-core/query/sort.rb +38 -0
- data/lib/dm-core/query.rb +1352 -0
- data/lib/dm-core/relationship_set.rb +69 -0
- data/lib/dm-core/repository.rb +226 -0
- data/lib/dm-core/resource/persistence_state/clean.rb +36 -0
- data/lib/dm-core/resource/persistence_state/deleted.rb +26 -0
- data/lib/dm-core/resource/persistence_state/dirty.rb +91 -0
- data/lib/dm-core/resource/persistence_state/immutable.rb +32 -0
- data/lib/dm-core/resource/persistence_state/persisted.rb +25 -0
- data/lib/dm-core/resource/persistence_state/transient.rb +87 -0
- data/lib/dm-core/resource/persistence_state.rb +70 -0
- data/lib/dm-core/resource.rb +1220 -0
- data/lib/dm-core/spec/lib/adapter_helpers.rb +63 -0
- data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
- data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
- data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
- data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
- data/lib/dm-core/spec/setup.rb +164 -0
- data/lib/dm-core/spec/shared/adapter_spec.rb +366 -0
- data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
- data/lib/dm-core/spec/shared/resource_spec.rb +1221 -0
- data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
- data/lib/dm-core/spec/shared/semipublic/property_spec.rb +184 -0
- data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/chainable.rb +18 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/descendant_set.rb +89 -0
- data/lib/dm-core/support/equalizer.rb +48 -0
- data/lib/dm-core/support/ext/array.rb +22 -0
- data/lib/dm-core/support/ext/blank.rb +25 -0
- data/lib/dm-core/support/ext/hash.rb +67 -0
- data/lib/dm-core/support/ext/module.rb +47 -0
- data/lib/dm-core/support/ext/object.rb +57 -0
- data/lib/dm-core/support/ext/string.rb +24 -0
- data/lib/dm-core/support/ext/try_dup.rb +12 -0
- data/lib/dm-core/support/hook.rb +388 -0
- data/lib/dm-core/support/inflections.rb +60 -0
- data/lib/dm-core/support/inflector/inflections.rb +211 -0
- data/lib/dm-core/support/inflector/methods.rb +151 -0
- data/lib/dm-core/support/lazy_array.rb +451 -0
- data/lib/dm-core/support/local_object_space.rb +13 -0
- data/lib/dm-core/support/logger.rb +201 -0
- data/lib/dm-core/support/mash.rb +176 -0
- data/lib/dm-core/support/naming_conventions.rb +109 -0
- data/lib/dm-core/support/ordered_set.rb +381 -0
- data/lib/dm-core/support/subject.rb +33 -0
- data/lib/dm-core/support/subject_set.rb +251 -0
- data/lib/dm-core/version.rb +3 -0
- data/lib/dm-core.rb +274 -0
- data/script/performance.rb +275 -0
- data/script/profile.rb +218 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
- data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +69 -0
- data/spec/public/associations/many_to_many_spec.rb +197 -0
- data/spec/public/associations/many_to_one_spec.rb +83 -0
- data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
- data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
- data/spec/public/associations/one_to_many_spec.rb +81 -0
- data/spec/public/associations/one_to_one_spec.rb +176 -0
- data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
- data/spec/public/collection_spec.rb +69 -0
- data/spec/public/finalize_spec.rb +77 -0
- data/spec/public/model/hook_spec.rb +245 -0
- data/spec/public/model/property_spec.rb +91 -0
- data/spec/public/model/relationship_spec.rb +1040 -0
- data/spec/public/model_spec.rb +456 -0
- data/spec/public/property/binary_spec.rb +43 -0
- data/spec/public/property/boolean_spec.rb +21 -0
- data/spec/public/property/class_spec.rb +27 -0
- data/spec/public/property/date_spec.rb +21 -0
- data/spec/public/property/date_time_spec.rb +21 -0
- data/spec/public/property/decimal_spec.rb +23 -0
- data/spec/public/property/discriminator_spec.rb +134 -0
- data/spec/public/property/float_spec.rb +22 -0
- data/spec/public/property/integer_spec.rb +22 -0
- data/spec/public/property/object_spec.rb +117 -0
- data/spec/public/property/serial_spec.rb +22 -0
- data/spec/public/property/string_spec.rb +21 -0
- data/spec/public/property/text_spec.rb +62 -0
- data/spec/public/property/time_spec.rb +21 -0
- data/spec/public/property_spec.rb +333 -0
- data/spec/public/resource/state_spec.rb +72 -0
- data/spec/public/resource_spec.rb +289 -0
- data/spec/public/sel_spec.rb +53 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +309 -0
- data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
- data/spec/public/shared/collection_shared_spec.rb +1637 -0
- data/spec/public/shared/finder_shared_spec.rb +1647 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
- data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
- data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
- data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +200 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +110 -0
- data/spec/semipublic/model_spec.rb +96 -0
- data/spec/semipublic/property/binary_spec.rb +13 -0
- data/spec/semipublic/property/boolean_spec.rb +47 -0
- data/spec/semipublic/property/class_spec.rb +33 -0
- data/spec/semipublic/property/date_spec.rb +43 -0
- data/spec/semipublic/property/date_time_spec.rb +46 -0
- data/spec/semipublic/property/decimal_spec.rb +83 -0
- data/spec/semipublic/property/discriminator_spec.rb +19 -0
- data/spec/semipublic/property/float_spec.rb +82 -0
- data/spec/semipublic/property/integer_spec.rb +82 -0
- data/spec/semipublic/property/lookup_spec.rb +29 -0
- data/spec/semipublic/property/serial_spec.rb +13 -0
- data/spec/semipublic/property/string_spec.rb +13 -0
- data/spec/semipublic/property/text_spec.rb +31 -0
- data/spec/semipublic/property/time_spec.rb +50 -0
- data/spec/semipublic/property_spec.rb +114 -0
- data/spec/semipublic/query/conditions/comparison_spec.rb +1502 -0
- data/spec/semipublic/query/conditions/operation_spec.rb +1296 -0
- data/spec/semipublic/query/path_spec.rb +471 -0
- data/spec/semipublic/query_spec.rb +3665 -0
- data/spec/semipublic/resource/state/clean_spec.rb +89 -0
- data/spec/semipublic/resource/state/deleted_spec.rb +79 -0
- data/spec/semipublic/resource/state/dirty_spec.rb +163 -0
- data/spec/semipublic/resource/state/immutable_spec.rb +107 -0
- data/spec/semipublic/resource/state/transient_spec.rb +163 -0
- data/spec/semipublic/resource/state_spec.rb +230 -0
- data/spec/semipublic/resource_spec.rb +23 -0
- data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +198 -0
- data/spec/semipublic/shared/resource_state_shared_spec.rb +91 -0
- data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/core_ext/hash.rb +10 -0
- data/spec/support/core_ext/inheritable_attributes.rb +46 -0
- data/spec/support/properties/huge_integer.rb +17 -0
- data/spec/unit/array_spec.rb +23 -0
- data/spec/unit/blank_spec.rb +73 -0
- data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
- data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
- data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
- data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
- data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
- data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
- data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
- data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
- data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
- data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
- data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
- data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
- data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
- data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
- data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
- data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
- data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
- data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
- data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
- data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
- data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
- data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
- data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
- data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
- data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
- data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
- data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
- data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
- data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
- data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
- data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
- data/spec/unit/hash_spec.rb +27 -0
- data/spec/unit/hook_spec.rb +1216 -0
- data/spec/unit/inflections_spec.rb +14 -0
- data/spec/unit/lazy_array_spec.rb +1949 -0
- data/spec/unit/mash_spec.rb +289 -0
- data/spec/unit/module_spec.rb +70 -0
- data/spec/unit/object_spec.rb +38 -0
- data/spec/unit/try_dup_spec.rb +46 -0
- data/tasks/ci.rake +1 -0
- data/tasks/spec.rake +18 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +323 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
|
|
3
|
+
# instance methods
|
|
4
|
+
describe DataMapper::Property do
|
|
5
|
+
|
|
6
|
+
# define the model prior to supported_by
|
|
7
|
+
before :all do
|
|
8
|
+
class ::Track
|
|
9
|
+
include DataMapper::Resource
|
|
10
|
+
|
|
11
|
+
property :id, Serial
|
|
12
|
+
property :artist, String, :lazy => false, :index => :artist_album
|
|
13
|
+
property :title, String, :field => 'name', :index => true
|
|
14
|
+
property :album, String, :index => :artist_album
|
|
15
|
+
property :musicbrainz_hash, String, :unique => true, :unique_index => true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ::Image
|
|
19
|
+
include DataMapper::Resource
|
|
20
|
+
|
|
21
|
+
property :md5hash, String, :key => true, :length => 32
|
|
22
|
+
property :title, String, :required => true, :unique => true
|
|
23
|
+
property :description, Text, :length => 1..1024, :lazy => [ :detail ]
|
|
24
|
+
property :width, Integer, :lazy => [:dimensions]
|
|
25
|
+
property :height, Integer, :lazy => [:dimensions]
|
|
26
|
+
property :format, String, :default => 'jpeg'
|
|
27
|
+
property :taken_at, Time, :default => proc { Time.now }
|
|
28
|
+
end
|
|
29
|
+
DataMapper.finalize
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
supported_by :all do
|
|
33
|
+
describe '#field' do
|
|
34
|
+
it 'returns @field value if it is present' do
|
|
35
|
+
expect(Track.properties[:title].field).to eql('name')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'returns field for specific repository when it is present'
|
|
39
|
+
|
|
40
|
+
it 'sets field value using field naming convention on first reference'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#default_for' do
|
|
44
|
+
it 'returns default value for non-callables' do
|
|
45
|
+
expect(Image.properties[:format].default_for(Image.new)).to eq 'jpeg'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'returns result of a call for callable values' do
|
|
49
|
+
expect(Image.properties[:taken_at].default_for(Image.new).year).to eq Time.now.year
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe '#eql?' do
|
|
54
|
+
it 'is true for properties with the same model and name' do
|
|
55
|
+
expect(Track.properties[:title]).to eql(Track.properties[:title])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'is false for properties of different models' do
|
|
59
|
+
expect(Track.properties[:title]).not_to eql(Image.properties[:title])
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'is false for properties with different names' do
|
|
63
|
+
expect(Track.properties[:title]).not_to eql(Track.properties[:id])
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe '#get!' do
|
|
68
|
+
before :all do
|
|
69
|
+
@image = Image.new
|
|
70
|
+
|
|
71
|
+
# now some dark Ruby magic
|
|
72
|
+
@image.instance_variable_set(:@description, 'Is set by magic')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'gets instance variable value from the resource directly' do
|
|
76
|
+
# if you know a better way to test direct instance variable access,
|
|
77
|
+
# go ahead and make changes to this example
|
|
78
|
+
expect(Image.properties[:description].get!(@image)).to eq 'Is set by magic'
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#index' do
|
|
83
|
+
it 'returns true when property has an index' do
|
|
84
|
+
expect(Track.properties[:title].index).to be(true)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'returns index name when property has a named index' do
|
|
88
|
+
expect(Track.properties[:album].index).to eql(:artist_album)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'returns false when property has no index' do
|
|
92
|
+
expect(Track.properties[:musicbrainz_hash].index).to be(false)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe '#initialize' do
|
|
97
|
+
describe 'when tracking strategy is explicitly given' do
|
|
98
|
+
it 'uses tracking strategy from options'
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe '#inspect' do
|
|
103
|
+
before :all do
|
|
104
|
+
@str = Track.properties[:title].inspect
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'features model name' do
|
|
108
|
+
expect(@str).to match(/@model=Track/)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'features property name' do
|
|
112
|
+
expect(@str).to match(/@name=:title/)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe '#key?' do
|
|
117
|
+
describe 'returns true when property is a ' do
|
|
118
|
+
it 'serial key' do
|
|
119
|
+
expect(Track.properties[:id].key?).to be(true)
|
|
120
|
+
end
|
|
121
|
+
it 'natural key' do
|
|
122
|
+
expect(Image.properties[:md5hash].key?).to be(true)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it 'returns true when property is a part of composite key'
|
|
127
|
+
|
|
128
|
+
it 'returns false when property does not relate to a key' do
|
|
129
|
+
expect(Track.properties[:title].key?).to be(false)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
describe '#lazy?' do
|
|
134
|
+
it 'returns true when property is lazy loaded' do
|
|
135
|
+
expect(Image.properties[:description].lazy?).to be(true)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'returns false when property is not lazy loaded' do
|
|
139
|
+
expect(Track.properties[:artist].lazy?).to be(false)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
describe '#lazy_load_properties' do
|
|
144
|
+
it 'returns all lazy properties in the same context' do
|
|
145
|
+
expect(Image.properties[:width].__send__(:lazy_load_properties)).to eq Image.properties.values_at(:width, :height)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'returns all properties by default' do
|
|
149
|
+
expect(Track.properties[:artist].__send__(:lazy_load_properties)).to eq Track.properties
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
describe '#length' do
|
|
154
|
+
it 'returns upper bound for Range values' do
|
|
155
|
+
expect(Image.properties[:description].length).to eql(1024)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it 'returns value as is for integer values' do
|
|
159
|
+
expect(Image.properties[:md5hash].length).to eql(32)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
describe '#min' do
|
|
164
|
+
describe 'when :min and :max options not provided to constructor' do
|
|
165
|
+
before do
|
|
166
|
+
@property = Image.property(:integer_with_nil_min, Integer)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
it 'Is nil' do
|
|
170
|
+
expect(@property.min).to be_nil
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
describe 'when :min option not provided to constructor, but :max is provided' do
|
|
175
|
+
before do
|
|
176
|
+
@property = Image.property(:integer_with_default_min, Integer, :max => 1)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'is the default value' do
|
|
180
|
+
expect(@property.min).to eq 0
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
describe 'when :min and :max options provided to constructor' do
|
|
185
|
+
before do
|
|
186
|
+
@min = 1
|
|
187
|
+
@property = Image.property(:integer_with_explicit_min, Integer, :min => @min, :max => 2)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it 'is the expected value' do
|
|
191
|
+
expect(@property.min).to eq @min
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
describe '#max' do
|
|
197
|
+
describe 'when :min and :max options not provided to constructor' do
|
|
198
|
+
before do
|
|
199
|
+
@property = Image.property(:integer_with_nil_max, Integer)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it 'Is nil' do
|
|
203
|
+
expect(@property.max).to be_nil
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
describe 'when :max option not provided to constructor, but :min is provided' do
|
|
208
|
+
before do
|
|
209
|
+
@property = Image.property(:integer_with_default_max, Integer, :min => 1)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it 'is the default value' do
|
|
213
|
+
expect(@property.max).to eq 2**31 - 1
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
describe 'when :min and :max options provided to constructor' do
|
|
218
|
+
before do
|
|
219
|
+
@max = 2
|
|
220
|
+
@property = Image.property(:integer_with_explicit_max, Integer, min: 1, max: @max)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it 'Is the expected value' do
|
|
224
|
+
expect(@property.max).to eq @max
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
describe '#allow_nil?' do
|
|
230
|
+
it 'returns true when property can accept nil as its value' do
|
|
231
|
+
expect(Track.properties[:artist].allow_nil?).to be(true)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it 'returns false when property nil value is prohibited for this property' do
|
|
235
|
+
expect(Image.properties[:title].allow_nil?).to be(false)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
describe '#serial?' do
|
|
240
|
+
it 'returns true when property is serial (auto incrementing)' do
|
|
241
|
+
expect(Track.properties[:id].serial?).to be(true)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it 'returns false when property is NOT serial (auto incrementing)' do
|
|
245
|
+
expect(Image.properties[:md5hash].serial?).to be(false)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
describe '#set' do
|
|
250
|
+
before :all do
|
|
251
|
+
# keep in mind we must run these examples with a
|
|
252
|
+
# saved model instance
|
|
253
|
+
@image = Image.create(
|
|
254
|
+
:md5hash => '5268f0f3f452844c79843e820f998869',
|
|
255
|
+
:title => 'Rome at the sunset',
|
|
256
|
+
:description => 'Just wow'
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
@property = Image.properties[:title]
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'triggers lazy loading for given resource'
|
|
263
|
+
|
|
264
|
+
it 'sets new property value' do
|
|
265
|
+
@property.set(@image, 'Updated value')
|
|
266
|
+
expect(@image.title).to eq 'Updated value'
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
describe '#set!' do
|
|
271
|
+
before :all do
|
|
272
|
+
@image = Image.new(:md5hash => '5268f0f3f452844c79843e820f998869',
|
|
273
|
+
:title => 'Rome at the sunset',
|
|
274
|
+
:description => 'Just wow')
|
|
275
|
+
|
|
276
|
+
@property = Image.properties[:title]
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'directly sets instance variable on given resource' do
|
|
280
|
+
@property.set!(@image, 'Set with dark Ruby magic')
|
|
281
|
+
expect(@image.title).to eq 'Set with dark Ruby magic'
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
describe '#unique?' do
|
|
286
|
+
it 'is true for fields that explicitly given uniq index' do
|
|
287
|
+
expect(Track.properties[:musicbrainz_hash].unique?).to be(true)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
it 'is true for serial fields' do
|
|
291
|
+
pending
|
|
292
|
+
|
|
293
|
+
expect(Track.properties[:title].unique?).to be(true)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
it 'is true for keys' do
|
|
297
|
+
expect(Image.properties[:md5hash].unique?).to be(true)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
describe '#unique_index' do
|
|
302
|
+
it 'returns true when property has unique index' do
|
|
303
|
+
expect(Track.properties[:musicbrainz_hash].unique_index).to be(true)
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
it 'returns false when property has no unique index' do
|
|
307
|
+
expect(Track.properties[:title].unique_index).to be(false)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
it 'returns true when property is unique' do
|
|
311
|
+
expect(Image.properties[:title].unique_index).to be(true)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it 'returns :key when property is a key' do
|
|
315
|
+
expect(Track.properties[:id].unique_index).to eq :key
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
describe 'exception on bad property names' do
|
|
320
|
+
it "is raised for 'model'" do
|
|
321
|
+
expect {
|
|
322
|
+
Track.property :model, String
|
|
323
|
+
}.to raise_error(ArgumentError)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it "is raised for 'repository_name'" do
|
|
327
|
+
expect {
|
|
328
|
+
Track.property :repository_name, String
|
|
329
|
+
}.to raise_error(ArgumentError)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end # DataMapper::Property
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
|
2
|
+
|
|
3
|
+
describe 'DataMapper::Resource' do
|
|
4
|
+
before :all do
|
|
5
|
+
class ::Author
|
|
6
|
+
include DataMapper::Resource
|
|
7
|
+
|
|
8
|
+
property :id, Serial
|
|
9
|
+
property :string_, String
|
|
10
|
+
property :bool_, Boolean
|
|
11
|
+
property :float_, Float
|
|
12
|
+
property :integer_, Integer
|
|
13
|
+
property :decimal_, Decimal
|
|
14
|
+
property :datetime_, DateTime
|
|
15
|
+
property :date_, Date
|
|
16
|
+
property :time_, Time
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
DataMapper.finalize
|
|
20
|
+
|
|
21
|
+
@model = Author
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
supported_by :all do
|
|
25
|
+
before do
|
|
26
|
+
@values = {
|
|
27
|
+
:string_ => Addressable::URI.parse('http://test.example/'),
|
|
28
|
+
:bool_ => true,
|
|
29
|
+
:float_ => 2.5,
|
|
30
|
+
:integer_ => 10,
|
|
31
|
+
:decimal_ => BigDecimal("999.95"),
|
|
32
|
+
:datetime_ => DateTime.parse('2010-10-11 12:13:14+0'),
|
|
33
|
+
:date_ => Date.parse('2010-10-11 12:13:14+0'),
|
|
34
|
+
:time_ => Time.parse('2010-10-11 12:13:14+0'),
|
|
35
|
+
}
|
|
36
|
+
@string_values = {
|
|
37
|
+
:string_ => 'http://test.example/',
|
|
38
|
+
:decimal_ => '999.95',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@resource = @model.create(@values)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '.new' do
|
|
45
|
+
subject { @resource }
|
|
46
|
+
|
|
47
|
+
it { is_expected.not_to be_dirty }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
[:string_, :bool_, :float_, :integer_, :decimal_, :datetime_, :date_, :time_].each do |property|
|
|
51
|
+
describe "#{property.to_s[0...-1]} property mutator" do
|
|
52
|
+
before do
|
|
53
|
+
@resource.send("#{property}=", @string_values[property] || @values[property].to_s)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'type casts given equal value so resource remains clean' do
|
|
57
|
+
expect(@resource).not_to be_dirty
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe "#attribute_set for #{property.to_s[0...-1]} property" do
|
|
62
|
+
before do
|
|
63
|
+
@resource.attribute_set(property, @string_values[property] || @values[property].to_s)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'type casts given equal value so resource remains clean' do
|
|
67
|
+
expect(@resource).not_to be_dirty
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
require_relative '../spec_helper'
|
|
2
|
+
|
|
3
|
+
describe DataMapper::Resource do
|
|
4
|
+
before :all do
|
|
5
|
+
module ::Blog
|
|
6
|
+
class User
|
|
7
|
+
include DataMapper::Resource
|
|
8
|
+
|
|
9
|
+
property :name, String, :key => true
|
|
10
|
+
property :age, Integer
|
|
11
|
+
property :summary, Text
|
|
12
|
+
property :description, Text
|
|
13
|
+
property :admin, Boolean, :accessor => :private
|
|
14
|
+
|
|
15
|
+
belongs_to :parent, self, :required => false
|
|
16
|
+
has n, :children, self, :inverse => :parent
|
|
17
|
+
|
|
18
|
+
belongs_to :referrer, self, :required => false
|
|
19
|
+
has n, :comments
|
|
20
|
+
|
|
21
|
+
# FIXME: figure out a different approach than stubbing things out
|
|
22
|
+
def comment=(*)
|
|
23
|
+
# do nothing with comment
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class Author < User; end
|
|
28
|
+
|
|
29
|
+
class Comment
|
|
30
|
+
include DataMapper::Resource
|
|
31
|
+
|
|
32
|
+
property :id, Serial
|
|
33
|
+
property :body, Text
|
|
34
|
+
|
|
35
|
+
belongs_to :user
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class Article
|
|
39
|
+
include DataMapper::Resource
|
|
40
|
+
|
|
41
|
+
property :id, Serial
|
|
42
|
+
property :body, Text
|
|
43
|
+
|
|
44
|
+
has n, :paragraphs
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class Paragraph
|
|
48
|
+
include DataMapper::Resource
|
|
49
|
+
|
|
50
|
+
property :id, Serial
|
|
51
|
+
property :text, String
|
|
52
|
+
|
|
53
|
+
belongs_to :article
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class ::Default
|
|
58
|
+
include DataMapper::Resource
|
|
59
|
+
|
|
60
|
+
property :name, String, :key => true, :default => 'a default value'
|
|
61
|
+
end
|
|
62
|
+
DataMapper.finalize
|
|
63
|
+
|
|
64
|
+
@user_model = Blog::User
|
|
65
|
+
@author_model = Blog::Author
|
|
66
|
+
@comment_model = Blog::Comment
|
|
67
|
+
@article_model = Blog::Article
|
|
68
|
+
@paragraph_model = Blog::Paragraph
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
supported_by :all do
|
|
72
|
+
before :all do
|
|
73
|
+
user = @user_model.create(:name => 'dbussink', :age => 25, :description => 'Test')
|
|
74
|
+
|
|
75
|
+
@user = @user_model.get!(*user.key)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it_behaves_like 'A public Resource'
|
|
79
|
+
it_behaves_like 'A Resource supporting Strategic Eager Loading'
|
|
80
|
+
|
|
81
|
+
it 'A resource responds to raise_on_save_failure' do
|
|
82
|
+
expect(@user).to respond_to(:raise_on_save_failure)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '#raise_on_save_failure' do
|
|
86
|
+
after do
|
|
87
|
+
# reset to the default value
|
|
88
|
+
reset_raise_on_save_failure(@user_model)
|
|
89
|
+
reset_raise_on_save_failure(@user)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
subject { @user.raise_on_save_failure }
|
|
93
|
+
|
|
94
|
+
describe 'when model.raise_on_save_failure has not been set' do
|
|
95
|
+
it { is_expected.to be(false) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe 'when model.raise_on_save_failure has been set to true' do
|
|
99
|
+
before do
|
|
100
|
+
@user_model.raise_on_save_failure = true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it { is_expected.to be(true) }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe 'when resource.raise_on_save_failure has been set to true' do
|
|
107
|
+
before do
|
|
108
|
+
@user.raise_on_save_failure = true
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it { is_expected.to be(true) }
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'A model responds to raise_on_save_failure=' do
|
|
116
|
+
expect(@user_model).to respond_to(:raise_on_save_failure=)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe '#raise_on_save_failure=' do
|
|
120
|
+
after do
|
|
121
|
+
# reset to the default value
|
|
122
|
+
@user_model.raise_on_save_failure = false
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
subject { @user_model.raise_on_save_failure = @value }
|
|
126
|
+
|
|
127
|
+
describe 'with a true value' do
|
|
128
|
+
before do
|
|
129
|
+
@value = true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it { is_expected.to be(true) }
|
|
133
|
+
|
|
134
|
+
it 'Sets raise_on_save_failure' do
|
|
135
|
+
expect { method(:subject) }.to change {
|
|
136
|
+
@user_model.raise_on_save_failure
|
|
137
|
+
}.from(false).to(true)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe 'with a false value' do
|
|
142
|
+
before do
|
|
143
|
+
@value = false
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it { is_expected.to be(false) }
|
|
147
|
+
|
|
148
|
+
it 'Sets raise_on_save_failure' do
|
|
149
|
+
expect { method(:subject) }.not_to change {
|
|
150
|
+
@user_model.raise_on_save_failure
|
|
151
|
+
}
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
[ :save, :save! ].each do |method|
|
|
157
|
+
describe "##{method}" do
|
|
158
|
+
subject { @user.__send__(method) }
|
|
159
|
+
|
|
160
|
+
describe 'when raise_on_save_failure is true' do
|
|
161
|
+
before do
|
|
162
|
+
@user.raise_on_save_failure = true
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
describe 'and it is a savable resource' do
|
|
166
|
+
it { is_expected.to be(true) }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# FIXME: We cannot trigger a failing save with invalid properties anymore.
|
|
170
|
+
# Invalid properties will result in their own exception.
|
|
171
|
+
# So Im mocking here, but a better approach is needed.
|
|
172
|
+
|
|
173
|
+
describe 'and it is an invalid resource' do
|
|
174
|
+
before do
|
|
175
|
+
expect(@user).to receive(:save_self).and_return(false)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'Raises an exception' do
|
|
179
|
+
expect { method(:subject) }.to raise_error(DataMapper::SaveFailureError,
|
|
180
|
+
"Blog::User##{method} returned false, Blog::User was not saved") { |error|
|
|
181
|
+
expect(error.resource).to equal(@user)
|
|
182
|
+
}
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
[ :update, :update! ].each do |method|
|
|
190
|
+
describe 'with attributes where one is a foreign key' do
|
|
191
|
+
before :all do
|
|
192
|
+
rescue_if @skip do
|
|
193
|
+
@dkubb = @user.referrer = @user_model.create(:name => 'dkubb', :age => 33)
|
|
194
|
+
@user.save
|
|
195
|
+
@user = @user_model.get!(*@user.key)
|
|
196
|
+
expect(@user.referrer).to
|
|
197
|
+
|
|
198
|
+
@solnic = @user_model.create(:name => 'solnic', :age => 28)
|
|
199
|
+
|
|
200
|
+
@attributes = {}
|
|
201
|
+
|
|
202
|
+
relationship = @user_model.relationships[:referrer]
|
|
203
|
+
relationship.child_key.to_a.each_with_index do |k, i|
|
|
204
|
+
@attributes[k.name] = relationship.parent_key.to_a[i].get!(@solnic)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
@return = @user.__send__(method, @attributes)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it 'Returns true' do
|
|
212
|
+
expect(@return).to be(true)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it 'Updates attributes of Resource' do
|
|
216
|
+
@attributes.each { |key, value| expect(@user.__send__(key)).to eq value }
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it 'Persists the changes' do
|
|
220
|
+
resource = @user_model.get!(*@user.key)
|
|
221
|
+
@attributes.each { |key, value| expect(resource.__send__(key)).to eq value }
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
it 'Returns correct parent' do
|
|
225
|
+
resource = @user_model.get!(*@user.key)
|
|
226
|
+
expect(resource.referrer).to eq @solnic
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
describe '#attribute_get' do
|
|
232
|
+
subject { object.attribute_get(name) }
|
|
233
|
+
|
|
234
|
+
let(:object) { @user }
|
|
235
|
+
|
|
236
|
+
context 'with a known property' do
|
|
237
|
+
let(:name) { :name }
|
|
238
|
+
|
|
239
|
+
it 'returns the attribute value' do
|
|
240
|
+
is_expected.to eq 'dbussink'
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
context 'with an unknown property' do
|
|
245
|
+
let(:name) { :unknown }
|
|
246
|
+
|
|
247
|
+
it 'returns nil' do
|
|
248
|
+
is_expected.to be_nil
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
describe '#attribute_set' do
|
|
254
|
+
subject { object.attribute_set(name, value) }
|
|
255
|
+
|
|
256
|
+
let(:object) { @user.dup }
|
|
257
|
+
|
|
258
|
+
context 'with a known property' do
|
|
259
|
+
let(:name) { :name }
|
|
260
|
+
let(:value) { 'dkubb' }
|
|
261
|
+
|
|
262
|
+
it 'sets the attribute' do
|
|
263
|
+
expect { subject }.to change { object.name }
|
|
264
|
+
.from('dbussink')
|
|
265
|
+
.to('dkubb')
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it 'makes the object dirty' do
|
|
269
|
+
expect { subject }.to change { object.dirty? }
|
|
270
|
+
.from(false)
|
|
271
|
+
.to(true)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
context 'with an unknown property' do
|
|
276
|
+
let(:name) { :unknown }
|
|
277
|
+
let(:value) { mock('Unknown Value') }
|
|
278
|
+
|
|
279
|
+
it 'does not set the attribute' do
|
|
280
|
+
expect { subject }.to_not change { object.attributes.dup }
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
it 'does not make the object dirty' do
|
|
284
|
+
expect { subject }.to_not change { object.dirty? }
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|