forked from datamapper/dm-core
-
Notifications
You must be signed in to change notification settings - Fork 1
/
property_set.rb
199 lines (165 loc) · 4.56 KB
/
property_set.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
module DataMapper
# Set of Property objects, used to associate
# queries with set of fields it performed over,
# to represent composite keys (esp. for associations)
# and so on.
class PropertySet < Array
extend Deprecate
deprecate :has_property?, :named?
deprecate :slice, :values_at
deprecate :add, :<<
# @api semipublic
def [](name)
@properties[name]
end
alias superclass_slice []=
private :superclass_slice
# @api semipublic
def []=(name, property)
self << property
end
# @api semipublic
def named?(name)
@properties.key?(name.to_sym)
end
# @api semipublic
def values_at(*names)
@properties.values_at(*names)
end
# @api semipublic
def <<(property)
found = named?(property.name)
add_property(property)
if found
superclass_slice(index(property), property)
else
super
end
end
# @api semipublic
def include?(property)
named?(property.name)
end
# @api semipublic
def index(property)
each_index { |index| break index if at(index).name == property.name }
end
# TODO: make PropertySet#reject return a PropertySet instance
# @api semipublic
def defaults
@defaults ||= self.class.new(key | [ discriminator ].compact | reject { |property| property.lazy? }).freeze
end
# @api semipublic
def key
@key ||= self.class.new(select { |property| property.key? }).freeze
end
# @api semipublic
def discriminator
@discriminator ||= detect { |property| property.kind_of?(Property::Discriminator) || property.type == Types::Discriminator }
end
# @api semipublic
def indexes
index_hash = {}
each { |property| parse_index(property.index, property.field, index_hash) }
index_hash
end
# @api semipublic
def unique_indexes
index_hash = {}
each { |property| parse_index(property.unique_index, property.field, index_hash) }
index_hash
end
# @api semipublic
def get(resource)
return [] if resource.nil?
map { |property| resource.__send__(property.name) }
end
# @api semipublic
def get!(resource)
map { |property| property.get!(resource) }
end
# @api semipublic
def set(resource, values)
zip(values) { |property, value| resource.__send__("#{property.name}=", value) }
end
# @api semipublic
def set!(resource, values)
zip(values) { |property, value| property.set!(resource, value) }
end
# @api semipublic
def loaded?(resource)
all? { |property| property.loaded?(resource) }
end
# @api semipublic
def valid?(values)
zip(values.nil? ? [] : values).all? { |property, value| property.valid?(value) }
end
# @api semipublic
def typecast(values)
zip(values.nil? ? [] : values).map { |property, value| property.typecast(value) }
end
# @api private
def property_contexts(property)
contexts = []
lazy_contexts.each do |context, properties|
contexts << context if properties.include?(property)
end
contexts
end
# @api private
def lazy_context(context)
lazy_contexts[context] ||= []
end
# @api private
def in_context(properties)
properties_in_context = properties.map do |property|
if (contexts = property_contexts(property)).any?
lazy_contexts.values_at(*contexts)
else
property
end
end
properties_in_context.flatten.uniq
end
# @api private
def field_map
map { |property| [ property.field, property ] }.to_hash
end
private
# @api semipublic
def initialize(*)
super
@properties = map { |property| [ property.name, property ] }.to_mash
end
# @api private
def initialize_copy(*)
super
@properties = @properties.dup
end
# @api private
def add_property(property)
clear_cache
@properties[property.name] = property
end
# @api private
def clear_cache
@defaults, @key, @discriminator = nil
end
# @api private
def lazy_contexts
@lazy_contexts ||= {}
end
# @api private
def parse_index(index, property, index_hash)
case index
when true
index_hash[property] = [ property ]
when Symbol
index_hash[index] ||= []
index_hash[index] << property
when Array
index.each { |idx| parse_index(idx, property, index_hash) }
end
end
end # class PropertySet
end # module DataMapper