veneer 0.2.0 → 0.4.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/Gemfile +12 -1
- data/README.md +55 -87
- data/Rakefile +1 -1
- data/lib/veneer.rb +6 -1
- data/lib/veneer/adapters/activerecord.rb +2 -0
- data/lib/veneer/adapters/activerecord/class_wrapper.rb +99 -5
- data/lib/veneer/adapters/activerecord/instance_wrapper.rb +4 -2
- data/lib/veneer/adapters/activerecord/pre_3.0_class_wrapper.rb +62 -1
- data/lib/veneer/adapters/activerecord/property.rb +22 -0
- data/lib/veneer/adapters/datamapper.rb +1 -0
- data/lib/veneer/adapters/datamapper/class_wrapper.rb +90 -6
- data/lib/veneer/adapters/datamapper/property.rb +25 -0
- data/lib/veneer/adapters/mongomapper.rb +1 -0
- data/lib/veneer/adapters/mongomapper/class_wrapper.rb +68 -0
- data/lib/veneer/adapters/mongomapper/property.rb +16 -0
- data/lib/veneer/base/class_wrapper.rb +110 -7
- data/lib/veneer/base/property.rb +27 -0
- data/lib/veneer/lint.rb +4 -180
- data/lib/veneer/lint/adapter.rb +282 -0
- data/lib/veneer/lint/base.rb +10 -0
- data/lib/veneer/lint/properties.rb +78 -0
- data/lib/veneer/version.rb +1 -1
- data/test/support/helpers.rb +10 -1
- data/test/test_helper.rb +3 -3
- data/test/veneer/activerecord/test_adapter.rb +80 -0
- data/test/veneer/activerecord/test_properties.rb +73 -0
- data/test/veneer/datamapper/test_adapter.rb +71 -0
- data/test/veneer/datamapper/test_properties.rb +59 -0
- data/test/veneer/{adapters/test_mongomapper.rb → mongomapper/test_adapter.rb} +35 -11
- data/test/veneer/mongomapper/test_properties.rb +56 -0
- data/test/veneer_test.rb +35 -0
- data/veneer.gemspec +2 -0
- metadata +57 -51
- data/test/veneer/adapters/test_active_record.rb +0 -56
- data/test/veneer/adapters/test_datamapper.rb +0 -56
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class Base
|
3
|
+
module VeneerInterface
|
4
|
+
class Property < Veneer::Base::Property
|
5
|
+
def normalize(type)
|
6
|
+
case type
|
7
|
+
when :serial, :integer then Integer
|
8
|
+
when :string, :text then String
|
9
|
+
when :float then Float
|
10
|
+
when :decimal then BigDecimal
|
11
|
+
when :datetime then DateTime
|
12
|
+
when :time then Time
|
13
|
+
when :date then Date
|
14
|
+
when :binary then StringIO
|
15
|
+
when :boolean then TrueClass
|
16
|
+
else type
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -2,10 +2,69 @@ module DataMapper
|
|
2
2
|
module Resource
|
3
3
|
module VeneerInterface
|
4
4
|
class ClassWrapper < ::Veneer::Base::ClassWrapper
|
5
|
+
def self.model_classes
|
6
|
+
::DataMapper::Model.descendants
|
7
|
+
end
|
8
|
+
|
5
9
|
def new(opts = {})
|
6
10
|
::Kernel.Veneer(klass.new(opts))
|
7
11
|
end
|
8
12
|
|
13
|
+
def collection_associations
|
14
|
+
@collection_associations ||= begin
|
15
|
+
result = klass.relationships.inject([]) do |ary, rel|
|
16
|
+
if rel.max > 1
|
17
|
+
ary << {
|
18
|
+
:name => rel.name,
|
19
|
+
:class => rel.child_model
|
20
|
+
}
|
21
|
+
end
|
22
|
+
ary
|
23
|
+
end
|
24
|
+
result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def member_associations
|
29
|
+
@member_associations ||= begin
|
30
|
+
result = klass.relationships.inject([]) do |ary, rel|
|
31
|
+
if rel.max == 1
|
32
|
+
ary << {
|
33
|
+
:name => rel.name,
|
34
|
+
:class => rel.parent_model
|
35
|
+
}
|
36
|
+
end
|
37
|
+
ary
|
38
|
+
end
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def properties
|
44
|
+
@properties ||= begin
|
45
|
+
klass.properties.map do |property|
|
46
|
+
::DataMapper::Resource::VeneerInterface::Property.new(
|
47
|
+
self,
|
48
|
+
{
|
49
|
+
:name => property.name,
|
50
|
+
:type => property,
|
51
|
+
:constraints => {
|
52
|
+
:length => property.options[:length],
|
53
|
+
:nullable? => property.options[:allow_nil],
|
54
|
+
:precision => property.options[:precision],
|
55
|
+
:scale => property.options[:scale],
|
56
|
+
},
|
57
|
+
:primary => primary_keys.include?(property.name),
|
58
|
+
}
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def primary_keys
|
65
|
+
@primary_keys ||= klass.key.map { |key| key.name }
|
66
|
+
end
|
67
|
+
|
9
68
|
def destroy_all
|
10
69
|
klass.all.destroy
|
11
70
|
end
|
@@ -15,7 +74,32 @@ module DataMapper
|
|
15
74
|
end
|
16
75
|
|
17
76
|
def find_many(opts)
|
18
|
-
klass.all(dm_conditions_from_opts(opts))
|
77
|
+
klass.all(dm_conditions_from_opts(opts)).to_a
|
78
|
+
end
|
79
|
+
|
80
|
+
def count(opts={})
|
81
|
+
opts[:conditions].nil? ? klass.count : klass.count(opts[:conditions])
|
82
|
+
end
|
83
|
+
|
84
|
+
def sum(field, opts={})
|
85
|
+
opts = ::Hashie::Mash.new(opts)
|
86
|
+
klass.all(dm_conditions_from_opts(opts)).sum(field)
|
87
|
+
end
|
88
|
+
|
89
|
+
def min(field, opts={})
|
90
|
+
opts = ::Hashie::Mash.new(opts)
|
91
|
+
klass.all(dm_conditions_from_opts(opts)).min(field)
|
92
|
+
end
|
93
|
+
|
94
|
+
def max(field, opts={})
|
95
|
+
opts = ::Hashie::Mash.new(opts)
|
96
|
+
klass.all(dm_conditions_from_opts(opts)).max(field)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Delegate to validators_on if ActiveModel::Validations has been
|
100
|
+
# included in the model
|
101
|
+
def validators_on(name)
|
102
|
+
klass <=> ::ActiveModel::Validations ? klass.validators_on(name) : []
|
19
103
|
end
|
20
104
|
|
21
105
|
private
|
@@ -38,20 +122,20 @@ module DataMapper
|
|
38
122
|
|
39
123
|
if raw.order.present?
|
40
124
|
opts[:order] = case raw.order
|
41
|
-
when Array
|
125
|
+
when ::Array
|
42
126
|
raw.order.inject([]) do |ary, str|
|
43
127
|
ary << order_from_string(str)
|
44
128
|
end.compact
|
45
|
-
when String
|
129
|
+
when ::String
|
46
130
|
order_from_string(raw.order)
|
47
|
-
when Symbol
|
131
|
+
when ::Symbol
|
48
132
|
raw.order
|
49
133
|
end
|
50
134
|
end
|
51
135
|
|
52
136
|
if raw.conditions.present?
|
53
|
-
raw.conditions.each do |field, value|
|
54
|
-
opts[field] = value if allowed_field?(field)
|
137
|
+
raw.conditions.each do |(field, value)|
|
138
|
+
opts[field.to_sym] = value if allowed_field?(field)
|
55
139
|
end
|
56
140
|
end
|
57
141
|
opts
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Resource
|
3
|
+
module VeneerInterface
|
4
|
+
class Property < Veneer::Base::Property
|
5
|
+
def normalize(type)
|
6
|
+
# Several DataMapper properties' types inherit from the Object class
|
7
|
+
# so DataMapper::Property::Object must be the last one i the case statement.
|
8
|
+
case type
|
9
|
+
when DataMapper::Property::Integer then Integer
|
10
|
+
when DataMapper::Property::String then String
|
11
|
+
when DataMapper::Property::Float then Float
|
12
|
+
when DataMapper::Property::Decimal then BigDecimal
|
13
|
+
when DataMapper::Property::DateTime then DateTime
|
14
|
+
when DataMapper::Property::Time then Time
|
15
|
+
when DataMapper::Property::Date then Date
|
16
|
+
when DataMapper::Property::Boolean then TrueClass
|
17
|
+
when DataMapper::Property::Discriminator then Class
|
18
|
+
when DataMapper::Property::Object then Object
|
19
|
+
else type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -2,14 +2,82 @@ module MongoMapper
|
|
2
2
|
module Document
|
3
3
|
module VeneerInterface
|
4
4
|
class ClassWrapper < Veneer::Base::ClassWrapper
|
5
|
+
delegate :validators_on, :to => :klass
|
6
|
+
|
7
|
+
PRIMARY_KEYS = [:_id]
|
8
|
+
|
9
|
+
def self.model_classes
|
10
|
+
::MongoMapper::Document.descendants
|
11
|
+
end
|
12
|
+
|
5
13
|
def new(opts = {})
|
6
14
|
::Kernel::Veneer(klass.new(opts))
|
7
15
|
end
|
8
16
|
|
17
|
+
def collection_associations
|
18
|
+
@collection_associations ||= begin
|
19
|
+
klass.associations.inject([]) do |ary, (name, assoc)|
|
20
|
+
if assoc.is_a? ::MongoMapper::Plugins::Associations::ManyAssociation
|
21
|
+
ary << {
|
22
|
+
:name => name,
|
23
|
+
:class => assoc.class_name.constantize
|
24
|
+
}
|
25
|
+
end
|
26
|
+
ary
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def member_associations
|
32
|
+
@member_associations ||= begin
|
33
|
+
types = [::MongoMapper::Plugins::Associations::BelongsToAssociation,
|
34
|
+
::MongoMapper::Plugins::Associations::ManyAssociation]
|
35
|
+
klass.associations.inject([]) do |ary, (name, assoc)|
|
36
|
+
if types.include?(assoc.class)
|
37
|
+
ary << {
|
38
|
+
:name => name,
|
39
|
+
:class => assoc.class_name.constantize
|
40
|
+
}
|
41
|
+
end
|
42
|
+
ary
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def properties
|
48
|
+
@properties ||= begin
|
49
|
+
klass.keys.map do |property|
|
50
|
+
property = property[1]
|
51
|
+
name = property.name.to_sym
|
52
|
+
::MongoMapper::Document::VeneerInterface::Property.new(
|
53
|
+
self,
|
54
|
+
{
|
55
|
+
:name => name,
|
56
|
+
:type => property.type,
|
57
|
+
:constraints => {
|
58
|
+
:length => property.options[:length],
|
59
|
+
:nullable? => nil,
|
60
|
+
:precision => nil,
|
61
|
+
},
|
62
|
+
:primary => primary_keys.include?(name),
|
63
|
+
}
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def primary_keys
|
70
|
+
::MongoMapper::Document::VeneerInterface::ClassWrapper::PRIMARY_KEYS
|
71
|
+
end
|
72
|
+
|
9
73
|
def destroy_all
|
10
74
|
klass.destroy_all
|
11
75
|
end
|
12
76
|
|
77
|
+
def count(opts={})
|
78
|
+
opts[:conditions].nil? ? klass.count : klass.count(opts[:conditions])
|
79
|
+
end
|
80
|
+
|
13
81
|
def find_first(opts)
|
14
82
|
klass.first(opts)
|
15
83
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Document
|
3
|
+
module VeneerInterface
|
4
|
+
class Property < Veneer::Base::Property
|
5
|
+
def normalize(type)
|
6
|
+
case type
|
7
|
+
when MongoMapper::Extensions::ObjectId then String
|
8
|
+
when MongoMapper::Extensions::Boolean then TrueClass
|
9
|
+
when MongoMapper::Extensions::Binary then StringIO
|
10
|
+
else type
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -4,11 +4,17 @@ module Veneer
|
|
4
4
|
# new
|
5
5
|
# find_many
|
6
6
|
# destroy_all
|
7
|
+
# model_classes
|
8
|
+
#
|
7
9
|
#
|
8
10
|
# Optional Methods
|
9
11
|
# find_first
|
10
12
|
# create!
|
11
13
|
# create
|
14
|
+
# count
|
15
|
+
# sum
|
16
|
+
# max
|
17
|
+
# min
|
12
18
|
#
|
13
19
|
class ClassWrapper < BasicObject
|
14
20
|
attr_reader :klass, :opts
|
@@ -16,6 +22,45 @@ module Veneer
|
|
16
22
|
@klass, @opts = klass, opts
|
17
23
|
end
|
18
24
|
|
25
|
+
def self.inherited(klass)
|
26
|
+
subclasses << klass
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.subclasses
|
30
|
+
@subclasses ||= []
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.model_classes
|
34
|
+
raise ::Veneer::Errors::NotImplemented
|
35
|
+
end
|
36
|
+
|
37
|
+
# Provides an array of associations of the format
|
38
|
+
# [
|
39
|
+
# {
|
40
|
+
# :name => :association_name,
|
41
|
+
# :class_name => 'TheClass'
|
42
|
+
# }
|
43
|
+
# ]
|
44
|
+
#
|
45
|
+
# The collection associations maps has_many, has n, embeds_many and the like.
|
46
|
+
# @api public
|
47
|
+
def collection_associations
|
48
|
+
[]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Provides an array of association for belongs_to type associaions
|
52
|
+
# of the format:
|
53
|
+
#
|
54
|
+
# [
|
55
|
+
# {
|
56
|
+
# :name => :assocaition_name,
|
57
|
+
# :class_name => 'TheClass'
|
58
|
+
# }
|
59
|
+
# ]
|
60
|
+
def member_associations
|
61
|
+
[]
|
62
|
+
end
|
63
|
+
|
19
64
|
# Create an instance of the object.
|
20
65
|
# That is, instantiate and persist it in one step.
|
21
66
|
# Raise an error if the object is not persisted
|
@@ -50,7 +95,7 @@ module Veneer
|
|
50
95
|
# @api public
|
51
96
|
# @see Veneer::Base::ClassWrapper.all
|
52
97
|
def first(opts={})
|
53
|
-
::Kernel.Veneer(find_first(Hashie::Mash.new(opts)))
|
98
|
+
::Kernel.Veneer(find_first(::Hashie::Mash.new(opts)))
|
54
99
|
end
|
55
100
|
|
56
101
|
# Provides an interface to query the objects
|
@@ -64,7 +109,58 @@ module Veneer
|
|
64
109
|
#
|
65
110
|
# @api public
|
66
111
|
def all(opts={})
|
67
|
-
find_many(Hashie::Mash.new(opts))
|
112
|
+
find_many(::Hashie::Mash.new(opts))
|
113
|
+
end
|
114
|
+
|
115
|
+
# Obtains a count of all matching records
|
116
|
+
# Takes the same options as all
|
117
|
+
#
|
118
|
+
# Adapter implementers should overwrite with a more
|
119
|
+
# efficient implementation
|
120
|
+
# @see all
|
121
|
+
def count(opts={})
|
122
|
+
all(opts).size
|
123
|
+
end
|
124
|
+
|
125
|
+
# Obtains a sum of all matching records for the given field
|
126
|
+
# Takes the same options as all
|
127
|
+
#
|
128
|
+
# Adapter implementers should overwrite with a more
|
129
|
+
# efficient implementation
|
130
|
+
# @see all
|
131
|
+
def sum(field, opts={})
|
132
|
+
opts = ::Hashie::Mash.new(opts)
|
133
|
+
all(opts).inject(0){|sum, item| (item.send(field) || 0) + sum }
|
134
|
+
end
|
135
|
+
|
136
|
+
# Obtains the minimum value of the given field of all matching records
|
137
|
+
# Takes the same options as all
|
138
|
+
#
|
139
|
+
# Adapter implementers should overwrite with a more
|
140
|
+
# efficient implementation
|
141
|
+
# @see all
|
142
|
+
def min(field, opts={})
|
143
|
+
opts = ::Hashie::Mash.new(opts)
|
144
|
+
all(opts).inject(nil) do |min, item|
|
145
|
+
val = item.send(field)
|
146
|
+
min = val if !val.nil? && (min.nil? || val < min)
|
147
|
+
min
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Obtains the maximum value of the given field of all matching records
|
152
|
+
# Takes the same options as all
|
153
|
+
#
|
154
|
+
# Adapter implementers should overwrite with a more
|
155
|
+
# efficient implementation
|
156
|
+
# @see all
|
157
|
+
def max(field, opts={})
|
158
|
+
opts = ::Hashie::Mash.new(opts)
|
159
|
+
all(opts).inject(nil) do |max, item|
|
160
|
+
val = item.send(field)
|
161
|
+
max = val if !val.nil? && (max.nil? || val > max)
|
162
|
+
max
|
163
|
+
end
|
68
164
|
end
|
69
165
|
|
70
166
|
# Should return an array or array like structure with elements matching the provided conditions hash
|
@@ -74,15 +170,22 @@ module Veneer
|
|
74
170
|
::Kernel.raise Errors::NotImplemented
|
75
171
|
end
|
76
172
|
|
173
|
+
# Should return an array of primary keys
|
174
|
+
# @api public
|
175
|
+
def primary_keys
|
176
|
+
::Kernel.raise Errors::NotImplemented
|
177
|
+
end
|
178
|
+
|
179
|
+
# Should return an array of ActiveModel::Validator class instances for given property name
|
180
|
+
# @api public
|
181
|
+
def validators_on(name)
|
182
|
+
::Kernel.raise Errors::NotImplemented
|
183
|
+
end
|
184
|
+
|
77
185
|
def find_first(opts)
|
78
186
|
opts[:limit] = 1
|
79
187
|
find_many(opts).first
|
80
188
|
end
|
81
|
-
|
82
|
-
private
|
83
|
-
def method_missing(meth, *args, &blk)
|
84
|
-
@klass.__send__(meth, *args, &blk)
|
85
|
-
end
|
86
189
|
end
|
87
190
|
end
|
88
191
|
end
|