og 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGELOG +485 -0
  2. data/README +35 -12
  3. data/Rakefile +4 -7
  4. data/benchmark/bench.rb +1 -1
  5. data/doc/AUTHORS +3 -3
  6. data/doc/RELEASES +153 -2
  7. data/doc/config.txt +0 -7
  8. data/doc/tutorial.txt +7 -0
  9. data/examples/README +5 -0
  10. data/examples/mysql_to_psql.rb +25 -50
  11. data/examples/run.rb +62 -77
  12. data/install.rb +1 -1
  13. data/lib/og.rb +45 -106
  14. data/lib/og/collection.rb +156 -0
  15. data/lib/og/entity.rb +131 -0
  16. data/lib/og/errors.rb +10 -15
  17. data/lib/og/manager.rb +115 -0
  18. data/lib/og/{mixins → mixin}/hierarchical.rb +43 -37
  19. data/lib/og/{mixins → mixin}/orderable.rb +35 -35
  20. data/lib/og/{mixins → mixin}/timestamped.rb +0 -6
  21. data/lib/og/{mixins → mixin}/tree.rb +0 -4
  22. data/lib/og/relation.rb +178 -0
  23. data/lib/og/relation/belongs_to.rb +14 -0
  24. data/lib/og/relation/has_many.rb +62 -0
  25. data/lib/og/relation/has_one.rb +17 -0
  26. data/lib/og/relation/joins_many.rb +69 -0
  27. data/lib/og/relation/many_to_many.rb +17 -0
  28. data/lib/og/relation/refers_to.rb +31 -0
  29. data/lib/og/store.rb +223 -0
  30. data/lib/og/store/filesys.rb +113 -0
  31. data/lib/og/store/madeleine.rb +4 -0
  32. data/lib/og/store/memory.rb +291 -0
  33. data/lib/og/store/mysql.rb +283 -0
  34. data/lib/og/store/psql.rb +238 -0
  35. data/lib/og/store/sql.rb +599 -0
  36. data/lib/og/store/sqlite.rb +190 -0
  37. data/lib/og/store/sqlserver.rb +262 -0
  38. data/lib/og/types.rb +19 -0
  39. data/lib/og/validation.rb +0 -4
  40. data/test/og/{mixins → mixin}/tc_hierarchical.rb +21 -23
  41. data/test/og/{mixins → mixin}/tc_orderable.rb +15 -14
  42. data/test/og/mixin/tc_timestamped.rb +38 -0
  43. data/test/og/store/tc_filesys.rb +71 -0
  44. data/test/og/tc_relation.rb +36 -0
  45. data/test/og/tc_store.rb +290 -0
  46. data/test/og/tc_types.rb +21 -0
  47. metadata +54 -40
  48. data/examples/mock_example.rb +0 -50
  49. data/lib/og/adapters/base.rb +0 -706
  50. data/lib/og/adapters/filesys.rb +0 -117
  51. data/lib/og/adapters/mysql.rb +0 -350
  52. data/lib/og/adapters/oracle.rb +0 -368
  53. data/lib/og/adapters/psql.rb +0 -272
  54. data/lib/og/adapters/sqlite.rb +0 -265
  55. data/lib/og/adapters/sqlserver.rb +0 -356
  56. data/lib/og/database.rb +0 -290
  57. data/lib/og/enchant.rb +0 -149
  58. data/lib/og/meta.rb +0 -407
  59. data/lib/og/testing/mock.rb +0 -165
  60. data/lib/og/typemacros.rb +0 -24
  61. data/test/og/adapters/tc_filesys.rb +0 -83
  62. data/test/og/adapters/tc_sqlite.rb +0 -86
  63. data/test/og/adapters/tc_sqlserver.rb +0 -96
  64. data/test/og/tc_automanage.rb +0 -46
  65. data/test/og/tc_lifecycle.rb +0 -105
  66. data/test/og/tc_many_to_many.rb +0 -61
  67. data/test/og/tc_meta.rb +0 -55
  68. data/test/og/tc_validation.rb +0 -89
  69. data/test/tc_og.rb +0 -364
@@ -1,368 +0,0 @@
1
- # * Matt Bowen <matt.bowen@farweststeel.com>
2
- # * George Moschovitis <gm@navel.gr>
3
- # (c) 2004-2005 Navel, all rights reserved.
4
- # $Id: oracle.rb 17 2005-04-14 16:03:40Z gmosx $
5
-
6
- begin
7
- require 'oracle'
8
- rescue
9
- Logger.error 'Ruby-Oracle bindings are not installed!'
10
- Logger.error ex
11
- end
12
-
13
- require 'og/adapters/base'
14
-
15
- module Og
16
-
17
- # The Oracle adapter. This adapter communicates with
18
- # an Oracle rdbms. For extra documentation see
19
- # lib/og/adapter.rb
20
-
21
- class OracleAdapter < Adapter
22
-
23
- def initialize
24
- super
25
- @typemap.update(
26
- Integer => 'number',
27
- Fixnum => 'number',
28
- String => 'varchar2(512)',
29
- TrueClass => 'number',
30
- Object => 'varchar2(1024)',
31
- Array => 'varchar2(1024)',
32
- Hash => 'varchar2(1024)'
33
- )
34
- @typecast.update(TrueClass => "#\{:s: ? \"1\" : 'NULL' \}")
35
- end
36
-
37
- def self.timestamp(time = Time.now)
38
- return nil unless time
39
- return time.strftime("%Y-%m-%d %H:%M:%S")
40
- end
41
-
42
- def self.date(date)
43
- return nil unless date
44
- return "#{date.year}-#{date.month}-#{date.mday}"
45
- end
46
-
47
- def write_prop(p)
48
- if p.klass.ancestors.include?(Integer)
49
- return "#\{@#{p.symbol} || 'NULL'\}"
50
- elsif p.klass.ancestors.include?(Float)
51
- return "#\{@#{p.symbol} || 'NULL'\}"
52
- elsif p.klass.ancestors.include?(String)
53
- return "'#\{#{self.class}.escape(@#{p.symbol})\}'"
54
- elsif p.klass.ancestors.include?(Time)
55
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
56
- elsif p.klass.ancestors.include?(Date)
57
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
58
- elsif p.klass.ancestors.include?(TrueClass)
59
- return "#\{@#{p.symbol} ? \"1\" : 'NULL' \}"
60
- else
61
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
62
- end
63
- end
64
-
65
- #--
66
- # mcb:
67
- # Unlike MySQL or Postgres, Oracle database/schema creation is a big deal.
68
- # I don't know how to do it from the command line. I use Oracle's Database
69
- # Configuration Assistant utility (dbca). I takes 30min - 1hr to create
70
- # a full blown schema. So, your FIXME comments are fine. I'm thinking you
71
- # won't be able to do this via Og, but once created, Og will be able to create
72
- # tables, indexes, and other objects.
73
- #++
74
-
75
- def create_db(database, user = nil, password = nil)
76
- # FIXME: what is appropriate for oracle?
77
- # `createdb #{database} -U #{user}`
78
- super
79
- end
80
-
81
- def drop_db(database, user = nil, password = nil)
82
- # FIXME: what is appropriate for oracle?
83
- # `dropdb #{database} -U #{user}`
84
- super
85
- end
86
-
87
- def insert_code(klass, db)
88
- props = props_for_insert(klass)
89
- values = props.collect { |p| write_prop(p) }.join(',')
90
-
91
- sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values})"
92
-
93
- %{
94
- res = conn.store.exec("SELECT #{klass::DBSEQ}.nextval FROM DUAL")
95
- @oid = res.fetch[0].to_i
96
- res.close
97
- conn.exec "#{sql}"
98
- }
99
- end
100
-
101
- def new_connection(db)
102
- return OracleConnection.new(db)
103
- end
104
-
105
- def calc_field_index(klass, db)
106
- # gmosx: This is incredible!!! argh!
107
- # res = db.query "SELECT * FROM #{klass::DBTABLE} # LIMIT 1"
108
- res = db.query "SELECT * FROM (SELECT * FROM #{klass::DBTABLE}) WHERE ROWNUM <= 1"
109
- meta = db.managed_classes[klass]
110
-
111
- columns = res.getColNames
112
-
113
- for idx in (0...columns.size)
114
- # mcb: Oracle will return column names in uppercase.
115
- meta.field_index[columns[idx].downcase] = idx
116
- end
117
-
118
- ensure
119
- res.close if res
120
- end
121
-
122
- def create_table(klass, db)
123
- conn = db.get_connection
124
-
125
- fields = create_fields(klass)
126
-
127
- sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
128
-
129
- # Create table constrains.
130
-
131
- if klass.__meta and constrains = klass.__meta[:sql_constrain]
132
- sql << ", #{constrains.join(', ')}"
133
- end
134
-
135
- # mcb: Oracle driver chokes on semicolon.
136
- sql << ")"
137
-
138
- # mcb:
139
- # Oracle driver appears to have problems executing multiple SQL
140
- # statements in single exec() call. Chokes with or without semicolon
141
- # delimiter. Solution: make separate calls for each statement.
142
-
143
- begin
144
- conn.store.exec(sql).close
145
- Logger.info "Created table '#{klass::DBTABLE}'."
146
-
147
- # Create indices.
148
-
149
- if klass.__meta and indices = klass.__meta[:sql_index]
150
- for data in indices
151
- idx, options = *data
152
- idx = idx.to_s
153
- pre_sql, post_sql = options[:pre], options[:post]
154
- idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
155
- sql = " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx})"
156
- conn.store.exec(sql).close
157
- Logger.info "Created index '#{klass::DBTABLE}_#{idxname}_idx'."
158
- end
159
- end
160
- rescue Exception => ex
161
- # gmosx: any idea how to better test this?
162
- if ex.to_s =~ /ORA-00955/i
163
- Logger.debug 'Table or index already exists' if $DBG
164
- return
165
- else
166
- raise
167
- end
168
- end
169
-
170
- # Create the sequence for this table.
171
- begin
172
- conn.store.exec("CREATE SEQUENCE #{klass::DBSEQ}").close
173
- Logger.info "Created sequence '#{klass::DBSEQ}'."
174
- rescue Exception => ex
175
- # gmosx: any idea how to better test this?
176
- if ex.to_s =~ /ORA-00955/i
177
- Logger.debug "Sequence already exists" if $DBG
178
- else
179
- raise
180
- end
181
- end
182
-
183
- # Create join tables if needed. Join tables are used in
184
- # 'many_to_many' relations.
185
-
186
- if klass.__meta and joins = klass.__meta[:sql_join]
187
- for data in joins
188
- # the class to join to and some options.
189
- join_name, join_class, options = *data
190
-
191
- # gmosx: dont use DBTABLE here, perhaps the join class
192
- # is not managed yet.
193
- join_table = "#{self.class.join_table(klass, join_class, join_name)}"
194
- join_src = "#{self.class.encode(klass)}_oid"
195
- join_dst = "#{self.class.encode(join_class)}_oid"
196
- begin
197
- conn.store.exec("CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )").close
198
- conn.store.exec("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").close
199
- conn.store.exec("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").close
200
- rescue Exception => ex
201
- # gmosx: any idea how to better test this?
202
- if ex.to_s =~ /ORA-00955/i
203
- Logger.debug "Join table already exists" if $DBG
204
- else
205
- raise
206
- end
207
- end
208
- end
209
- end
210
-
211
- ensure
212
- db.put_connection
213
- end
214
-
215
- def drop_table(klass)
216
- super
217
- exec "DROP SEQUENCE #{klass::DBSEQ}"
218
- end
219
-
220
- # Generate the property for oid.
221
-
222
- #--
223
- # mcb:
224
- # Oracle doesn't have a "serial" datatype. Replace with
225
- # integer (which is probably just a synonym for NUMBER(38,0))
226
- # A sequence is created automatically by Og.
227
- #++
228
-
229
- def eval_og_oid(klass)
230
- klass.class_eval %{
231
- prop_accessor :oid, Fixnum, :sql => 'integer PRIMARY KEY'
232
- }
233
- end
234
- end
235
-
236
- # The Oracle connection.
237
-
238
- class OracleConnection < Connection
239
-
240
- # mcb:
241
- # The database connection details are tucked away in a
242
- # TNS entry (Transparent Network Substrate) which specifies host,
243
- # port, protocol, and database instance. Here is a sample TNS
244
- # entry:
245
- #
246
- # File: tns_names.ora
247
- #
248
- # KBSID =
249
- # (DESCRIPTION =
250
- # (ADDRESS_LIST =
251
- # (ADDRESS = (PROTOCOL = TCP)(HOST = keebler.farweststeel.com)(PORT = 1521))
252
- # )
253
- # (CONNECT_DATA =
254
- # (SID = KBSID)
255
- # )
256
- # )
257
-
258
- def initialize(db)
259
- super
260
- config = db.config
261
-
262
- begin
263
- # FIXME: how to pass address etc?
264
- @store = Oracle.new(config[:user], config[:password], config[:database])
265
- # gmosx: better use this???
266
- # @store = Oracle.new(config[:tns])
267
-
268
- # gmosx: does this work?
269
- @store.autocommit = true
270
- rescue Exception => ex
271
- # mcb:
272
- # Oracle will raise a ORA-01017 if username, password, or
273
- # SID aren't valid. I verified this for all three.
274
- # irb(main):002:0> conn = Oracle.new('keebler', 'dfdfd', 'kbsid')
275
- # /usr/local/lib/ruby/site_ruby/1.8/oracle.rb:27:in `logon': ORA-01017: invalid username/password; logon denied (OCIError)
276
- # gmosx:
277
- # any idea how to better test this? an integer error id?
278
- if ex.to_s =~ /ORA-01017/i
279
- Logger.info "Database '#{config[:database]}' not found!"
280
- @db.adapter.create_db(config[:database], config[:user])
281
- retry
282
- end
283
- raise
284
- end
285
- end
286
-
287
- def close
288
- @store.logoff
289
- super
290
- end
291
-
292
- def query(sql)
293
- Logger.debug sql if $DBG
294
- begin
295
- return @store.exec(sql)
296
- rescue Exception => ex
297
- handle_db_exception(ex, sql)
298
- end
299
- end
300
-
301
- def exec(sql)
302
- Logger.debug sql if $DBG
303
- begin
304
- @store.exec(sql)
305
- rescue Exception => ex
306
- handle_db_exception(ex, sql)
307
- end
308
- end
309
-
310
- def start
311
- @store.autocommit = false
312
- end
313
-
314
- def commit
315
- @store.commit
316
- ensure
317
- @store.autocommit = true
318
- end
319
-
320
- def rollback
321
- @store.rollback
322
- ensure
323
- @store.autocommit = true
324
- end
325
-
326
- def valid_res?(res)
327
- return !(res.nil?)
328
- end
329
-
330
- def read_one(res, klass)
331
- return nil unless valid_res?(res)
332
-
333
- row = res.fetch
334
- return nil unless row
335
-
336
- obj = klass.allocate
337
- obj.og_read(row)
338
-
339
- res.close
340
- return obj
341
- end
342
-
343
- def read_all(res, klass)
344
- return [] unless valid_res?(res)
345
- objects = []
346
-
347
- while row = res.fetch
348
- obj = klass.allocate
349
- obj.og_read(row)
350
- objects << obj
351
- end
352
-
353
- res.close
354
- return objects
355
- end
356
-
357
- def read_int(res, idx = 0)
358
- val = res.fetch[idx].to_i
359
- res.close
360
- return val
361
- end
362
-
363
- def get_row(res)
364
- res.fetch
365
- end
366
- end
367
-
368
- end
@@ -1,272 +0,0 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: psql.rb 17 2005-04-14 16:03:40Z gmosx $
4
-
5
- begin
6
- require 'postgres'
7
- rescue Object => ex
8
- Logger.error 'Ruby-Postgresql bindings are not installed!'
9
- Logger.error ex
10
- end
11
-
12
- require 'og/adapters/base'
13
-
14
- module Og
15
-
16
- # The PostgreSQL adapter. This adapter communicates with
17
- # an PostgreSQL rdbms. For extra documentation see
18
- # lib/og/adapter.rb
19
-
20
- class PsqlAdapter < Adapter
21
-
22
- def self.escape(str)
23
- return nil unless str
24
- return PGconn.escape(str)
25
- end
26
-
27
- def self.timestamp(time = Time.now)
28
- return nil unless time
29
- return time.strftime("%Y-%m-%d %H:%M:%S")
30
- end
31
-
32
- def self.date(date)
33
- return nil unless date
34
- return "#{date.year}-#{date.month}-#{date.mday}"
35
- end
36
-
37
- def read_prop(p, idx)
38
- if p.klass.ancestors.include?(Integer)
39
- return "res.getvalue(tuple, #{idx}).to_i()"
40
- elsif p.klass.ancestors.include?(Float)
41
- return "res.getvalue(tuple, #{idx}).to_f()"
42
- elsif p.klass.ancestors.include?(String)
43
- return "res.getvalue(tuple, #{idx})"
44
- elsif p.klass.ancestors.include?(Time)
45
- return "#{self.class}.parse_timestamp(res.getvalue(tuple, #{idx}))"
46
- elsif p.klass.ancestors.include?(Date)
47
- return "#{self.class}.parse_date(res.getvalue(tuple, #{idx}))"
48
- elsif p.klass.ancestors.include?(TrueClass)
49
- return %|('t' == res.getvalue(tuple, #{idx}))|
50
- else
51
- return "YAML::load(res.getvalue(tuple, #{idx}))"
52
- end
53
- end
54
-
55
- def create_db(database, user = nil, password = nil)
56
- # gmosx: system is used to avoid shell expansion.
57
- system 'createdb', database, '-U', user
58
- super
59
- end
60
-
61
- def drop_db(database, user = nil, password = nil)
62
- system 'dropdb', database, '-U', user
63
- super
64
- end
65
-
66
- def insert_code(klass, db)
67
- props = props_for_insert(klass)
68
- values = props.collect { |p| write_prop(p) }.join(',')
69
-
70
- sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values})"
71
-
72
- %{
73
- res = conn.store.exec("SELECT nextval('#{klass::DBSEQ}')")
74
- @oid = res.getvalue(0, 0).to_i
75
- res.clear
76
- conn.exec "#{sql}"
77
- }
78
- end
79
-
80
- def new_connection(db)
81
- return PsqlConnection.new(db)
82
- end
83
-
84
- def calc_field_index(klass, db)
85
- res = db.query "SELECT * FROM #{klass::DBTABLE} LIMIT 1"
86
- meta = db.managed_classes[klass]
87
-
88
- for field in res.fields
89
- meta.field_index[field] = res.fieldnum(field)
90
- end
91
-
92
- ensure
93
- res.clear if res
94
- end
95
-
96
- def create_table(klass, db)
97
- conn = db.get_connection
98
-
99
- fields = create_fields(klass)
100
-
101
- sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
102
-
103
- # Create table constrains.
104
-
105
- if klass.__meta and constrains = klass.__meta[:sql_constrain]
106
- sql << ", #{constrains.join(', ')}"
107
- end
108
-
109
- sql << ") WITHOUT OIDS;"
110
-
111
- # Create indices.
112
-
113
- if klass.__meta and indices = klass.__meta[:sql_index]
114
- for data in indices
115
- idx, options = *data
116
- idx = idx.to_s
117
- pre_sql, post_sql = options[:pre], options[:post]
118
- idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
119
- sql << " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx});"
120
- end
121
- end
122
-
123
- begin
124
- conn.store.exec(sql).clear
125
- Logger.info "Created table '#{klass::DBTABLE}'."
126
- rescue => ex
127
- # gmosx: any idea how to better test this?
128
- if ex.to_s =~ /relation .* already exists/i
129
- Logger.debug 'Table already exists' if $DBG
130
- return
131
- else
132
- raise
133
- end
134
- end
135
-
136
- # Create join tables if needed. Join tables are used in
137
- # 'many_to_many' relations.
138
-
139
- if klass.__meta and joins = klass.__meta[:sql_join]
140
- for data in joins
141
- # the class to join to and some options.
142
- join_name, join_class, options = *data
143
-
144
- # gmosx: dont use DBTABLE here, perhaps the join class
145
- # is not managed yet.
146
- join_table = "#{self.class.join_table(klass, join_class, join_name)}"
147
- join_src = "#{self.class.encode(klass)}_oid"
148
- join_dst = "#{self.class.encode(join_class)}_oid"
149
- begin
150
- conn.store.exec("CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )").clear
151
- conn.store.exec("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").clear
152
- conn.store.exec("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").clear
153
- rescue => ex
154
- # gmosx: any idea how to better test this?
155
- if ex.to_s =~ /relation .* already exists/i
156
- Logger.debug "Join table already exists" if $DBG
157
- else
158
- raise
159
- end
160
- end
161
- end
162
- end
163
-
164
- ensure
165
- db.put_connection
166
- end
167
-
168
- def drop_table(klass)
169
- super
170
- exec "DROP SEQUENCE #{klass::DBSEQ}"
171
- end
172
-
173
- # Generate the property for oid.
174
-
175
- def eval_og_oid(klass)
176
- klass.class_eval %{
177
- prop_accessor :oid, Fixnum, :sql => 'serial PRIMARY KEY'
178
- }
179
- end
180
-
181
- end
182
-
183
- # The PostgreSQL connection.
184
-
185
- class PsqlConnection < Connection
186
-
187
- def initialize(db)
188
- super
189
-
190
- config = db.config
191
-
192
- begin
193
- @store = PGconn.connect(
194
- config[:address],
195
- config[:port],
196
- nil,
197
- nil,
198
- config[:database],
199
- config[:user].to_s,
200
- config[:password].to_s
201
- )
202
- rescue => ex
203
- # gmosx: any idea how to better test this?
204
- if ex.to_s =~ /database .* does not exist/i
205
- Logger.info "Database '#{config[:database]}' not found!"
206
- @db.adapter.create_db(config[:database], config[:user])
207
- retry
208
- end
209
- raise
210
- end
211
- end
212
-
213
- def close
214
- @store.close
215
- super
216
- end
217
-
218
- def query(sql)
219
- Logger.debug sql if $DBG
220
- begin
221
- return @store.exec(sql)
222
- rescue => ex
223
- handle_db_exception(ex, sql)
224
- end
225
- end
226
-
227
- def exec(sql)
228
- Logger.debug sql if $DBG
229
- begin
230
- @store.exec(sql).clear
231
- rescue => ex
232
- handle_db_exception(ex, sql)
233
- end
234
- end
235
-
236
- def valid_res?(res)
237
- return !(res.nil? or 0 == res.num_tuples)
238
- end
239
-
240
- def read_one(res, klass)
241
- return nil unless valid_res?(res)
242
-
243
- obj = klass.allocate
244
- obj.og_read(res, 0)
245
-
246
- res.clear
247
- return obj
248
- end
249
-
250
- def read_all(res, klass)
251
- return [] unless valid_res?(res)
252
- objects = []
253
-
254
- for tuple in (0...res.num_tuples)
255
- obj = klass.allocate
256
- obj.og_read(res, tuple)
257
- objects << obj
258
- end
259
-
260
- res.clear
261
- return objects
262
- end
263
-
264
- def read_int(res, idx = 0)
265
- val = res.getvalue(0, idx).to_i
266
- res.clear
267
- return val
268
- end
269
-
270
- end
271
-
272
- end