og 0.23.0 → 0.24.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/ProjectInfo +58 -0
- data/README +5 -4
- data/Rakefile +2 -2
- data/doc/AUTHORS +10 -7
- data/doc/RELEASES +108 -0
- data/lib/og.rb +1 -3
- data/lib/og/collection.rb +4 -4
- data/lib/og/entity.rb +96 -27
- data/lib/og/evolution.rb +78 -0
- data/lib/og/manager.rb +29 -32
- data/lib/og/mixin/hierarchical.rb +1 -1
- data/lib/og/mixin/optimistic_locking.rb +5 -8
- data/lib/og/mixin/orderable.rb +15 -2
- data/lib/og/mixin/schema_inheritance_base.rb +12 -0
- data/lib/og/mixin/taggable.rb +29 -25
- data/lib/og/mixin/timestamped.rb +4 -2
- data/lib/og/mixin/tree.rb +0 -1
- data/lib/og/relation.rb +161 -116
- data/lib/og/relation/all.rb +6 -0
- data/lib/og/relation/belongs_to.rb +4 -1
- data/lib/og/relation/has_many.rb +6 -5
- data/lib/og/relation/joins_many.rb +13 -12
- data/lib/og/relation/refers_to.rb +3 -3
- data/lib/og/store.rb +9 -9
- data/lib/og/store/{filesys.rb → alpha/filesys.rb} +0 -0
- data/lib/og/store/alpha/kirby.rb +284 -0
- data/lib/og/store/{memory.rb → alpha/memory.rb} +2 -0
- data/lib/og/store/{sqlserver.rb → alpha/sqlserver.rb} +6 -6
- data/lib/og/store/kirby.rb +145 -162
- data/lib/og/store/mysql.rb +58 -27
- data/lib/og/store/psql.rb +15 -13
- data/lib/og/store/sql.rb +136 -135
- data/lib/og/store/sqlite.rb +13 -12
- data/lib/og/validation.rb +2 -2
- data/lib/vendor/kbserver.rb +20 -0
- data/lib/vendor/kirbybase.rb +2790 -1601
- data/test/og/CONFIG.rb +79 -0
- data/test/og/mixin/tc_hierarchical.rb +1 -1
- data/test/og/mixin/tc_optimistic_locking.rb +1 -3
- data/test/og/mixin/tc_orderable.rb +42 -1
- data/test/og/mixin/tc_taggable.rb +1 -1
- data/test/og/mixin/tc_timestamped.rb +1 -1
- data/test/og/store/tc_filesys.rb +1 -2
- data/test/og/tc_delete_all.rb +45 -0
- data/test/og/tc_inheritance.rb +10 -38
- data/test/og/tc_join.rb +2 -11
- data/test/og/tc_multiple.rb +3 -16
- data/test/og/tc_override.rb +3 -3
- data/test/og/tc_polymorphic.rb +3 -13
- data/test/og/tc_relation.rb +8 -6
- data/test/og/tc_reverse.rb +2 -11
- data/test/og/tc_select.rb +2 -15
- data/test/og/tc_store.rb +4 -63
- data/test/og/tc_types.rb +1 -2
- metadata +80 -77
@@ -6,7 +6,10 @@ class BelongsTo < RefersTo
|
|
6
6
|
|
7
7
|
def enchant
|
8
8
|
super
|
9
|
-
target_class.
|
9
|
+
unless target_class.ann.this[:descendants]
|
10
|
+
target_class.ann(:this, :descendants => [])
|
11
|
+
end
|
12
|
+
target_class.ann.this.descendants! << [owner_class, foreign_key]
|
10
13
|
end
|
11
14
|
|
12
15
|
end
|
data/lib/og/relation/has_many.rb
CHANGED
@@ -19,7 +19,7 @@ end
|
|
19
19
|
|
20
20
|
class HasMany < Relation
|
21
21
|
def resolve_polymorphic
|
22
|
-
|
22
|
+
unless target_class.relations.empty?
|
23
23
|
unless target_class.relations.find { |r| r.is_a?(BelongsTo) and r.target_class == owner_class }
|
24
24
|
target_class.belongs_to(owner_class)
|
25
25
|
end
|
@@ -29,7 +29,7 @@ class HasMany < Relation
|
|
29
29
|
def enchant
|
30
30
|
self[:owner_singular_name] = owner_class.to_s.demodulize.underscore.downcase
|
31
31
|
self[:target_singular_name] = target_plural_name.to_s.singular
|
32
|
-
self[:foreign_key] = "#{foreign_name || owner_singular_name}_#{
|
32
|
+
self[:foreign_key] = "#{foreign_name || owner_singular_name}_#{owner_class.primary_key}"
|
33
33
|
# gmosx: DON'T set self[:foreign_field]
|
34
34
|
foreign_field = self[:foreign_field] || self[:foreign_key]
|
35
35
|
|
@@ -55,17 +55,18 @@ class HasMany < Relation
|
|
55
55
|
|
56
56
|
def add_#{target_singular_name}(obj, options = nil)
|
57
57
|
return unless obj
|
58
|
-
obj.#{foreign_key} = @#{
|
58
|
+
obj.#{foreign_key} = @#{owner_class.primary_key}
|
59
59
|
obj.save
|
60
60
|
end
|
61
61
|
|
62
62
|
def remove_#{target_singular_name}(obj)
|
63
63
|
obj.#{foreign_key} = nil
|
64
|
+
obj.save
|
64
65
|
end
|
65
66
|
|
66
67
|
def find_#{target_plural_name}(options = {})
|
67
68
|
find_options = {
|
68
|
-
:condition => "#{foreign_field} = \#{og_quote(
|
69
|
+
:condition => "#{foreign_field} = \#{og_quote(#{owner_class.primary_key})}"
|
69
70
|
}
|
70
71
|
if options
|
71
72
|
if condition = options.delete(:condition)
|
@@ -77,7 +78,7 @@ class HasMany < Relation
|
|
77
78
|
end
|
78
79
|
|
79
80
|
def count_#{target_plural_name}
|
80
|
-
#{target_class}.count(:condition => "#{foreign_field} = \#{og_quote(
|
81
|
+
#{target_class}.count(:condition => "#{foreign_field} = \#{og_quote(#{owner_class.primary_key})}")
|
81
82
|
end
|
82
83
|
}
|
83
84
|
end
|
@@ -28,25 +28,26 @@ class JoinsMany < Relation
|
|
28
28
|
# handle schema_inheritance
|
29
29
|
|
30
30
|
join_class = owner_class
|
31
|
-
if sclass = owner_class.
|
32
|
-
join_class = sclass
|
31
|
+
if sclass = owner_class.ann.this[:superclass]
|
32
|
+
join_class = sclass
|
33
33
|
end
|
34
34
|
join_table_info = store.join_table_info(join_class, target_class)
|
35
35
|
|
36
36
|
if through = self[:through]
|
37
37
|
# A custom class is used for the join. Use the class
|
38
38
|
# table and don't create a new table.
|
39
|
-
through =
|
39
|
+
through = Relation.symbol_to_class(through, owner_class) if through.is_a?(Symbol)
|
40
40
|
join_table = self[:join_table] = through.table
|
41
41
|
else
|
42
42
|
# Calculate the name of the join table
|
43
43
|
join_table = self[:join_table] = join_table_info[:table]
|
44
|
-
# Create a join table.
|
45
|
-
owner_class.
|
44
|
+
# Create a join table.
|
45
|
+
owner_class.ann :this, :join_tables => []
|
46
|
+
owner_class.ann.this.join_tables! << join_table_info
|
46
47
|
end
|
47
48
|
|
48
|
-
owner_key = join_table_info[:owner_key]
|
49
|
-
target_key = join_table_info[:target_key]
|
49
|
+
owner_key = join_table_info[:owner_key]
|
50
|
+
target_key = join_table_info[:target_key]
|
50
51
|
|
51
52
|
owner_class.module_eval %{
|
52
53
|
attr_accessor :#{target_plural_name}
|
@@ -82,8 +83,8 @@ class JoinsMany < Relation
|
|
82
83
|
def find_#{target_plural_name}(options = {})
|
83
84
|
find_options = {
|
84
85
|
:join_table => "#{join_table}",
|
85
|
-
:join_condition => "#{join_table}.#{target_key}
|
86
|
-
:condition => "#{join_table}.#{owner_key}=\#\{
|
86
|
+
:join_condition => "#{join_table}.#{target_key}=\#{#{target_class}::OGTABLE}.oid",
|
87
|
+
:condition => "#{join_table}.#{owner_key}=\#\{#{owner_class.primary_key}\}"
|
87
88
|
}
|
88
89
|
if options
|
89
90
|
if condition = options.delete(:condition)
|
@@ -101,8 +102,8 @@ class JoinsMany < Relation
|
|
101
102
|
def count_#{target_plural_name}
|
102
103
|
find_options = {
|
103
104
|
:join_table => "#{join_table}",
|
104
|
-
:join_condition => "#{join_table}.#{target_key}
|
105
|
-
:condition => "#{join_table}.#{owner_key}=\#\{
|
105
|
+
:join_condition => "#{join_table}.#{target_key}=\#{#{target_class}::OGTABLE}.oid",
|
106
|
+
:condition => "#{join_table}.#{owner_key}=\#\{#{owner_class.primary_key}\}"
|
106
107
|
}
|
107
108
|
#{target_class}.find(find_options).size
|
108
109
|
end
|
@@ -111,7 +112,7 @@ class JoinsMany < Relation
|
|
111
112
|
if through
|
112
113
|
owner_class.module_eval %{
|
113
114
|
def #{target_singular_name}_join_data(t)
|
114
|
-
#{through}.find_one(:condition => "#{owner_key}=\#{
|
115
|
+
#{through}.find_one(:condition => "#{owner_key}=\#{#{owner_class.primary_key}} and #{target_key}=\#{t.pk}")
|
115
116
|
end
|
116
117
|
}
|
117
118
|
end
|
@@ -5,7 +5,7 @@ module Og
|
|
5
5
|
class RefersTo < Relation
|
6
6
|
|
7
7
|
def enchant
|
8
|
-
self[:foreign_key] = "#{foreign_name || target_singular_name}_#{
|
8
|
+
self[:foreign_key] = "#{foreign_name || target_singular_name}_#{target_class.primary_key}"
|
9
9
|
|
10
10
|
if self[:field]
|
11
11
|
field = ", :field => :#{self[:field]}"
|
@@ -13,7 +13,7 @@ class RefersTo < Relation
|
|
13
13
|
|
14
14
|
owner_class.module_eval %{
|
15
15
|
attr_accessor :#{target_singular_name}
|
16
|
-
prop_accessor :#{foreign_key}, #{
|
16
|
+
prop_accessor :#{foreign_key}, #{target_class.primary_key.klass}#{field}, :relation => true
|
17
17
|
|
18
18
|
def #{target_singular_name}(reload = false)
|
19
19
|
return nil if @#{foreign_key}.nil?
|
@@ -26,7 +26,7 @@ class RefersTo < Relation
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def #{target_singular_name}=(obj)
|
29
|
-
@#{foreign_key} = obj.#{
|
29
|
+
@#{foreign_key} = obj.#{target_class.primary_key} if obj
|
30
30
|
end
|
31
31
|
}
|
32
32
|
end
|
data/lib/og/store.rb
CHANGED
@@ -55,15 +55,15 @@ class Store
|
|
55
55
|
meta :index, arg
|
56
56
|
end
|
57
57
|
|
58
|
-
pk = klass.primary_key.
|
58
|
+
pk = klass.primary_key.symbol
|
59
59
|
|
60
60
|
klass.module_eval %{
|
61
61
|
def saved?
|
62
|
-
return
|
62
|
+
return #{klass.primary_key.symbol}
|
63
63
|
end
|
64
64
|
|
65
65
|
def unsaved?
|
66
|
-
return
|
66
|
+
return !#{klass.primary_key.symbol}
|
67
67
|
end
|
68
68
|
|
69
69
|
# Evaluate an alias for the primary key.
|
@@ -72,7 +72,7 @@ class Store
|
|
72
72
|
alias_method :pk=, :#{pk}=
|
73
73
|
|
74
74
|
def self.pk_symbol
|
75
|
-
:#{klass.primary_key.
|
75
|
+
:#{klass.primary_key.symbol}
|
76
76
|
end
|
77
77
|
}
|
78
78
|
|
@@ -80,16 +80,16 @@ class Store
|
|
80
80
|
|
81
81
|
code = ''
|
82
82
|
|
83
|
-
for p in klass.properties
|
84
|
-
# gmosx: :uniq does NOT set a unique
|
83
|
+
for p in klass.properties.values
|
84
|
+
# gmosx: :uniq does NOT set a unique constraint in the
|
85
85
|
# database.
|
86
|
-
finder = p.
|
86
|
+
finder = p.uniq || p.unique ? 'find_one' : 'find'
|
87
87
|
|
88
88
|
code << %{
|
89
|
-
def self.find_by_#{p
|
89
|
+
def self.find_by_#{p}(val, operator = '=', options = {})
|
90
90
|
options.update(
|
91
91
|
:class => #{klass},
|
92
|
-
:condition => "#{p.
|
92
|
+
:condition => "#{p.field || p}\#{operator}\#{ogmanager.store.quote(val)}"
|
93
93
|
)
|
94
94
|
ogmanager.store.#{finder}(options)
|
95
95
|
end;
|
File without changes
|
@@ -0,0 +1,284 @@
|
|
1
|
+
begin
|
2
|
+
require 'lib/vendor/kirbybase'
|
3
|
+
rescue Object => ex
|
4
|
+
Logger.error 'KirbyBase is not installed!'
|
5
|
+
Logger.error ex
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'og/store/sql'
|
9
|
+
|
10
|
+
module Og
|
11
|
+
|
12
|
+
# A Store that persists objects into an KirbyBase database.
|
13
|
+
# KirbyBase is a pure-ruby database implementation.
|
14
|
+
# To read documentation about the methods, consult the
|
15
|
+
# documentation for SqlStore and Store.
|
16
|
+
|
17
|
+
class KirbyStore < SqlStore
|
18
|
+
|
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
|
+
|
79
|
+
private
|
80
|
+
|
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
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
283
|
+
|
284
|
+
# * George Moschovitis <gm@navel.gr>
|