jdbc-helper 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,31 +12,31 @@ module JDBCHelper
12
12
  #
13
13
  # # Counting the records in the table
14
14
  # table.count
15
- # table.count(:a => 10)
16
- # table.where(:a => 10).count
15
+ # table.count(a: 10)
16
+ # table.where(a: 10).count
17
17
  #
18
18
  # table.empty?
19
- # table.where(:a => 10).empty?
19
+ # table.where(a: 10).empty?
20
20
  #
21
21
  # # Selects the table by combining select, where, and order methods
22
- # table.select('a apple', :b).where(:c => (1..10)).order('b desc', 'a asc') do |row|
22
+ # table.select('a apple', :b).where(c: (1..10)).order('b desc', 'a asc') do |row|
23
23
  # puts row.apple
24
24
  # end
25
25
  #
26
26
  # # Updates with conditions
27
- # table.update(:a => 'hello', :b => JDBCHelper::SQL('now()'), :where => { :c => 3 })
27
+ # table.update(a: 'hello', b: { sql: 'now()' }, where: { c: 3 })
28
28
  # # Or equivalently,
29
- # table.where(:c => 3).update(:a => 'hello', :b => JDBCHelper::SQL('now()'))
29
+ # table.where(c: 3).update(a: 'hello', b: { sql: 'now()' })
30
30
  #
31
31
  # # Insert into the table
32
- # table.insert(:a => 10, :b => 20, :c => JDBCHelper::SQL('10 + 20'))
33
- # table.insert_ignore(:a => 10, :b => 20, :c => 30)
34
- # table.replace(:a => 10, :b => 20, :c => 30)
32
+ # table.insert(a: 10, b: 20, c: { sql: '10 + 20' })
33
+ # table.insert_ignore(a: 10, b: 20, c: 30)
34
+ # table.replace(a: 10, b: 20, c: 30)
35
35
  #
36
36
  # # Delete with conditions
37
- # table.delete(:c => 3)
37
+ # table.delete(c: 3)
38
38
  # # Or equivalently,
39
- # table.where(:c => 3).delete
39
+ # table.where(c: 3).delete
40
40
  #
41
41
  # # Truncate or drop table (Cannot be undone)
42
42
  # table.truncate_table!
@@ -50,9 +50,9 @@ class TableWrapper < ObjectWrapper
50
50
  # @param [List of Hash/String] where Filter conditions
51
51
  # @return [Fixnum] Count of the records.
52
52
  def count *where
53
- sql, binds = JDBCHelper::SQLPrepared.count(name, @query_where + where)
53
+ sql, *binds = SQLHelper.count :table => name, :where => @query_where + where, :prepared => true
54
54
  pstmt = prepare :count, sql
55
- pstmt.query(*binds)[0][0].to_i
55
+ pstmt.query(*binds).to_a[0][0].to_i
56
56
  end
57
57
 
58
58
  # Sees if the table is empty
@@ -66,7 +66,9 @@ class TableWrapper < ObjectWrapper
66
66
  # @param [Hash] data_hash Column values in Hash
67
67
  # @return [Fixnum] Number of affected records
68
68
  def insert data_hash = {}
69
- sql, binds = JDBCHelper::SQLPrepared.insert(name, @query_default.merge(data_hash))
69
+ sql, *binds = SQLHelper.insert :table => name,
70
+ :data => @query_default.merge(data_hash),
71
+ :prepared => true
70
72
  pstmt = prepare :insert, sql
71
73
  pstmt.send @update_method, *binds
72
74
  end
@@ -77,7 +79,9 @@ class TableWrapper < ObjectWrapper
77
79
  # @param [Hash] data_hash Column values in Hash
78
80
  # @return [Fixnum] Number of affected records
79
81
  def insert_ignore data_hash = {}
80
- sql, binds = JDBCHelper::SQLPrepared.insert_ignore(name, @query_default.merge(data_hash))
82
+ sql, *binds = SQLHelper.insert_ignore :table => name,
83
+ :data => @query_default.merge(data_hash),
84
+ :prepared => true
81
85
  pstmt = prepare :insert, sql
82
86
  pstmt.set_fetch_size @fetch_size if @fetch_size
83
87
  pstmt.send @update_method, *binds
@@ -88,7 +92,9 @@ class TableWrapper < ObjectWrapper
88
92
  # @param [Hash] data_hash Column values in Hash
89
93
  # @return [Fixnum] Number of affected records
90
94
  def replace data_hash = {}
91
- sql, binds = JDBCHelper::SQLPrepared.replace(name, @query_default.merge(data_hash))
95
+ sql, *binds = SQLHelper.replace :table => name,
96
+ :data => @query_default.merge(data_hash),
97
+ :prepared => true
92
98
  pstmt = prepare :insert, sql
93
99
  pstmt.send @update_method, *binds
94
100
  end
@@ -101,9 +107,11 @@ class TableWrapper < ObjectWrapper
101
107
  def update data_hash_with_where = {}
102
108
  where_ext = data_hash_with_where.delete(:where)
103
109
  where_ext = [where_ext] unless where_ext.is_a? Array
104
- sql, binds = JDBCHelper::SQLPrepared.update(name,
105
- @query_default.merge(data_hash_with_where),
106
- @query_where + where_ext.compact)
110
+ sql, *binds = SQLHelper.update(
111
+ :prepared => true,
112
+ :table => name,
113
+ :data => @query_default.merge(data_hash_with_where),
114
+ :where => @query_where + where_ext.compact)
107
115
  pstmt = prepare :update, sql
108
116
  pstmt.send @update_method, *binds
109
117
  end
@@ -112,7 +120,7 @@ class TableWrapper < ObjectWrapper
112
120
  # @param [List of Hash/String] where Delete filters
113
121
  # @return [Fixnum] Number of affected records
114
122
  def delete *where
115
- sql, binds = JDBCHelper::SQLPrepared.delete(name, @query_where + where)
123
+ sql, *binds = SQLHelper.delete(:table => name, :where => @query_where + where, :prepared => true)
116
124
  pstmt = prepare :delete, sql
117
125
  pstmt.send @update_method, *binds
118
126
  end
@@ -121,7 +129,7 @@ class TableWrapper < ObjectWrapper
121
129
  # @note This operation cannot be undone
122
130
  # @return [JDBCHelper::TableWrapper] Self.
123
131
  def truncate!
124
- @connection.update(JDBCHelper::SQL.check "truncate table #{name}")
132
+ @connection.update("truncate table #{name}")
125
133
  self
126
134
  end
127
135
  alias truncate_table! truncate!
@@ -130,7 +138,7 @@ class TableWrapper < ObjectWrapper
130
138
  # @note This operation cannot be undone
131
139
  # @return [JDBCHelper::TableWrapper] Self.
132
140
  def drop!
133
- @connection.update(JDBCHelper::SQL.check "drop table #{name}")
141
+ @connection.update("drop table #{name}")
134
142
  self
135
143
  end
136
144
  alias drop_table! drop!
@@ -149,6 +157,7 @@ class TableWrapper < ObjectWrapper
149
157
  obj.instance_variable_set :@query_select, fields unless fields.empty?
150
158
  ret obj, &block
151
159
  end
160
+ alias project select
152
161
 
153
162
  # Returns a new TableWrapper object which can be used to execute a select
154
163
  # statement for the table with the specified filter conditions.
@@ -164,6 +173,16 @@ class TableWrapper < ObjectWrapper
164
173
  ret obj, &block
165
174
  end
166
175
 
176
+ # @overload limit(offset, limit)
177
+ # @overload limit(limit)
178
+ # @return [JDBCHelper::TableWrapper]
179
+ # @since 0.8.0
180
+ def limit *args, &block
181
+ obj = self.dup
182
+ obj.instance_variable_set :@query_limit, args
183
+ ret obj, &block
184
+ end
185
+
167
186
  # Returns a new TableWrapper object which can be used to execute a select
168
187
  # statement for the table with the given sorting criteria.
169
188
  # If a block is given, executes the select statement and yields each row to the block.
@@ -203,14 +222,16 @@ class TableWrapper < ObjectWrapper
203
222
 
204
223
  # Executes a select SQL for the table and returns an Enumerable object,
205
224
  # or yields each row if block is given.
206
- # @return [JDBCHelper::Connection::ResultSetEnumerator]
225
+ # @return [JDBCHelper::Connection::ResultSet]
207
226
  # @since 0.4.0
208
227
  def each &block
209
- sql, binds = JDBCHelper::SQLPrepared.select(
210
- name,
211
- :select => @query_select,
212
- :where => @query_where,
213
- :order => @query_order)
228
+ sql, *binds = SQLHelper.select(
229
+ :prepared => true,
230
+ :table => name,
231
+ :project => @query_select,
232
+ :where => @query_where,
233
+ :order => @query_order,
234
+ :limit => @query_limit)
214
235
  pstmt = prepare :select, sql
215
236
  pstmt.enumerate(*binds, &block)
216
237
  end
@@ -276,25 +297,28 @@ class TableWrapper < ObjectWrapper
276
297
  # @return [String] Select SQL
277
298
  # @since 0.4.0
278
299
  def sql
279
- JDBCHelper::SQL.select(
280
- name,
281
- :select => @query_select,
282
- :where => @query_where,
283
- :order => @query_order)
300
+ SQLHelper.select(
301
+ :prepared => false,
302
+ :table => name,
303
+ :project => @query_select,
304
+ :where => @query_where,
305
+ :limit => @query_limit,
306
+ :order => @query_order)
284
307
  end
285
308
 
286
309
  def initialize connection, table_name
287
310
  super connection, table_name
288
311
  @update_method = :update
289
312
  @query_default = {}
290
- @query_where = []
291
- @query_order = nil
292
- @query_select = nil
313
+ @query_where = []
314
+ @query_order = nil
315
+ @query_limit = nil
316
+ @query_select = nil
293
317
  @pstmts = {
294
318
  :select => {},
295
319
  :insert => {},
296
320
  :delete => {},
297
- :count => {},
321
+ :count => {},
298
322
  :update => {}
299
323
  }
300
324
  @fetch_size = nil
@@ -319,13 +343,14 @@ class TableWrapper < ObjectWrapper
319
343
 
320
344
  def inspect
321
345
  {
322
- :conn => @connection,
323
- :name => name,
324
- :sqls => @pstmts.values.map(&:keys).flatten,
325
- :where => @query_where,
346
+ :conn => @connection,
347
+ :name => name,
348
+ :sqls => @pstmts.values.map(&:keys).flatten,
349
+ :where => @query_where,
326
350
  :default => @query_default,
327
- :order => @query_order,
328
- :batch? => batch?
351
+ :order => @query_order,
352
+ :limit => @query_limit,
353
+ :batch? => batch?
329
354
  }.inspect
330
355
  end
331
356
 
data/lib/jdbc-helper.rb CHANGED
@@ -12,4 +12,5 @@ require 'jdbc-helper/sql'
12
12
  require 'jdbc-helper/constants'
13
13
  require 'jdbc-helper/connection'
14
14
  require 'jdbc-helper/connector'
15
+ require 'sql_helper'
15
16
 
data/test/helper.rb CHANGED
@@ -84,7 +84,7 @@ module JDBCHelperTestHelper
84
84
  config.each do | db, conn_info |
85
85
  # Just for quick and dirty testing
86
86
  @type = case conn_info[:driver]
87
- when /mysql/i
87
+ when /mysql/i, /maria/i
88
88
  :mysql
89
89
  when /oracle/i
90
90
  :oracle
@@ -187,9 +187,10 @@ class TestConnection < Test::Unit::TestCase
187
187
 
188
188
  def test_query_enumerate
189
189
  each_connection do | conn |
190
- # Query without a block => Array
190
+ # Query without a block => ResultSet
191
191
  query_result = conn.query get_one_two
192
- assert query_result.is_a? Array
192
+ assert query_result.is_a? JDBCHelper::Connection::ResultSet
193
+ query_result = query_result.to_a
193
194
  assert_equal 2, query_result.length
194
195
  check_one_two(query_result.first)
195
196
  assert_equal query_result.first, query_result.last
@@ -203,13 +204,64 @@ class TestConnection < Test::Unit::TestCase
203
204
  assert_equal 2, count
204
205
 
205
206
  # Enumerate
206
- enum = conn.enumerate(get_one_two)
207
+ enum = conn.query(get_one_two)
207
208
  assert enum.is_a? Enumerable
208
209
  assert enum.closed? == false
209
210
  a = enum.to_a
210
211
  assert_equal 2, a.length
211
212
  check_one_two a.first
212
213
  assert enum.closed? == true
214
+
215
+ # Enumerator chain
216
+ cnt = 0
217
+ enum = conn.query(get_one_two)
218
+ assert_equal false, enum.closed?
219
+ enum.each.each.each.each_slice(1) do |slice|
220
+ assert_equal Array, slice.class
221
+ assert_equal 1, slice.length
222
+ cnt += 1
223
+ assert_equal cnt == 2, enum.closed?
224
+ end
225
+ assert_equal true, enum.closed?
226
+ assert_equal 2, cnt
227
+
228
+ # Enumerator chain 2
229
+ cnt = 0
230
+ enum = conn.query(get_one_two)
231
+ assert_equal false, enum.closed?
232
+ enum.each.each.each.with_index.each_slice(2).each do |slice|
233
+ assert_equal Array, slice.class
234
+ assert_equal 2, slice.length
235
+ assert_equal Array, slice[0].class
236
+ assert_equal 2, slice[0].length
237
+ assert_equal cnt, slice[0][1]
238
+ assert_equal cnt + 1, slice[1][1]
239
+ cnt += 2
240
+ assert_equal cnt == 2, enum.closed?
241
+ end
242
+ assert_equal true, enum.closed?
243
+ assert_equal 2, cnt
244
+ assert_equal 0, enum.to_a.length
245
+
246
+ enum = conn.query('
247
+ select 1 a from dual union all
248
+ select 2 a from dual union all
249
+ select 3 a from dual')
250
+
251
+ row = enum.take(1).first
252
+ assert_equal 0, row.rownum
253
+ assert_equal false, enum.closed?
254
+
255
+ row = enum.take(1).first
256
+ assert_equal 1, row.rownum
257
+ assert_equal false, enum.closed?
258
+
259
+ row = enum.take(1).first
260
+ assert_equal 2, row.rownum
261
+ assert_equal true, enum.closed?
262
+
263
+ assert_equal [], enum.take(1)
264
+ assert_equal true, enum.closed?
213
265
  end
214
266
  end
215
267
 
@@ -217,17 +269,18 @@ class TestConnection < Test::Unit::TestCase
217
269
  each_connection do |conn|
218
270
  # On error, Statement object must be returned to the StatementPool
219
271
  (JDBCHelper::Constants::MAX_STATEMENT_NESTING_LEVEL * 2).times do |i|
220
- conn.enumerate('xxx') rescue nil
272
+ conn.query('xxx') rescue nil
221
273
  end
222
- assert_equal 'OK', conn.query("select 'OK' from dual")[0][0]
274
+ assert_equal 'OK', conn.query("select 'OK' from dual").to_a[0][0]
223
275
  end
224
276
  end
225
277
 
226
278
  def test_deep_nesting
227
279
  nest = lambda { |str, lev|
228
280
  if lev > 0
229
- "conn.query('select 1 from dual') do |r#{lev}|
281
+ "conn.query('select 1 a from dual union all select 2 a from dual') do |r#{lev}|
230
282
  #{nest.call str, lev - 1}
283
+ break
231
284
  end"
232
285
  else
233
286
  str
@@ -323,7 +376,8 @@ class TestConnection < Test::Unit::TestCase
323
376
 
324
377
  # Query without a block => Array
325
378
  query_result = sel.query
326
- assert query_result.is_a? Array
379
+ assert query_result.is_a? JDBCHelper::Connection::ResultSet
380
+ query_result = query_result.to_a
327
381
  assert_equal 2, query_result.length
328
382
  check_one_two(query_result.first)
329
383
 
@@ -336,7 +390,7 @@ class TestConnection < Test::Unit::TestCase
336
390
  assert_equal 2, count
337
391
 
338
392
  # Enumerate
339
- enum = sel.enumerate
393
+ enum = sel.query
340
394
  assert enum.is_a? Enumerable
341
395
  assert enum.closed? == false
342
396
  a = enum.to_a
@@ -475,13 +529,13 @@ class TestConnection < Test::Unit::TestCase
475
529
  if @type == :mysql
476
530
  conn.prepare("insert into #{TEST_TABLE} (a, b, c) values (?, ?, ?)").update(ts, d, t)
477
531
  # MySQL doesn't have subsecond precision
478
- assert [lt, lt / 1000 * 1000].include?(conn.query("select a from #{TEST_TABLE}")[0][0].getTime)
532
+ assert [lt, (lt * 0.001).round * 1000].include?(conn.query("select a from #{TEST_TABLE}").to_a[0][0].getTime)
479
533
  # The JDBC spec states that java.sql.Dates have _no_ time component
480
534
  # http://bugs.mysql.com/bug.php?id=2876
481
- assert_equal d.getTime, conn.query("select b from #{TEST_TABLE}")[0][0].getTime
535
+ assert_equal d.getTime, conn.query("select b from #{TEST_TABLE}").to_a[0][0].getTime
482
536
 
483
537
  # http://stackoverflow.com/questions/907170/java-getminutes-and-gethours
484
- t2 = conn.query("select c from #{TEST_TABLE}")[0][0]
538
+ t2 = conn.query("select c from #{TEST_TABLE}").to_a[0][0]
485
539
  cal = java.util.Calendar.getInstance
486
540
  cal.setTime(t)
487
541
  cal2 = java.util.Calendar.getInstance
@@ -498,9 +552,10 @@ class TestConnection < Test::Unit::TestCase
498
552
  reset_test_table_ts conn
499
553
  ts = Time.now
500
554
  conn.prepare("insert into #{TEST_TABLE} (a) values (?)").update(ts)
501
- got = conn.query("select a from #{TEST_TABLE}")[0][0]
555
+ got = conn.query("select a from #{TEST_TABLE}").to_a[0][0]
502
556
  arr = [
503
557
  ts.to_i * 1000,
558
+ (ts.to_f.round) * 1000, # MySQL
504
559
  (ts.to_f * 1000).to_i,
505
560
  # SQL Server seems to round up the millisecond precision
506
561
  (ts.to_f * 1000).to_i / 10 * 10
@@ -611,7 +666,7 @@ class TestConnection < Test::Unit::TestCase
611
666
  each_connection do | conn |
612
667
  reset_test_table conn
613
668
 
614
- rse_class = JDBCHelper::Connection::ResultSetEnumerator
669
+ rse_class = JDBCHelper::Connection::ResultSet
615
670
 
616
671
  # Connection#execute
617
672
  assert_equal 1, conn.execute("insert into #{TEST_TABLE} values (0, 'A')")
@@ -659,8 +714,8 @@ class TestConnection < Test::Unit::TestCase
659
714
 
660
715
  assert_equal 20, 20.times.select {
661
716
  conn.execute(q).close
662
- conn.enumerate(q).close
663
- conn.query q
717
+ conn.query(q).close
718
+ conn.query(q).to_a
664
719
  conn.update u
665
720
 
666
721
  conn.execute(q).count == 1
@@ -119,11 +119,10 @@ class TestObjectWrapper < Test::Unit::TestCase
119
119
  end
120
120
  end
121
121
 
122
-
123
122
  def insert_params
124
123
  {
125
124
  :alpha => 100,
126
- :beta => JDBCHelper::SQL('0.1 + 0.2'),
125
+ :beta => { :sql => '0.1 + 0.2' },
127
126
  :num_f => 1234567890.12345, # 16 digits
128
127
  :num_fstr => BigDecimal.new("12345678901234567890.12345"),
129
128
  :num_int => 123456789,
@@ -272,7 +271,7 @@ class TestObjectWrapper < Test::Unit::TestCase
272
271
  params = {
273
272
  :id => 1,
274
273
  :alpha => 100,
275
- :beta => JDBCHelper::SQL('0.1 + 0.2'),
274
+ :beta => { :sql => '0.1 + 0.2' },
276
275
  :gamma => 'hello world' }
277
276
 
278
277
  100.times do
@@ -291,7 +290,7 @@ class TestObjectWrapper < Test::Unit::TestCase
291
290
  table = conn.table(@table_name)
292
291
  params = {
293
292
  :id => 1,
294
- :beta => JDBCHelper::SQL('0.1 + 0.2'),
293
+ :beta => { :sql => '0.1 + 0.2' },
295
294
  :gamma => 'hello world' }
296
295
 
297
296
  100.times do |i|
@@ -355,7 +354,7 @@ class TestObjectWrapper < Test::Unit::TestCase
355
354
  # SQL Server seems to have a bug in getBinaryStream (FIXME)
356
355
  # http://www.herongyang.com/JDBC/SQL-Server-BLOB-getBinaryStream.html
357
356
  assert_equal @blob, get_blob_data(blob) unless @type == :sqlserver
358
- assert_equal Float, row.num_f.class
357
+ assert_equal BigDecimal, row.num_f.class
359
358
  assert_equal BigDecimal, row.num_fstr.class
360
359
  assert_equal Fixnum, row.num_int.class
361
360
  assert_equal Fixnum, row.num_long.class
@@ -382,13 +381,13 @@ class TestObjectWrapper < Test::Unit::TestCase
382
381
  assert_equal 10, cnt
383
382
 
384
383
  assert_equal "select a, b, c cc from tmp_jdbc_helper " +
385
- "where id >= 11 and id <= 20 order by id desc, name asc",
384
+ "where id between 11 and 20 order by id desc, name asc",
386
385
  table.where(:id => 11..20).
387
386
  select(:a, :b, 'c cc').
388
387
  order('id desc', 'name asc').sql
389
388
 
390
389
  assert_equal "select a, b, c cc from tmp_jdbc_helper " +
391
- "where (id != 15) and id >= 11 and id <= 20 order by id desc, name asc",
390
+ "where (id != 15) and id between 11 and 20 order by id desc, name asc",
392
391
  table.where("id != 15", :id => 11..20).
393
392
  select(:a, :b, 'c cc').
394
393
  order('id desc', 'name asc').sql
@@ -499,7 +498,7 @@ class TestObjectWrapper < Test::Unit::TestCase
499
498
  table.clear_batch
500
499
  assert_equal 50, table.count
501
500
 
502
- table.batch.update(:alpha => JDBCHelper::SQL('alpha * 2'))
501
+ table.batch.update(:alpha => { :sql => 'alpha * 2' })
503
502
  assert_equal 100, table.select(:alpha).to_a.first.alpha.to_i
504
503
 
505
504
  # Independent update inbetween
@@ -517,7 +516,7 @@ class TestObjectWrapper < Test::Unit::TestCase
517
516
  assert_equal 200, table.select(:alpha).to_a.first.alpha.to_i
518
517
 
519
518
  # Order of execution
520
- table.batch.update(:alpha => JDBCHelper::SQL('alpha * 4'))
519
+ table.batch.update(:alpha => { :sql => 'alpha * 4' })
521
520
  insert table.batch, 50, 2000
522
521
  table.batch.delete
523
522
  ret = table.execute_batch :delete, :insert, :update
@@ -733,5 +732,19 @@ class TestObjectWrapper < Test::Unit::TestCase
733
732
  conn.table(@table_name).fetch_size("No").count
734
733
  end
735
734
  end
735
+
736
+ def test_limit
737
+ each_connection do |conn|
738
+ next unless [:mysql].include?(@type)
739
+
740
+ create_table conn
741
+ t = conn.table(@table_name)
742
+ insert t, 100
743
+ assert_equal 100, t.to_a.count
744
+
745
+ assert_equal 30, t.limit(30).to_a.count
746
+ assert_equal 100, t.limit(30).count
747
+ end
748
+ end
736
749
  end
737
750