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/filesys.rb
CHANGED
@@ -10,102 +10,102 @@ module Og
|
|
10
10
|
|
11
11
|
class FilesysStore < Store
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
13
|
+
# :section: Store methods.
|
14
|
+
|
15
|
+
def self.dir(name)
|
16
|
+
"#{name}_db"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create(options)
|
20
|
+
name = dir(options[:name])
|
21
|
+
FileUtils.mkdir_p(name)
|
22
|
+
rescue
|
23
|
+
Logger.error "Cannot create '#{name}'"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.destroy(options)
|
27
|
+
name = dir(options[:name])
|
28
|
+
FileUtils.rm_rf(name)
|
29
|
+
rescue
|
30
|
+
Logger.error "Cannot destroy '#{name}'"
|
31
|
+
end
|
32
|
+
|
33
|
+
# :section: Misc methods.
|
34
|
+
|
35
|
+
# Initialize a connection to this store.
|
36
36
|
|
37
37
|
def initialize(options)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
38
|
+
super
|
39
|
+
|
40
|
+
@base_dir = self.class.dir(options[:name])
|
41
|
+
|
42
|
+
unless File.directory?(@base_dir)
|
43
|
+
Logger.info "Database '#{options[:name]}' not found!"
|
44
|
+
self.class.create(options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def enchant(klass, manager)
|
49
|
+
super
|
50
|
+
|
51
|
+
klass.const_set 'OGNAME', klass.to_s.gsub(/::/, "/").downcase
|
52
|
+
klass.property :oid, Fixnum
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
54
|
+
FileUtils.mkdir_p(path(klass))
|
55
|
+
File.open(spath(klass), 'w') { |f| f << '1' }
|
56
|
+
rescue => ex
|
57
|
+
p ex
|
58
|
+
Logger.error "Cannot create directory to store '#{klass}' classes!"
|
59
|
+
end
|
60
60
|
|
61
|
-
|
61
|
+
# :section: Lifecycle methods.
|
62
62
|
|
63
|
-
|
63
|
+
def load(oid, klass)
|
64
64
|
obj = nil
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
File.open(path(klass, oid), 'r') { |f| obj = YAML::load(f.read) }
|
66
|
+
return obj
|
67
|
+
rescue
|
68
|
+
return nil
|
69
|
+
end
|
70
70
|
|
71
|
-
|
72
|
-
|
71
|
+
def reload(obj)
|
72
|
+
end
|
73
73
|
|
74
|
-
|
74
|
+
def save(obj)
|
75
75
|
seq = nil
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
76
|
+
File.open(spath(obj.class), 'r') { |f| seq = f.read.to_i }
|
77
|
+
obj.oid = seq
|
78
|
+
File.open(path(obj.class, obj.oid), 'w') { |f| f << obj.to_yaml }
|
79
|
+
seq += 1
|
80
|
+
File.open(spath(obj.class), 'w') { |f| f << seq }
|
81
|
+
end
|
82
82
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
def delete(obj_or_pk, klass = nil, cascade = true)
|
84
|
+
pk = obj_or_pk.is_a?(Fixnum) ? obj_or_pk : obj_or_pk.oid
|
85
|
+
klass ||= obj_or_pk.class
|
86
|
+
FileUtils.rm(path(klass, pk))
|
87
|
+
end
|
88
88
|
|
89
|
-
|
90
|
-
|
89
|
+
def find
|
90
|
+
end
|
91
91
|
|
92
|
-
|
93
|
-
|
92
|
+
def count
|
93
|
+
end
|
94
94
|
|
95
95
|
private
|
96
96
|
|
97
|
-
|
97
|
+
# Path helper.
|
98
98
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
def path(klass, pk = nil)
|
100
|
+
class_dir = File.join(@base_dir, klass::OGNAME)
|
101
|
+
pk ? File.join(class_dir, "#{pk}.yml") : class_dir
|
102
|
+
end
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
104
|
+
# Path to sequence helper.
|
105
|
+
|
106
|
+
def spath(klass)
|
107
|
+
File.join(path(klass), 'seq')
|
108
|
+
end
|
109
109
|
|
110
110
|
end
|
111
111
|
|
data/lib/og/store/kirby.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
begin
|
2
|
-
|
2
|
+
require 'lib/og/store/kirby/kirbybase'
|
3
3
|
rescue Object => ex
|
4
|
-
|
5
|
-
|
4
|
+
Logger.error 'KirbyBase is not installed!'
|
5
|
+
Logger.error ex
|
6
6
|
end
|
7
7
|
|
8
8
|
require 'og/store/sql'
|
@@ -16,265 +16,270 @@ module Og
|
|
16
16
|
|
17
17
|
class KirbyStore < SqlStore
|
18
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
|
-
|
19
|
+
def self.db_dir(options)
|
20
|
+
"#{options[:name]}_db"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.destroy(options)
|
24
|
+
begin
|
25
|
+
FileUtils.rm_rf(db_dir(options))
|
26
|
+
super
|
27
|
+
rescue Object
|
28
|
+
Logger.info "Cannot drop '#{options[:name]}'!"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(options)
|
33
|
+
super
|
34
|
+
|
35
|
+
if options[:embedded]
|
36
|
+
name = self.class.db_dir(options)
|
37
|
+
FileUtils.mkdir_p(name)
|
38
|
+
@conn = KirbyBase.new(:local, nil, nil, name)
|
39
|
+
else
|
40
|
+
# TODO
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
def enchant(klass, manager)
|
49
|
+
klass.property :oid, Fixnum, :sql => 'integer PRIMARY KEY'
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
def query(sql)
|
54
|
+
Logger.debug sql if $DBG
|
55
|
+
return @conn.query(sql)
|
56
|
+
rescue => ex
|
57
|
+
handle_sql_exception(ex, sql)
|
58
|
+
end
|
59
|
+
|
60
|
+
def exec(sql)
|
61
|
+
Logger.debug sql if $DBG
|
62
|
+
@conn.query(sql).close
|
63
|
+
rescue => ex
|
64
|
+
handle_sql_exception(ex, sql)
|
65
|
+
end
|
66
|
+
|
67
|
+
def start
|
68
|
+
# nop
|
69
|
+
end
|
70
|
+
|
71
|
+
def commit
|
72
|
+
# nop
|
73
|
+
end
|
74
|
+
|
75
|
+
def rollback
|
76
|
+
# nop
|
77
|
+
end
|
78
78
|
|
79
79
|
private
|
80
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
|
-
|
225
|
-
|
226
|
-
|
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
|
-
|
81
|
+
def create_table(klass)
|
82
|
+
fields = fields_for_class(klass)
|
83
|
+
|
84
|
+
table = @conn.create_table(klass::OGTABLE, *fields) { |obj| obj.encrypt = false }
|
85
|
+
|
86
|
+
# Create join tables if needed. Join tables are used in
|
87
|
+
# 'many_to_many' relations.
|
88
|
+
|
89
|
+
if klass.__meta and join_tables = klass.__meta[:join_tables]
|
90
|
+
for join_table in join_tables
|
91
|
+
begin
|
92
|
+
@conn.create_table(join_table[:table],
|
93
|
+
join_table[:first_key], :Integer,
|
94
|
+
join_table[:second_key], :Integer)
|
95
|
+
# KirbyBase doesn't support indices.
|
96
|
+
rescue RuntimeError => error
|
97
|
+
# Unfortunately, KirbyBase just throws RuntimeErrors
|
98
|
+
# with no extra information, so we just have to look
|
99
|
+
# for the error message it uses.
|
100
|
+
if error.message =~ /table #{join_table[:table]} already exists/i
|
101
|
+
Logger.debug 'Join table already exists' if $DBG
|
102
|
+
else
|
103
|
+
raise
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def drop_table(klass)
|
111
|
+
@conn.drop_table(klass.table) if @conn.table_exists?(klass.table)
|
112
|
+
end
|
113
|
+
|
114
|
+
def fields_for_class(klass)
|
115
|
+
fields = []
|
116
|
+
|
117
|
+
klass.properties.each do |p|
|
118
|
+
klass.index(p.symbol) if p.meta[:index]
|
119
|
+
|
120
|
+
fields << p.symbol
|
121
|
+
|
122
|
+
type = p.klass.name.intern
|
123
|
+
type = :Integer if type == :Fixnum
|
124
|
+
|
125
|
+
fields << type
|
126
|
+
end
|
127
|
+
|
128
|
+
return fields
|
129
|
+
end
|
130
|
+
|
131
|
+
def create_field_map(klass)
|
132
|
+
map = {}
|
133
|
+
fields = @conn.get_table(klass.table).field_names
|
134
|
+
|
135
|
+
fields.size.times do |i|
|
136
|
+
map[fields[i]] = i
|
137
|
+
end
|
138
|
+
|
139
|
+
return map
|
140
|
+
end
|
141
|
+
|
142
|
+
# Return an sql string evaluator for the property.
|
143
|
+
# No need to optimize this, used only to precalculate code.
|
144
|
+
# YAML is used to store general Ruby objects to be more
|
145
|
+
# portable.
|
146
|
+
#--
|
147
|
+
# FIXME: add extra handling for float.
|
148
|
+
#++
|
149
|
+
|
150
|
+
def write_prop(p)
|
151
|
+
if p.klass.ancestors.include?(Integer)
|
152
|
+
return "@#{p.symbol} || nil"
|
153
|
+
elsif p.klass.ancestors.include?(Float)
|
154
|
+
return "@#{p.symbol} || nil"
|
155
|
+
elsif p.klass.ancestors.include?(String)
|
156
|
+
return %|@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : nil|
|
157
|
+
elsif p.klass.ancestors.include?(Time)
|
158
|
+
return %|@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : nil|
|
159
|
+
elsif p.klass.ancestors.include?(Date)
|
160
|
+
return %|@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : nil|
|
161
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
162
|
+
return "@#{p.symbol} ? \"'t'\" : nil"
|
163
|
+
else
|
164
|
+
# gmosx: keep the '' for nil symbols.
|
165
|
+
return %|@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"|
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Return an evaluator for reading the property.
|
170
|
+
# No need to optimize this, used only to precalculate code.
|
171
|
+
|
172
|
+
def read_prop(p, col)
|
173
|
+
if p.klass.ancestors.include?(Integer)
|
174
|
+
return "#{self.class}.parse_int(res[#{col} + offset])"
|
175
|
+
elsif p.klass.ancestors.include?(Float)
|
176
|
+
return "#{self.class}.parse_float(res[#{col} + offset])"
|
177
|
+
elsif p.klass.ancestors.include?(String)
|
178
|
+
return "res[#{col} + offset]"
|
179
|
+
elsif p.klass.ancestors.include?(Time)
|
180
|
+
return "#{self.class}.parse_timestamp(res[#{col} + offset])"
|
181
|
+
elsif p.klass.ancestors.include?(Date)
|
182
|
+
return "#{self.class}.parse_date(res[#{col} + offset])"
|
183
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
184
|
+
return "('0' != res[#{col} + offset])"
|
185
|
+
else
|
186
|
+
return "YAML::load(res[#{col} + offset])"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# :section: Lifecycle method compilers.
|
191
|
+
|
192
|
+
# Compile the og_update method for the class.
|
193
|
+
|
194
|
+
def eval_og_insert(klass)
|
195
|
+
pk = klass.pk_symbol
|
196
|
+
props = klass.properties
|
197
|
+
|
198
|
+
data = props.collect {|p| ":#{p.symbol} => #{write_prop(p)}"}.join(', ')
|
199
|
+
# data.gsub!(/#|\{|\}/, '')
|
200
|
+
|
201
|
+
klass.module_eval %{
|
202
|
+
def og_insert(store)
|
203
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)}
|
204
|
+
store.conn.get_table('#{klass.table}').insert(#{data})
|
205
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :post) if klass.respond_to?(:advices)}
|
206
|
+
end
|
207
|
+
}
|
208
|
+
end
|
209
|
+
|
210
|
+
# Compile the og_update method for the class.
|
211
|
+
|
212
|
+
def eval_og_update(klass)
|
213
|
+
pk = klass.pk_symbol
|
214
|
+
props = klass.properties.reject { |p| pk == p.symbol }
|
215
|
+
|
216
|
+
updates = props.collect { |p|
|
217
|
+
"#{p.symbol}=#{write_prop(p)}"
|
218
|
+
}
|
219
|
+
|
220
|
+
sql = "UPDATE #{klass::OGTABLE} SET #{updates.join(', ')} WHERE #{pk}=#\{@#{pk}\}"
|
221
|
+
|
222
|
+
klass.module_eval %{
|
223
|
+
def og_update(store)
|
224
|
+
#{Aspects.gen_advice_code(:og_update, klass.advices, :pre) if klass.respond_to?(:advices)}
|
225
|
+
store.exec "#{sql}"
|
226
|
+
#{Aspects.gen_advice_code(:og_update, klass.advices, :post) if klass.respond_to?(:advices)}
|
227
|
+
end
|
228
|
+
}
|
229
|
+
end
|
230
|
+
|
231
|
+
# Compile the og_read method for the class. This method is
|
232
|
+
# used to read (deserialize) the given class from the store.
|
233
|
+
# In order to allow for changing field/attribute orders a
|
234
|
+
# field mapping hash is used.
|
235
|
+
|
236
|
+
def eval_og_read(klass)
|
237
|
+
code = []
|
238
|
+
props = klass.properties
|
239
|
+
field_map = create_field_map(klass)
|
240
|
+
|
241
|
+
props.each do |p|
|
242
|
+
if col = field_map[p.symbol]
|
243
|
+
code << "@#{p.symbol} = #{read_prop(p, col)}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
code = code.join('; ')
|
248
|
+
|
249
|
+
klass.module_eval %{
|
250
|
+
def og_read(res, row = 0, offset = 0)
|
251
|
+
#{Aspects.gen_advice_code(:og_read, klass.advices, :pre) if klass.respond_to?(:advices)}
|
252
|
+
#{code}
|
253
|
+
#{Aspects.gen_advice_code(:og_read, klass.advices, :post) if klass.respond_to?(:advices)}
|
254
|
+
end
|
255
|
+
}
|
256
|
+
end
|
257
|
+
|
258
|
+
#--
|
259
|
+
# FIXME: is pk needed as parameter?
|
260
|
+
#++
|
261
|
+
|
262
|
+
def eval_og_delete(klass)
|
263
|
+
klass.module_eval %{
|
264
|
+
def og_delete(store, pk, cascade = true)
|
265
|
+
#{Aspects.gen_advice_code(:og_delete, klass.advices, :pre) if klass.respond_to?(:advices)}
|
266
|
+
pk ||= @#{klass.pk_symbol}
|
267
|
+
transaction do |tx|
|
268
|
+
tx.exec "DELETE FROM #{klass.table} WHERE #{klass.pk_symbol}=\#{pk}"
|
269
|
+
if cascade and #{klass}.__meta[:descendants]
|
270
|
+
#{klass}.__meta[:descendants].each do |dclass, foreign_key|
|
271
|
+
tx.exec "DELETE FROM \#{dclass::OGTABLE} WHERE \#{foreign_key}=\#{pk}"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
#{Aspects.gen_advice_code(:og_delete, klass.advices, :post) if klass.respond_to?(:advices)}
|
276
|
+
end
|
277
|
+
}
|
278
|
+
end
|
277
279
|
|
278
280
|
end
|
279
281
|
|
280
282
|
end
|
283
|
+
|
284
|
+
# * George Moschovitis <gm@navel.gr>
|
285
|
+
# * Ysabel <deb@isabel.org>
|