og 0.20.0 → 0.21.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/CHANGELOG +796 -664
- data/INSTALL +24 -24
- data/README +39 -32
- data/Rakefile +41 -42
- data/benchmark/bench.rb +36 -36
- data/doc/AUTHORS +15 -12
- data/doc/LICENSE +3 -3
- data/doc/RELEASES +311 -243
- data/doc/config.txt +1 -1
- data/examples/mysql_to_psql.rb +15 -15
- data/examples/run.rb +92 -92
- data/install.rb +7 -17
- data/lib/og.rb +76 -75
- data/lib/og/collection.rb +203 -160
- data/lib/og/entity.rb +168 -169
- data/lib/og/errors.rb +5 -5
- data/lib/og/manager.rb +179 -178
- data/lib/og/mixin/hierarchical.rb +107 -107
- data/lib/og/mixin/optimistic_locking.rb +36 -36
- data/lib/og/mixin/orderable.rb +148 -148
- data/lib/og/mixin/timestamped.rb +8 -8
- data/lib/og/mixin/tree.rb +124 -124
- data/lib/og/relation.rb +237 -213
- data/lib/og/relation/belongs_to.rb +5 -5
- data/lib/og/relation/has_many.rb +60 -58
- data/lib/og/relation/joins_many.rb +93 -47
- data/lib/og/relation/refers_to.rb +25 -21
- data/lib/og/store.rb +210 -207
- data/lib/og/store/filesys.rb +79 -79
- data/lib/og/store/kirby.rb +263 -258
- data/lib/og/store/memory.rb +261 -261
- data/lib/og/store/mysql.rb +288 -284
- data/lib/og/store/psql.rb +261 -244
- data/lib/og/store/sql.rb +873 -720
- data/lib/og/store/sqlite.rb +177 -175
- data/lib/og/store/sqlserver.rb +204 -214
- data/lib/og/types.rb +1 -1
- data/lib/og/validation.rb +57 -57
- data/lib/vendor/mysql.rb +376 -376
- data/lib/vendor/mysql411.rb +10 -10
- data/test/og/mixin/tc_hierarchical.rb +59 -59
- data/test/og/mixin/tc_optimistic_locking.rb +40 -40
- data/test/og/mixin/tc_orderable.rb +67 -67
- data/test/og/mixin/tc_timestamped.rb +19 -19
- data/test/og/store/tc_filesys.rb +46 -46
- data/test/og/tc_inheritance.rb +81 -81
- data/test/og/tc_join.rb +67 -0
- data/test/og/tc_polymorphic.rb +49 -49
- data/test/og/tc_relation.rb +57 -30
- data/test/og/tc_select.rb +49 -0
- data/test/og/tc_store.rb +345 -337
- data/test/og/tc_types.rb +11 -11
- metadata +11 -18
data/lib/og/relation.rb
CHANGED
@@ -9,152 +9,176 @@ module Og
|
|
9
9
|
|
10
10
|
class Relation
|
11
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
|
-
|
12
|
+
attr_accessor :options
|
13
|
+
|
14
|
+
attr_accessor :is_polymorphic
|
15
|
+
|
16
|
+
# A generalized initialize method for all relations.
|
17
|
+
# Contains common setup code.
|
18
|
+
|
19
|
+
def initialize(args, options = {})
|
20
|
+
@options = options
|
21
|
+
@options.update(args.pop) if args.last.is_a?(Hash)
|
22
|
+
|
23
|
+
if args.empty? or (not (args.last.is_a?(Class) or args.last.is_a?(Symbol)))
|
24
|
+
raise 'Class of target not defined'
|
25
|
+
end
|
26
|
+
|
27
|
+
@options[:target_class] = args.pop
|
28
|
+
|
29
|
+
if target_class == Object
|
30
|
+
# If the target class is just an Object mark that class
|
31
|
+
# as a polymorphic parent class.
|
32
|
+
# This class acts as template
|
33
|
+
# to generate customized versions of this class.
|
34
|
+
|
35
|
+
owner_class.meta(:polymorphic, owner_class)
|
36
|
+
elsif target_class.respond_to?(:metadata) and target_class.metadata.polymorphic
|
37
|
+
# If the target class is polymorphic, create a specialized
|
38
|
+
# version of the class enclosed in the owner namespace.
|
39
|
+
|
40
|
+
target_dm = target_class.to_s.demodulize
|
41
|
+
owner_class.module_eval %{
|
42
|
+
class #{owner_class}::#{target_dm} < #{target_class}
|
43
|
+
end
|
44
|
+
}
|
45
|
+
eval %{
|
46
|
+
@options[:target_class] = #{owner_class}::#{target_dm}
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
target_name = if collection
|
51
|
+
:target_plural_name
|
52
|
+
else
|
53
|
+
:target_singular_name
|
54
|
+
end
|
55
|
+
|
56
|
+
# Inflect the relation name.
|
57
|
+
|
58
|
+
unless args.empty?
|
59
|
+
@options[target_name] = args.first
|
60
|
+
else
|
61
|
+
@options[target_name] = if collection
|
62
|
+
target_class.to_s.demodulize.underscore.downcase.plural.intern
|
63
|
+
else
|
64
|
+
target_class.to_s.demodulize.underscore.downcase.intern
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
@options[:name] = options[target_name]
|
69
|
+
end
|
70
|
+
|
71
|
+
def [](key)
|
72
|
+
@options[key]
|
73
|
+
end
|
74
|
+
|
75
|
+
def []=(key, val)
|
76
|
+
@options[key] = val
|
77
|
+
end
|
78
|
+
|
79
|
+
# Is the relation polymorphic?
|
80
|
+
|
81
|
+
def polymorphic?
|
82
|
+
target_class == Object
|
83
|
+
end
|
84
|
+
|
85
|
+
#--
|
86
|
+
# gmosx, TODO: remove, this is not really needed.
|
87
|
+
#++
|
88
|
+
|
89
|
+
def resolve_options
|
90
|
+
@options[:owner_pk], @options[:owner_pkclass] = owner_class.primary_key
|
91
|
+
if target_class.respond_to?(:primary_key)
|
92
|
+
@options[:target_pk], @options[:target_pkclass] = target_class.primary_key
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# To avoid forward declarations, references to undefined
|
97
|
+
# (at the time of the creation of the relation) classes are
|
98
|
+
# stored as symbols. These symbols are resolved by this
|
99
|
+
# method.
|
100
|
+
#--
|
101
|
+
# FIXME: do something more elegant here.
|
102
|
+
#++
|
103
|
+
|
104
|
+
def resolve_symbol(sym, owner_class)
|
105
|
+
c = owner_class.name.dup
|
106
|
+
c = "::" + c unless c =~ /::/
|
107
|
+
c.gsub!(/::.*$/, '::')
|
108
|
+
c << sym.to_s
|
109
|
+
begin
|
110
|
+
return constant(c)
|
111
|
+
rescue
|
112
|
+
unless c == sym
|
113
|
+
c = sym
|
114
|
+
retry
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def resolve_target
|
120
|
+
if target_class.is_a?(Symbol)
|
121
|
+
klass = resolve_symbol(target_class, owner_class)
|
122
|
+
@options[:target_class] = klass
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
=begin
|
127
|
+
def resolve_target
|
128
|
+
if target_class.is_a?(Symbol)
|
129
|
+
c = owner_class.name.dup
|
130
|
+
c = "::" + c unless c =~ /::/
|
131
|
+
c.gsub!(/::.*$/, '::')
|
132
|
+
c << target_class.to_s
|
133
|
+
begin
|
134
|
+
klass = constant(c)
|
135
|
+
rescue
|
136
|
+
unless c == target_class
|
137
|
+
c = target_class
|
138
|
+
retry
|
139
|
+
end
|
140
|
+
end
|
141
|
+
@options[:target_class] = klass
|
142
|
+
end
|
143
|
+
end
|
144
|
+
=end
|
145
|
+
|
146
|
+
# Resolve a polymorphic target class.
|
147
|
+
# Overrided in subclasses.
|
148
|
+
|
149
|
+
def resolve_polymorphic
|
150
|
+
end
|
151
|
+
|
152
|
+
# This method is implemented in subclasses.
|
153
|
+
|
154
|
+
def enchant
|
155
|
+
end
|
156
|
+
|
157
|
+
# Access the hash values as methods.
|
158
|
+
|
159
|
+
def method_missing(sym, *args)
|
160
|
+
return @options[sym]
|
161
|
+
end
|
162
|
+
|
163
|
+
class << self
|
164
|
+
|
165
|
+
def resolve(klass, action)
|
166
|
+
if klass.__meta[:relations]
|
167
|
+
for relation in klass.__meta[:relations]
|
168
|
+
relation.send(action)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def enchant(klass)
|
174
|
+
if klass.__meta[:relations]
|
175
|
+
for relation in klass.__meta[:relations]
|
176
|
+
relation.enchant unless relation.target_class == Object
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
158
182
|
|
159
183
|
end
|
160
184
|
|
@@ -162,73 +186,73 @@ end
|
|
162
186
|
# relations.
|
163
187
|
|
164
188
|
module RelationMacros
|
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
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
189
|
+
def self.append_features(base)
|
190
|
+
super
|
191
|
+
base.extend(ClassMethods)
|
192
|
+
end
|
193
|
+
|
194
|
+
module ClassMethods
|
195
|
+
|
196
|
+
# === Examples
|
197
|
+
#
|
198
|
+
# belongs_to Article
|
199
|
+
# belongs_to :article, Article
|
200
|
+
# belongs_to :article, Article, :view => 'lala'
|
201
|
+
|
202
|
+
def belongs_to(*args)
|
203
|
+
require 'og/relation/belongs_to'
|
204
|
+
meta :relations, Og::BelongsTo.new(args, :owner_class => self)
|
205
|
+
end
|
206
|
+
|
207
|
+
# === Examples
|
208
|
+
#
|
209
|
+
# refers_to Topic
|
210
|
+
|
211
|
+
def refers_to(*args)
|
212
|
+
require 'og/relation/refers_to'
|
213
|
+
meta :relations, Og::RefersTo.new(args, :owner_class => self)
|
214
|
+
end
|
215
|
+
|
216
|
+
# === Examples
|
217
|
+
#
|
218
|
+
# has_one User
|
219
|
+
|
220
|
+
def has_one(*args)
|
221
|
+
require 'og/relation/has_one'
|
222
|
+
meta :relations, Og::HasOne.new(args, :owner_class => self)
|
223
|
+
end
|
224
|
+
|
225
|
+
# === Examples
|
226
|
+
#
|
227
|
+
# has_many Comment
|
228
|
+
# has_many :comments, Comment
|
229
|
+
|
230
|
+
def has_many(*args)
|
231
|
+
require 'og/relation/has_many'
|
232
|
+
meta :relations, Og::HasMany.new(args, :owner_class => self, :collection => true)
|
233
|
+
end
|
234
|
+
|
235
|
+
def joins_many(*args)
|
236
|
+
require 'og/relation/joins_many'
|
237
|
+
meta :relations, Og::JoinsMany.new(args, :owner_class => self, :collection => true)
|
238
|
+
end
|
239
|
+
|
240
|
+
def many_to_many(*args)
|
241
|
+
require 'og/relation/many_to_many'
|
242
|
+
meta :relations, Og::ManyToMany.new(args, :owner_class => self, :collection => true)
|
243
|
+
end
|
244
|
+
|
245
|
+
def inspect_relations
|
246
|
+
__meta[:relations]
|
247
|
+
end
|
248
|
+
alias_method :relations, :inspect_relations
|
249
|
+
|
250
|
+
def inspect_relation(name)
|
251
|
+
__meta[:relations].find { |r| r[:name] == name }
|
252
|
+
end
|
253
|
+
alias_method :relation, :inspect_relation
|
254
|
+
|
255
|
+
end
|
232
256
|
end
|
233
257
|
|
234
258
|
end
|