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/store/memory.rb
CHANGED
@@ -8,21 +8,21 @@ module Og
|
|
8
8
|
|
9
9
|
module MemoryUtils
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
# FIXME: find a neutral name.
|
12
|
+
|
13
|
+
def table(klass)
|
14
|
+
klass.to_s
|
15
|
+
end
|
16
16
|
|
17
|
-
|
17
|
+
# FIXME: find a neutral name.
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
def join_table(class1, class2, postfix = nil)
|
20
|
+
"#{class1}#{class2}"
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
def quote(val)
|
24
|
+
val.inspect
|
25
|
+
end
|
26
26
|
|
27
27
|
end
|
28
28
|
|
@@ -33,258 +33,258 @@ end
|
|
33
33
|
#++
|
34
34
|
|
35
35
|
class MemoryStore < Store
|
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
|
-
|
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
|
-
|
36
|
+
extend MemoryUtils; include MemoryUtils
|
37
|
+
|
38
|
+
class ObjectHash < Hash
|
39
|
+
def [](key)
|
40
|
+
super(key.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
def []=(key, value)
|
44
|
+
super(key.to_s, value)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# This hash implements an in-memory database.
|
49
|
+
|
50
|
+
@objects = ObjectHash.new
|
51
|
+
|
52
|
+
def self.objects
|
53
|
+
@objects
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.objects=(val)
|
57
|
+
@objects = val
|
58
|
+
end
|
59
|
+
|
60
|
+
# A pseudo-connection to the actual object store.
|
61
|
+
|
62
|
+
attr_accessor :conn
|
63
|
+
|
64
|
+
def self.destroy(options)
|
65
|
+
FileUtils.rm_rf("#{options[:name]}.db")
|
66
|
+
rescue
|
67
|
+
Logger.info "Cannot destroy '#{name}'"
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(options)
|
71
|
+
super
|
72
|
+
begin
|
73
|
+
@conn = self.class.objects = YAML.load_file("#{@options[:name]}.db")
|
74
|
+
rescue
|
75
|
+
@conn = self.class.objects = ObjectHash.new
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def close
|
80
|
+
File.open("#{@options[:name]}.db", 'w') { |f| f << @conn.to_yaml }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Enchants a class.
|
84
|
+
|
85
|
+
def enchant(klass, manager)
|
86
|
+
klass.property :oid, Fixnum
|
87
|
+
|
88
|
+
super
|
89
|
+
|
90
|
+
@conn[klass] ||= {}
|
91
|
+
|
92
|
+
eval_og_insert(klass)
|
93
|
+
eval_og_update(klass)
|
94
|
+
eval_og_read(klass)
|
95
|
+
eval_og_delete(klass)
|
96
|
+
end
|
97
|
+
|
98
|
+
# :section: Lifecycle methods.
|
99
|
+
|
100
|
+
# Loads an object from the store using the primary key.
|
101
|
+
|
102
|
+
def load(pk, klass)
|
103
|
+
@conn[klass][pk]
|
104
|
+
end
|
105
|
+
|
106
|
+
# Update selected properties of an object or class of
|
107
|
+
# objects.
|
108
|
+
|
109
|
+
def update_properties(target, set, options = nil)
|
110
|
+
set = set.gsub(/,/, ';')
|
111
|
+
if target.is_a?(Class)
|
112
|
+
if options
|
113
|
+
condition = options[:condition] || options[:where]
|
114
|
+
else
|
115
|
+
condition = 'true'
|
116
|
+
end
|
117
|
+
for obj in @conn[target].values
|
118
|
+
obj.instance_eval %{
|
119
|
+
if #{condition.gsub(/=/, '==')}
|
120
|
+
#{set}
|
121
|
+
end
|
122
|
+
}
|
123
|
+
end
|
124
|
+
else
|
125
|
+
target.instance_eval(set)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
alias_method :pupdate, :update_properties
|
129
|
+
alias_method :update_property, :update_properties
|
130
|
+
|
131
|
+
# Find a collection of objects.
|
132
|
+
#
|
133
|
+
# === Examples
|
134
|
+
#
|
135
|
+
# User.find(:condition => 'age > 15', :order => 'score ASC', :offet => 10, :limit =>10)
|
136
|
+
# Comment.find(:include => :entry)
|
137
|
+
# store.find(:class => User, :where => 'age > 15')
|
138
|
+
|
139
|
+
def find(options)
|
140
|
+
query(options)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Find one object.
|
144
|
+
|
145
|
+
def find_one(options)
|
146
|
+
query(options).first
|
147
|
+
end
|
148
|
+
|
149
|
+
# Reloads an object from the store.
|
150
|
+
|
151
|
+
def reload(obj, pk)
|
152
|
+
# Nop, the memory store is always synchronized.
|
153
|
+
end
|
154
|
+
|
155
|
+
# Count results.
|
156
|
+
|
157
|
+
def count(options)
|
158
|
+
objects = 0
|
159
|
+
|
160
|
+
if condition = options[:condition] || options[:where]
|
161
|
+
condition = "obj." + condition.gsub(/=/, '==')
|
162
|
+
else
|
163
|
+
condition = true
|
164
|
+
end
|
165
|
+
|
166
|
+
eval %{
|
167
|
+
for obj in @conn[options[:class]].values
|
168
|
+
objects += 1 if #{condition}
|
169
|
+
end
|
170
|
+
}
|
171
|
+
|
172
|
+
return objects
|
173
|
+
end
|
174
|
+
|
175
|
+
# Relate two objects through an intermediate join table.
|
176
|
+
# Typically used in joins_many and many_to_many relations.
|
177
|
+
|
178
|
+
def join(obj1, obj2, table)
|
179
|
+
# nop
|
180
|
+
end
|
181
|
+
|
182
|
+
# Query.
|
183
|
+
|
184
|
+
def query(options)
|
185
|
+
objects = []
|
186
|
+
|
187
|
+
if condition = options[:condition] || options[:where]
|
188
|
+
condition = "obj." + condition.gsub(/=/, '==')
|
189
|
+
else
|
190
|
+
condition = true
|
191
|
+
end
|
192
|
+
|
193
|
+
eval %{
|
194
|
+
for obj in @conn[options[:class]].values
|
195
|
+
objects << obj if #{condition}
|
196
|
+
end
|
197
|
+
}
|
198
|
+
|
199
|
+
if order = options[:order]
|
200
|
+
desc = (order =~ /DESC/)
|
201
|
+
order = order.gsub(/DESC/, '').gsub(/ASC/, '')
|
202
|
+
eval "objects.sort { |x, y| x.#{order} <=> y.#{order} }"
|
203
|
+
objects.reverse! if desc
|
204
|
+
end
|
205
|
+
|
206
|
+
return objects
|
207
|
+
end
|
208
|
+
|
209
|
+
# :section: Transaction methods.
|
210
|
+
|
211
|
+
# Start a new transaction.
|
212
|
+
|
213
|
+
def start
|
214
|
+
end
|
215
|
+
|
216
|
+
# Commit a transaction.
|
217
|
+
|
218
|
+
def commit
|
219
|
+
end
|
220
|
+
|
221
|
+
# Rollback a transaction.
|
222
|
+
|
223
|
+
def rollback
|
224
|
+
end
|
225
225
|
|
226
226
|
private
|
227
227
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
228
|
+
# :section: Lifecycle method compilers.
|
229
|
+
|
230
|
+
# Compile the og_update method for the class.
|
231
|
+
|
232
|
+
def eval_og_insert(klass)
|
233
|
+
pk = klass.primary_key.first
|
234
|
+
|
235
|
+
klass.class_eval %{
|
236
|
+
def og_insert(store)
|
237
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)}
|
238
|
+
@#{pk} = store.conn[#{klass}].size + 1
|
239
|
+
store.conn[#{klass}][@#{pk}] = self
|
240
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :post) if klass.respond_to?(:advices)}
|
241
|
+
end
|
242
|
+
}
|
243
|
+
end
|
244
|
+
|
245
|
+
# Compile the og_update method for the class.
|
246
|
+
|
247
|
+
def eval_og_update(klass)
|
248
|
+
pk = klass.primary_key.first
|
249
|
+
|
250
|
+
klass.class_eval %{
|
251
|
+
def og_update(store, options)
|
252
|
+
#{Aspects.gen_advice_code(:og_update, klass.advices, :pre) if klass.respond_to?(:advices)}
|
253
|
+
store.conn[#{klass}][@#{pk}] = self
|
254
|
+
#{Aspects.gen_advice_code(:og_update, klass.advices, :post) if klass.respond_to?(:advices)}
|
255
|
+
end
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
# Not really useful in this store, kept for compatibility,
|
260
|
+
# just to call the aspects.
|
261
|
+
|
262
|
+
def eval_og_read(klass)
|
263
|
+
klass.class_eval %{
|
264
|
+
def og_read
|
265
|
+
#{Aspects.gen_advice_code(:og_read, klass.advices, :pre) if klass.respond_to?(:advices)}
|
266
|
+
#{Aspects.gen_advice_code(:og_read, klass.advices, :post) if klass.respond_to?(:advices)}
|
267
|
+
end
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
def eval_og_delete(klass)
|
272
|
+
klass.module_eval %{
|
273
|
+
def og_delete(store, pk, cascade = true)
|
274
|
+
#{Aspects.gen_advice_code(:og_delete, klass.advices, :pre) if klass.respond_to?(:advices)}
|
275
|
+
pk ||= @#{klass.primary_key.first}
|
276
|
+
transaction do |tx|
|
277
|
+
tx.conn[#{klass}].delete(pk)
|
278
|
+
if cascade and #{klass}.__meta[:descendants]
|
279
|
+
#{klass}.__meta[:descendants].each do |dclass, foreign_key|
|
280
|
+
eval "tx.conn[dclass].delete_if { |dobj| dobj.\#{foreign_key} == \#{pk} }"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
#{Aspects.gen_advice_code(:og_delete, klass.advices, :post) if klass.respond_to?(:advices)}
|
285
|
+
end
|
286
|
+
}
|
287
|
+
end
|
288
288
|
|
289
289
|
end
|
290
290
|
|