og 0.16.0 → 0.17.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 +485 -0
- data/README +35 -12
- data/Rakefile +4 -7
- data/benchmark/bench.rb +1 -1
- data/doc/AUTHORS +3 -3
- data/doc/RELEASES +153 -2
- data/doc/config.txt +0 -7
- data/doc/tutorial.txt +7 -0
- data/examples/README +5 -0
- data/examples/mysql_to_psql.rb +25 -50
- data/examples/run.rb +62 -77
- data/install.rb +1 -1
- data/lib/og.rb +45 -106
- data/lib/og/collection.rb +156 -0
- data/lib/og/entity.rb +131 -0
- data/lib/og/errors.rb +10 -15
- data/lib/og/manager.rb +115 -0
- data/lib/og/{mixins → mixin}/hierarchical.rb +43 -37
- data/lib/og/{mixins → mixin}/orderable.rb +35 -35
- data/lib/og/{mixins → mixin}/timestamped.rb +0 -6
- data/lib/og/{mixins → mixin}/tree.rb +0 -4
- data/lib/og/relation.rb +178 -0
- data/lib/og/relation/belongs_to.rb +14 -0
- data/lib/og/relation/has_many.rb +62 -0
- data/lib/og/relation/has_one.rb +17 -0
- data/lib/og/relation/joins_many.rb +69 -0
- data/lib/og/relation/many_to_many.rb +17 -0
- data/lib/og/relation/refers_to.rb +31 -0
- data/lib/og/store.rb +223 -0
- data/lib/og/store/filesys.rb +113 -0
- data/lib/og/store/madeleine.rb +4 -0
- data/lib/og/store/memory.rb +291 -0
- data/lib/og/store/mysql.rb +283 -0
- data/lib/og/store/psql.rb +238 -0
- data/lib/og/store/sql.rb +599 -0
- data/lib/og/store/sqlite.rb +190 -0
- data/lib/og/store/sqlserver.rb +262 -0
- data/lib/og/types.rb +19 -0
- data/lib/og/validation.rb +0 -4
- data/test/og/{mixins → mixin}/tc_hierarchical.rb +21 -23
- data/test/og/{mixins → mixin}/tc_orderable.rb +15 -14
- data/test/og/mixin/tc_timestamped.rb +38 -0
- data/test/og/store/tc_filesys.rb +71 -0
- data/test/og/tc_relation.rb +36 -0
- data/test/og/tc_store.rb +290 -0
- data/test/og/tc_types.rb +21 -0
- metadata +54 -40
- data/examples/mock_example.rb +0 -50
- data/lib/og/adapters/base.rb +0 -706
- data/lib/og/adapters/filesys.rb +0 -117
- data/lib/og/adapters/mysql.rb +0 -350
- data/lib/og/adapters/oracle.rb +0 -368
- data/lib/og/adapters/psql.rb +0 -272
- data/lib/og/adapters/sqlite.rb +0 -265
- data/lib/og/adapters/sqlserver.rb +0 -356
- data/lib/og/database.rb +0 -290
- data/lib/og/enchant.rb +0 -149
- data/lib/og/meta.rb +0 -407
- data/lib/og/testing/mock.rb +0 -165
- data/lib/og/typemacros.rb +0 -24
- data/test/og/adapters/tc_filesys.rb +0 -83
- data/test/og/adapters/tc_sqlite.rb +0 -86
- data/test/og/adapters/tc_sqlserver.rb +0 -96
- data/test/og/tc_automanage.rb +0 -46
- data/test/og/tc_lifecycle.rb +0 -105
- data/test/og/tc_many_to_many.rb +0 -61
- data/test/og/tc_meta.rb +0 -55
- data/test/og/tc_validation.rb +0 -89
- data/test/tc_og.rb +0 -364
@@ -0,0 +1,283 @@
|
|
1
|
+
begin
|
2
|
+
require 'mysql'
|
3
|
+
rescue Object => ex
|
4
|
+
Logger.error 'Ruby-Mysql bindings are not installed!'
|
5
|
+
Logger.error ex
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'og/store/sql'
|
9
|
+
|
10
|
+
# Customize the standard mysql resultset to make
|
11
|
+
# more compatible with Og.
|
12
|
+
|
13
|
+
class Mysql::Result
|
14
|
+
def blank?
|
15
|
+
0 == num_rows
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :next, :fetch_row
|
19
|
+
|
20
|
+
def each_row
|
21
|
+
each do |row|
|
22
|
+
yield(row, 0)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def first_value
|
27
|
+
val = fetch_row[0]
|
28
|
+
free
|
29
|
+
return val
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method :close, :free
|
33
|
+
end
|
34
|
+
|
35
|
+
module Og
|
36
|
+
|
37
|
+
module MysqlUtils
|
38
|
+
include SqlUtils
|
39
|
+
|
40
|
+
def escape(str)
|
41
|
+
return nil unless str
|
42
|
+
return Mysql.quote(str)
|
43
|
+
end
|
44
|
+
|
45
|
+
def quote(val)
|
46
|
+
case val
|
47
|
+
when Fixnum, Integer, Float
|
48
|
+
val ? val.to_s : 'NULL'
|
49
|
+
when String
|
50
|
+
val ? "'#{escape(val)}'" : 'NULL'
|
51
|
+
when Time
|
52
|
+
val ? "'#{timestamp(val)}'" : 'NULL'
|
53
|
+
when Date
|
54
|
+
val ? "'#{date(val)}'" : 'NULL'
|
55
|
+
when TrueClass
|
56
|
+
val ? "'1'" : 'NULL'
|
57
|
+
else
|
58
|
+
# gmosx: keep the '' for nil symbols.
|
59
|
+
val ? escape(val.to_yaml) : ''
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# A Store that persists objects into a MySQL database.
|
65
|
+
# To read documentation about the methods, consult the documentation
|
66
|
+
# for SqlStore and Store.
|
67
|
+
|
68
|
+
class MysqlStore < SqlStore
|
69
|
+
extend MysqlUtils
|
70
|
+
include MysqlUtils
|
71
|
+
|
72
|
+
def self.create(options)
|
73
|
+
# gmosx: system is used to avoid shell expansion.
|
74
|
+
system 'mysqladmin', '-f', "--user=#{options[:user]}",
|
75
|
+
"--password=#{options[:password]}",
|
76
|
+
'create', options[:name]
|
77
|
+
super
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.destroy(options)
|
81
|
+
system 'mysqladmin', '-f', "--user=#{options[:user]}",
|
82
|
+
"--password=#{options[:password]}", 'drop',
|
83
|
+
options[:name]
|
84
|
+
super
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize(options)
|
88
|
+
super
|
89
|
+
|
90
|
+
@typemap.update(TrueClass => 'tinyint')
|
91
|
+
|
92
|
+
@conn = Mysql.connect(
|
93
|
+
options[:address] || 'localhost',
|
94
|
+
options[:user],
|
95
|
+
options[:password],
|
96
|
+
options[:name]
|
97
|
+
)
|
98
|
+
rescue => ex
|
99
|
+
if ex.errno == 1049 # database does not exist.
|
100
|
+
Logger.info "Database '#{options[:name]}' not found!"
|
101
|
+
self.class.create(options)
|
102
|
+
retry
|
103
|
+
end
|
104
|
+
raise
|
105
|
+
end
|
106
|
+
|
107
|
+
def close
|
108
|
+
@conn.close
|
109
|
+
super
|
110
|
+
end
|
111
|
+
|
112
|
+
def enchant(klass, manager)
|
113
|
+
klass.property :oid, Fixnum, :sql => 'integer AUTO_INCREMENT PRIMARY KEY'
|
114
|
+
super
|
115
|
+
end
|
116
|
+
|
117
|
+
def query(sql)
|
118
|
+
# Logger.debug sql if $DBG
|
119
|
+
@conn.query_with_result = true
|
120
|
+
return @conn.query(sql)
|
121
|
+
rescue => ex
|
122
|
+
handle_sql_exception(ex, sql)
|
123
|
+
end
|
124
|
+
|
125
|
+
def exec(sql)
|
126
|
+
# Logger.debug sql if $DBG
|
127
|
+
@conn.query_with_result = false
|
128
|
+
@conn.query(sql)
|
129
|
+
rescue => ex
|
130
|
+
handle_sql_exception(ex, sql)
|
131
|
+
end
|
132
|
+
|
133
|
+
def start
|
134
|
+
# nop
|
135
|
+
# FIXME: InnoDB supports transactions.
|
136
|
+
end
|
137
|
+
|
138
|
+
# Commit a transaction.
|
139
|
+
|
140
|
+
def commit
|
141
|
+
# nop, not supported?
|
142
|
+
# FIXME: InnoDB supports transactions.
|
143
|
+
end
|
144
|
+
|
145
|
+
# Rollback a transaction.
|
146
|
+
|
147
|
+
def rollback
|
148
|
+
# nop, not supported?
|
149
|
+
# FIXME: InnoDB supports transactions.
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def create_table(klass)
|
155
|
+
columns = columns_for_class(klass)
|
156
|
+
|
157
|
+
sql = "CREATE TABLE #{klass::OGTABLE} (#{columns.join(', ')}"
|
158
|
+
|
159
|
+
# Create table constrains.
|
160
|
+
|
161
|
+
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
162
|
+
sql << ", #{constrains.join(', ')}"
|
163
|
+
end
|
164
|
+
|
165
|
+
sql << ");"
|
166
|
+
|
167
|
+
# Create indices.
|
168
|
+
|
169
|
+
if klass.__meta and indices = klass.__meta[:index]
|
170
|
+
for data in indices
|
171
|
+
idx, options = *data
|
172
|
+
idx = idx.to_s
|
173
|
+
pre_sql, post_sql = options[:pre], options[:post]
|
174
|
+
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
175
|
+
sql << " CREATE #{pre_sql} INDEX #{klass::OGTABLE}_#{idxname}_idx #{post_sql} ON #{klass::OGTABLE} (#{idx});"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
@conn.query_with_result = false
|
180
|
+
|
181
|
+
begin
|
182
|
+
@conn.query(sql)
|
183
|
+
Logger.info "Created table '#{klass::OGTABLE}'."
|
184
|
+
rescue => ex
|
185
|
+
if ex.errno == 1050 # table already exists.
|
186
|
+
Logger.debug 'Table already exists' if $DBG
|
187
|
+
return
|
188
|
+
else
|
189
|
+
raise
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Create join tables if needed. Join tables are used in
|
194
|
+
# 'many_to_many' relations.
|
195
|
+
|
196
|
+
if klass.__meta and join_tables = klass.__meta[:join_tables]
|
197
|
+
for join_table in join_tables
|
198
|
+
begin
|
199
|
+
@conn.query("CREATE TABLE #{join_table} (key1 integer NOT NULL, key2 integer NOT NULL)")
|
200
|
+
@conn.query("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)")
|
201
|
+
@conn.query("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)")
|
202
|
+
rescue => ex
|
203
|
+
if ex.errno == 1050 # table already exists.
|
204
|
+
Logger.debug 'Join table already exists'
|
205
|
+
else
|
206
|
+
raise
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def create_column_map(klass)
|
214
|
+
conn.query_with_result = true
|
215
|
+
res = @conn.query "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
|
216
|
+
map = {}
|
217
|
+
|
218
|
+
res.num_fields.times do |i|
|
219
|
+
map[res.fetch_field.name.intern] = i
|
220
|
+
end
|
221
|
+
|
222
|
+
return map
|
223
|
+
ensure
|
224
|
+
res.close if res
|
225
|
+
end
|
226
|
+
|
227
|
+
def write_prop(p)
|
228
|
+
if p.klass.ancestors.include?(Integer)
|
229
|
+
return "#\{@#{p.symbol} || 'NULL'\}"
|
230
|
+
elsif p.klass.ancestors.include?(Float)
|
231
|
+
return "#\{@#{p.symbol} || 'NULL'\}"
|
232
|
+
elsif p.klass.ancestors.include?(String)
|
233
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : 'NULL'\}|
|
234
|
+
elsif p.klass.ancestors.include?(Time)
|
235
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
|
236
|
+
elsif p.klass.ancestors.include?(Date)
|
237
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
|
238
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
239
|
+
return "#\{@#{p.symbol} ? \"'1'\" : 'NULL' \}"
|
240
|
+
else
|
241
|
+
# gmosx: keep the '' for nil symbols.
|
242
|
+
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def read_prop(p, col)
|
247
|
+
if p.klass.ancestors.include?(Integer)
|
248
|
+
return "res[#{col} + offset].to_i"
|
249
|
+
elsif p.klass.ancestors.include?(Float)
|
250
|
+
return "res[#{col} + offset].to_f"
|
251
|
+
elsif p.klass.ancestors.include?(String)
|
252
|
+
return "res[#{col} + offset]"
|
253
|
+
elsif p.klass.ancestors.include?(Time)
|
254
|
+
return "#{self.class}.parse_timestamp(res[#{col} + offset])"
|
255
|
+
elsif p.klass.ancestors.include?(Date)
|
256
|
+
return "#{self.class}.parse_date(res[#{col} + offset])"
|
257
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
258
|
+
return "('0' != res[#{col} + offset])"
|
259
|
+
else
|
260
|
+
return "YAML.load(res[#{col} + offset])"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def eval_og_insert(klass)
|
265
|
+
props = klass.properties
|
266
|
+
values = props.collect { |p| write_prop(p) }.join(',')
|
267
|
+
|
268
|
+
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| p.symbol.to_s}.join(',')}) VALUES (#{values})"
|
269
|
+
|
270
|
+
klass.class_eval %{
|
271
|
+
def og_insert(store)
|
272
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)}
|
273
|
+
store.conn.query_with_result = false
|
274
|
+
store.conn.query "#{sql}"
|
275
|
+
@#{klass.pk_symbol} = store.conn.insert_id
|
276
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :post) if klass.respond_to?(:advices)}
|
277
|
+
end
|
278
|
+
}
|
279
|
+
end
|
280
|
+
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
begin
|
2
|
+
require 'postgres'
|
3
|
+
rescue Object => ex
|
4
|
+
Logger.error 'Ruby-PostgreSQL bindings are not installed!'
|
5
|
+
Logger.error ex
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'og/store/sql'
|
9
|
+
|
10
|
+
# Customize the standard postgres resultset to make
|
11
|
+
# more compatible with Og.
|
12
|
+
|
13
|
+
class PGresult
|
14
|
+
def blank?
|
15
|
+
0 == num_tuples
|
16
|
+
end
|
17
|
+
|
18
|
+
def next
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def each_row
|
23
|
+
for row in (0...num_tuples)
|
24
|
+
yield(self, row)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def first_value
|
29
|
+
val = getvalue(0, 0)
|
30
|
+
clear
|
31
|
+
return val
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :close, :clear
|
35
|
+
end
|
36
|
+
|
37
|
+
module Og
|
38
|
+
|
39
|
+
module PsqlUtils
|
40
|
+
include SqlUtils
|
41
|
+
|
42
|
+
def escape(str)
|
43
|
+
return nil unless str
|
44
|
+
return PGconn.escape(str)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# A Store that persists objects into a PostgreSQL database.
|
49
|
+
# To read documentation about the methods, consult the documentation
|
50
|
+
# for SqlStore and Store.
|
51
|
+
#
|
52
|
+
# === Design
|
53
|
+
#
|
54
|
+
# The getvalue interface is used instead of each for extra
|
55
|
+
# performance.
|
56
|
+
|
57
|
+
class PsqlStore < SqlStore
|
58
|
+
extend PsqlUtils
|
59
|
+
include PsqlUtils
|
60
|
+
|
61
|
+
def self.create(options)
|
62
|
+
# gmosx: system is used to avoid shell expansion.
|
63
|
+
system 'createdb', options[:name], '-U', options[:user]
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.destroy(options)
|
68
|
+
system 'dropdb', options[:name], '-U', options[:user]
|
69
|
+
super
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(options)
|
73
|
+
super
|
74
|
+
|
75
|
+
@conn = PGconn.connect(
|
76
|
+
options[:address],
|
77
|
+
options[:port], nil, nil,
|
78
|
+
options[:name],
|
79
|
+
options[:user].to_s,
|
80
|
+
options[:password].to_s
|
81
|
+
)
|
82
|
+
rescue => ex
|
83
|
+
# gmosx: any idea how to better test this?
|
84
|
+
if ex.to_s =~ /database .* does not exist/i
|
85
|
+
Logger.info "Database '#{options[:name]}' not found!"
|
86
|
+
self.class.create(options)
|
87
|
+
retry
|
88
|
+
end
|
89
|
+
raise
|
90
|
+
end
|
91
|
+
|
92
|
+
def close
|
93
|
+
@conn.close
|
94
|
+
super
|
95
|
+
end
|
96
|
+
|
97
|
+
def enchant(klass, manager)
|
98
|
+
klass.const_set 'OGSEQ', "#{table(klass)}_oid_seq"
|
99
|
+
klass.property :oid, Fixnum, :sql => 'serial PRIMARY KEY'
|
100
|
+
super
|
101
|
+
end
|
102
|
+
|
103
|
+
def query(sql)
|
104
|
+
Logger.debug sql if $DBG
|
105
|
+
return @conn.exec(sql)
|
106
|
+
rescue => ex
|
107
|
+
handle_sql_exception(ex, sql)
|
108
|
+
end
|
109
|
+
|
110
|
+
def exec(sql)
|
111
|
+
Logger.debug sql if $DBG
|
112
|
+
@conn.exec(sql).clear
|
113
|
+
rescue => ex
|
114
|
+
handle_sql_exception(ex, sql)
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def create_table(klass)
|
120
|
+
columns = columns_for_class(klass)
|
121
|
+
|
122
|
+
sql = "CREATE TABLE #{klass::OGTABLE} (#{columns.join(', ')}"
|
123
|
+
|
124
|
+
# Create table constrains.
|
125
|
+
|
126
|
+
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
127
|
+
sql << ", #{constrains.join(', ')}"
|
128
|
+
end
|
129
|
+
|
130
|
+
sql << ") WITHOUT OIDS;"
|
131
|
+
|
132
|
+
# Create indices.
|
133
|
+
|
134
|
+
if klass.__meta and indices = klass.__meta[:index]
|
135
|
+
for data in indices
|
136
|
+
idx, options = *data
|
137
|
+
idx = idx.to_s
|
138
|
+
pre_sql, post_sql = options[:pre], options[:post]
|
139
|
+
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
140
|
+
sql << " CREATE #{pre_sql} INDEX #{klass::OGTABLE}_#{idxname}_idx #{post_sql} ON #{klass::OGTABLE} (#{idx});"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
begin
|
145
|
+
@conn.exec(sql).clear
|
146
|
+
Logger.info "Created table '#{klass::OGTABLE}'."
|
147
|
+
rescue Object => ex
|
148
|
+
# gmosx: any idea how to better test this?
|
149
|
+
if ex.to_s =~ /relation .* already exists/i
|
150
|
+
Logger.debug 'Table already exists' if $DBG
|
151
|
+
return
|
152
|
+
else
|
153
|
+
raise
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Create join tables if needed. Join tables are used in
|
158
|
+
# 'many_to_many' relations.
|
159
|
+
|
160
|
+
if klass.__meta and join_tables = klass.__meta[:join_tables]
|
161
|
+
for join_table in join_tables
|
162
|
+
begin
|
163
|
+
@conn.exec("CREATE TABLE #{join_table} (key1 integer NOT NULL, key2 integer NOT NULL)").clear
|
164
|
+
@conn.exec("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").clear
|
165
|
+
@conn.exec("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").clear
|
166
|
+
rescue Object => ex
|
167
|
+
# gmosx: any idea how to better test this?
|
168
|
+
if ex.to_s =~ /relation .* already exists/i
|
169
|
+
Logger.debug 'Join table already exists'
|
170
|
+
else
|
171
|
+
raise
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def drop_table(klass)
|
179
|
+
super
|
180
|
+
exec "DROP SEQUENCE #{klass::OGSEQ}"
|
181
|
+
end
|
182
|
+
|
183
|
+
def create_column_map(klass)
|
184
|
+
res = @conn.exec "SELECT * FROM #{klass::OGTABLE} LIMIT 1"
|
185
|
+
map = {}
|
186
|
+
|
187
|
+
for column in res.fields
|
188
|
+
map[column.intern] = res.fieldnum(column)
|
189
|
+
end
|
190
|
+
|
191
|
+
return map
|
192
|
+
ensure
|
193
|
+
res.clear if res
|
194
|
+
end
|
195
|
+
|
196
|
+
def read_prop(p, col)
|
197
|
+
if p.klass.ancestors.include?(Integer)
|
198
|
+
return "res.getvalue(row, #{col} + offset).to_i"
|
199
|
+
elsif p.klass.ancestors.include?(Float)
|
200
|
+
return "res.getvalue(row, #{col} + offset).to_f"
|
201
|
+
elsif p.klass.ancestors.include?(String)
|
202
|
+
return "res.getvalue(row, #{col} + offset)"
|
203
|
+
elsif p.klass.ancestors.include?(Time)
|
204
|
+
return "#{self.class}.parse_timestamp(res.getvalue(row, #{col} + offset))"
|
205
|
+
elsif p.klass.ancestors.include?(Date)
|
206
|
+
return "#{self.class}.parse_date(res.getvalue(row, #{col} + offset))"
|
207
|
+
elsif p.klass.ancestors.include?(TrueClass)
|
208
|
+
return %|('t' == res.getvalue(row, #{col} + offset))|
|
209
|
+
else
|
210
|
+
return "YAML.load(res.getvalue(row, #{col} + offset))"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
#--
|
215
|
+
# TODO: create stored procedure.
|
216
|
+
#++
|
217
|
+
|
218
|
+
def eval_og_insert(klass)
|
219
|
+
props = klass.properties
|
220
|
+
values = props.collect { |p| write_prop(p) }.join(',')
|
221
|
+
|
222
|
+
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| p.symbol.to_s}.join(',')}) VALUES (#{values})"
|
223
|
+
|
224
|
+
klass.class_eval %{
|
225
|
+
def og_insert(store)
|
226
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)}
|
227
|
+
res = store.conn.exec "SELECT nextval('#{klass::OGSEQ}')"
|
228
|
+
@#{klass.pk_symbol} = res.getvalue(0, 0).to_i
|
229
|
+
res.clear
|
230
|
+
store.conn.exec("#{sql}").clear
|
231
|
+
#{Aspects.gen_advice_code(:og_insert, klass.advices, :post) if klass.respond_to?(:advices)}
|
232
|
+
end
|
233
|
+
}
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|