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.
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