sequel_core 1.5.1 → 2.0.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 (68) hide show
  1. data/CHANGELOG +116 -0
  2. data/COPYING +19 -19
  3. data/README +83 -32
  4. data/Rakefile +9 -20
  5. data/bin/sequel +43 -112
  6. data/doc/cheat_sheet.rdoc +225 -0
  7. data/doc/dataset_filtering.rdoc +257 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
  9. data/lib/sequel_core/adapters/ado.rb +3 -1
  10. data/lib/sequel_core/adapters/db2.rb +4 -2
  11. data/lib/sequel_core/adapters/dbi.rb +127 -113
  12. data/lib/sequel_core/adapters/informix.rb +4 -2
  13. data/lib/sequel_core/adapters/jdbc.rb +5 -3
  14. data/lib/sequel_core/adapters/mysql.rb +112 -46
  15. data/lib/sequel_core/adapters/odbc.rb +5 -7
  16. data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
  17. data/lib/sequel_core/adapters/openbase.rb +3 -1
  18. data/lib/sequel_core/adapters/oracle.rb +11 -9
  19. data/lib/sequel_core/adapters/postgres.rb +261 -262
  20. data/lib/sequel_core/adapters/sqlite.rb +72 -22
  21. data/lib/sequel_core/connection_pool.rb +140 -73
  22. data/lib/sequel_core/core_ext.rb +201 -66
  23. data/lib/sequel_core/core_sql.rb +123 -153
  24. data/lib/sequel_core/database/schema.rb +156 -0
  25. data/lib/sequel_core/database.rb +321 -338
  26. data/lib/sequel_core/dataset/callback.rb +11 -12
  27. data/lib/sequel_core/dataset/convenience.rb +213 -240
  28. data/lib/sequel_core/dataset/pagination.rb +58 -43
  29. data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
  30. data/lib/sequel_core/dataset/query.rb +41 -0
  31. data/lib/sequel_core/dataset/schema.rb +15 -0
  32. data/lib/sequel_core/dataset/sequelizer.rb +41 -373
  33. data/lib/sequel_core/dataset/sql.rb +741 -632
  34. data/lib/sequel_core/dataset.rb +183 -168
  35. data/lib/sequel_core/deprecated.rb +1 -169
  36. data/lib/sequel_core/exceptions.rb +24 -19
  37. data/lib/sequel_core/migration.rb +44 -52
  38. data/lib/sequel_core/object_graph.rb +43 -42
  39. data/lib/sequel_core/pretty_table.rb +71 -76
  40. data/lib/sequel_core/schema/generator.rb +163 -105
  41. data/lib/sequel_core/schema/sql.rb +250 -93
  42. data/lib/sequel_core/schema.rb +2 -8
  43. data/lib/sequel_core/sql.rb +394 -0
  44. data/lib/sequel_core/worker.rb +37 -27
  45. data/lib/sequel_core.rb +99 -45
  46. data/spec/adapters/informix_spec.rb +0 -1
  47. data/spec/adapters/mysql_spec.rb +177 -124
  48. data/spec/adapters/oracle_spec.rb +0 -1
  49. data/spec/adapters/postgres_spec.rb +98 -58
  50. data/spec/adapters/sqlite_spec.rb +45 -4
  51. data/spec/blockless_filters_spec.rb +269 -0
  52. data/spec/connection_pool_spec.rb +21 -18
  53. data/spec/core_ext_spec.rb +169 -19
  54. data/spec/core_sql_spec.rb +56 -49
  55. data/spec/database_spec.rb +78 -17
  56. data/spec/dataset_spec.rb +300 -428
  57. data/spec/migration_spec.rb +1 -1
  58. data/spec/object_graph_spec.rb +5 -11
  59. data/spec/rcov.opts +1 -1
  60. data/spec/schema_generator_spec.rb +16 -4
  61. data/spec/schema_spec.rb +89 -10
  62. data/spec/sequelizer_spec.rb +56 -56
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_config.rb +7 -0
  65. data/spec/spec_config.rb.example +5 -5
  66. data/spec/spec_helper.rb +6 -0
  67. data/spec/worker_spec.rb +1 -1
  68. metadata +78 -63
@@ -1,5 +1,28 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
 
3
+ context "Array#all_two_pairs?" do
4
+ specify "should return false if empty" do
5
+ [].all_two_pairs?.should == false
6
+ end
7
+
8
+ specify "should return false if any of the elements is not an array" do
9
+ [1].all_two_pairs?.should == false
10
+ [[1,2],1].all_two_pairs?.should == false
11
+ end
12
+
13
+ specify "should return false if any of the elements has a length other than two" do
14
+ [[1,2],[]].all_two_pairs?.should == false
15
+ [[1,2],[1]].all_two_pairs?.should == false
16
+ [[1,2],[1,2,3]].all_two_pairs?.should == false
17
+ end
18
+
19
+ specify "should return true if all of the elements are arrays with a length of two" do
20
+ [[1,2]].all_two_pairs?.should == true
21
+ [[1,2],[1,2]].all_two_pairs?.should == true
22
+ [[1,2],[1,2],[1,2]].all_two_pairs?.should == true
23
+ end
24
+ end
25
+
3
26
  context "Array#to_sql" do
4
27
  specify "should concatenate multiple lines into a single string" do
5
28
  "SELECT * \r\nFROM items\r\n WHERE a = 1".split.to_sql. \
@@ -51,25 +74,14 @@ context "String#lit" do
51
74
  end
52
75
 
53
76
  specify "should inhibit string literalization" do
54
- db = Sequel::Database.new
55
- ds = db[:t]
56
-
57
- ds.update_sql(:stamp => "NOW()".lit).should == \
77
+ Sequel::Database.new[:t].update_sql(:stamp => "NOW()".expr).should == \
58
78
  "UPDATE t SET stamp = NOW()"
59
79
  end
60
- end
61
80
 
62
- context "String#expr" do
63
- specify "should return an LiteralString object" do
81
+ specify "should be aliased as expr" do
64
82
  'xyz'.expr.should be_a_kind_of(Sequel::LiteralString)
65
83
  'xyz'.expr.to_s.should == 'xyz'
66
- end
67
-
68
- specify "should inhibit string literalization" do
69
- db = Sequel::Database.new
70
- ds = db[:t]
71
-
72
- ds.update_sql(:stamp => "NOW()".expr).should == \
84
+ Sequel::Database.new[:t].update_sql(:stamp => "NOW()".expr).should == \
73
85
  "UPDATE t SET stamp = NOW()"
74
86
  end
75
87
  end
@@ -149,20 +161,21 @@ end
149
161
  context "Column references" do
150
162
  setup do
151
163
  @c = Class.new(Sequel::Dataset) do
152
- def quote_column_ref(c); "`#{c}`"; end
164
+ def quoted_identifier(c); "`#{c}`"; end
153
165
  end
154
166
  @ds = @c.new(nil)
167
+ @ds.quote_identifiers = true
155
168
  end
156
169
 
157
170
  specify "should be quoted properly" do
158
171
  @ds.literal(:xyz).should == "`xyz`"
159
- @ds.literal(:xyz__abc).should == "xyz.`abc`"
172
+ @ds.literal(:xyz__abc).should == "`xyz`.`abc`"
160
173
 
161
174
  @ds.literal(:xyz.as(:x)).should == "`xyz` AS `x`"
162
- @ds.literal(:xyz__abc.as(:x)).should == "xyz.`abc` AS `x`"
175
+ @ds.literal(:xyz__abc.as(:x)).should == "`xyz`.`abc` AS `x`"
163
176
 
164
177
  @ds.literal(:xyz___x).should == "`xyz` AS `x`"
165
- @ds.literal(:xyz__abc___x).should == "xyz.`abc` AS `x`"
178
+ @ds.literal(:xyz__abc___x).should == "`xyz`.`abc` AS `x`"
166
179
  end
167
180
 
168
181
  specify "should be quoted properly in SQL functions" do
@@ -178,7 +191,7 @@ context "Column references" do
178
191
 
179
192
  specify "should be quoted properly in a cast function" do
180
193
  @ds.literal(:x.cast_as(:integer)).should == "cast(`x` AS integer)"
181
- @ds.literal(:x__y.cast_as(:varchar[20])).should == "cast(x.`y` AS varchar(20))"
194
+ @ds.literal(:x__y.cast_as(:varchar[20])).should == "cast(`x`.`y` AS varchar(20))"
182
195
  end
183
196
  end
184
197
 
@@ -187,10 +200,15 @@ context "Symbol#*" do
187
200
  @ds = Sequel::Dataset.new(nil)
188
201
  end
189
202
 
190
- specify "should format a qualified wildcard" do
203
+ specify "should format a qualified wildcard if no argument" do
191
204
  :xyz.*.to_s(@ds).should == 'xyz.*'
192
205
  :abc.*.to_s(@ds).should == 'abc.*'
193
206
  end
207
+
208
+ specify "should format a filter expression if an argument" do
209
+ :xyz.*(3).to_s(@ds).should == '(xyz * 3)'
210
+ :abc.*(5).to_s(@ds).should == '(abc * 5)'
211
+ end
194
212
  end
195
213
 
196
214
  context "Symbol#to_column_ref" do
@@ -219,38 +237,21 @@ context "Symbol#to_column_ref" do
219
237
  :ABC.to_column_ref(@ds).should == 'ABC'
220
238
  :Zvashtoy__aBcD.to_column_ref(@ds).should == 'Zvashtoy.aBcD'
221
239
  end
240
+
241
+ specify "should support spaces inside column names" do
242
+ @ds.quote_identifiers = true
243
+ :"AB C".to_column_ref(@ds).should == '"AB C"'
244
+ :"Zvas htoy__aB cD".to_column_ref(@ds).should == '"Zvas htoy"."aB cD"'
245
+ :"aB cD___XX XX".to_column_ref(@ds).should == '"aB cD" AS "XX XX"'
246
+ :"Zva shtoy__aB cD___XX XX".to_column_ref(@ds).should == '"Zva shtoy"."aB cD" AS "XX XX"'
247
+ end
222
248
  end
223
249
 
224
- ### DEPRECATED
225
250
  context "Symbol" do
226
251
  setup do
227
252
  @ds = Sequel::Dataset.new(nil)
228
253
  end
229
254
 
230
- specify "should support MIN for specifying min function" do
231
- :abc__def.MIN.to_s(@ds).should == 'min(abc.def)'
232
- end
233
-
234
- specify "should support MAX for specifying max function" do
235
- :abc__def.MAX.to_s(@ds).should == 'max(abc.def)'
236
- end
237
-
238
- specify "should support SUM for specifying sum function" do
239
- :abc__def.SUM.to_s(@ds).should == 'sum(abc.def)'
240
- end
241
-
242
- specify "should support AVG for specifying avg function" do
243
- :abc__def.AVG.to_s(@ds).should == 'avg(abc.def)'
244
- end
245
-
246
- specify "should support COUNT for specifying count function" do
247
- :abc__def.COUNT.to_s(@ds).should == 'count(abc.def)'
248
- end
249
-
250
- specify "should support any other function using upper case letters" do
251
- :abc__def.DADA.to_s(@ds).should == 'dada(abc.def)'
252
- end
253
-
254
255
  specify "should support upper case outer functions" do
255
256
  :COUNT['1'].to_s(@ds).should == "COUNT('1')"
256
257
  end
@@ -265,10 +266,6 @@ context "Symbol" do
265
266
  :abc.cast_as(:integer).to_s(@ds).should == "cast(abc AS integer)"
266
267
  end
267
268
 
268
- specify "should raise NoMethodError for non-uppercase invalid methods" do
269
- proc {:abc.dfaxs}.should raise_error(NoMethodError)
270
- end
271
-
272
269
  specify "should support subscript access using | operator" do
273
270
  (:abc|1).to_s(@ds).should == 'abc[1]'
274
271
  (:abc|[1]).to_s(@ds).should == 'abc[1]'
@@ -298,6 +295,16 @@ context "String#to_date" do
298
295
  end
299
296
  end
300
297
 
298
+ context "String#to_datetime" do
299
+ specify "should convert the string into a DateTime object" do
300
+ "2007-07-11 10:11:12a".to_datetime.should == DateTime.parse("2007-07-11 10:11:12a")
301
+ end
302
+
303
+ specify "should raise Error::InvalidValue for an invalid date" do
304
+ proc {'0000-00-00'.to_datetime}.should raise_error(Sequel::Error::InvalidValue)
305
+ end
306
+ end
307
+
301
308
  context "Sequel::SQL::Function#==" do
302
309
  specify "should be true for functions with the same name and arguments, false otherwise" do
303
310
  a = :date[:t]
@@ -9,8 +9,17 @@ context "A new Database" do
9
9
  @db.opts.should == {1 => 2, :logger => 3}
10
10
  end
11
11
 
12
- specify "should set the logger from opts[:logger]" do
12
+ specify "should set the logger from opts[:logger] and opts[:loggers]" do
13
13
  @db.logger.should == 3
14
+ @db.loggers.should == [3]
15
+ Sequel::Database.new(1 => 2, :loggers => 3).logger.should == 3
16
+ Sequel::Database.new(1 => 2, :loggers => 3).loggers.should == [3]
17
+ Sequel::Database.new(1 => 2, :loggers => [3]).logger.should == 3
18
+ Sequel::Database.new(1 => 2, :loggers => [3]).loggers.should == [3]
19
+ Sequel::Database.new(1 => 2, :logger => 4, :loggers => 3).logger.should == 4
20
+ Sequel::Database.new(1 => 2, :logger => 4, :loggers => 3).loggers.should == [4,3]
21
+ Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).logger.should == 4
22
+ Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).loggers.should == [4,3]
14
23
  end
15
24
 
16
25
  specify "should create a connection pool" do
@@ -88,7 +97,7 @@ context "Database#dataset" do
88
97
  e.sql.should == 'SELECT * FROM miu'
89
98
  end
90
99
 
91
- specify "should provide a filtered #from dataset if a block is given" do
100
+ pt_specify "should provide a filtered #from dataset if a block is given" do
92
101
  d = @db.from(:mau) {:x > 100}
93
102
  d.should be_a_kind_of(Sequel::Dataset)
94
103
  d.sql.should == 'SELECT * FROM mau WHERE (x > 100)'
@@ -435,6 +444,18 @@ context "Database#transaction" do
435
444
  @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
436
445
  end
437
446
 
447
+ specify "should handle returning inside of the block by committing" do
448
+ def @db.ret_commit
449
+ transaction do
450
+ execute 'DROP TABLE test;'
451
+ return
452
+ execute 'DROP TABLE test2;';
453
+ end
454
+ end
455
+ @db.ret_commit
456
+ @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
457
+ end
458
+
438
459
  specify "should issue ROLLBACK if an exception is raised, and re-raise" do
439
460
  @db.transaction {@db.execute 'DROP TABLE test'; raise RuntimeError} rescue nil
440
461
  @db.sql.should == ['BEGIN', 'DROP TABLE test', 'ROLLBACK']
@@ -477,7 +498,15 @@ end
477
498
  context "A Database adapter with a scheme" do
478
499
  setup do
479
500
  class CCC < Sequel::Database
501
+ if defined?(DISCONNECTS)
502
+ DISCONNECTS.clear
503
+ else
504
+ DISCONNECTS = []
505
+ end
480
506
  set_adapter_scheme :ccc
507
+ def disconnect
508
+ DISCONNECTS << self
509
+ end
481
510
  end
482
511
  end
483
512
 
@@ -499,25 +528,40 @@ context "A Database adapter with a scheme" do
499
528
  c.opts[:database].should == 'db'
500
529
  end
501
530
 
502
- specify "should be accessible through Sequel.open" do
503
- c = Sequel.open 'ccc://localhost/db'
504
- c.should be_a_kind_of(CCC)
505
- c.opts[:host].should == 'localhost'
506
- c.opts[:database].should == 'db'
531
+ specify "should be accessible through Sequel.connect via a block" do
532
+ x = nil
533
+ y = nil
534
+ z = nil
535
+
536
+ p = proc do |c|
537
+ c.should be_a_kind_of(CCC)
538
+ c.opts[:host].should == 'localhost'
539
+ c.opts[:database].should == 'db'
540
+ z = y
541
+ y = x
542
+ x = c
543
+ end
544
+ Sequel::Database.connect('ccc://localhost/db', &p).should == nil
545
+ CCC::DISCONNECTS.should == [x]
546
+
547
+ Sequel.connect('ccc://localhost/db', &p).should == nil
548
+ CCC::DISCONNECTS.should == [y, x]
549
+
550
+ Sequel.send(:def_adapter_method, :ccc)
551
+ Sequel.ccc('db', :host=>'localhost', &p).should == nil
552
+ CCC::DISCONNECTS.should == [z, y, x]
507
553
  end
508
554
 
509
- ### DEPRECATED
510
- specify "should be accessible through Sequel()" do
511
- c = Sequel('ccc://localhost/db')
555
+ specify "should be accessible through Sequel.open" do
556
+ c = Sequel.open 'ccc://localhost/db'
512
557
  c.should be_a_kind_of(CCC)
513
558
  c.opts[:host].should == 'localhost'
514
559
  c.opts[:database].should == 'db'
515
560
  end
516
561
 
517
562
  specify "should be accessible through Sequel.<adapter>" do
518
- class << Sequel
519
- def_adapter_method(:ccc)
520
- end
563
+ Sequel.send(:def_adapter_method, :ccc)
564
+
521
565
  # invalid parameters
522
566
  proc {Sequel.ccc('abc', 'def')}.should raise_error(Sequel::Error)
523
567
 
@@ -681,9 +725,26 @@ context "A database" do
681
725
  db = Sequel::Database.new
682
726
  s = "I'm a logger"
683
727
  db.logger = s
684
- db.logger.should be(s)
728
+ db.logger.should == s
729
+ db.loggers.should == [s]
685
730
  db.logger = nil
686
- db.logger.should be_nil
731
+ db.logger.should == nil
732
+ db.loggers.should == []
733
+
734
+ db.loggers = [s]
735
+ db.logger.should == s
736
+ db.loggers.should == [s]
737
+ db.loggers = []
738
+ db.logger.should == nil
739
+ db.loggers.should == []
740
+
741
+ t = "I'm also a logger"
742
+ db.loggers = [s, t]
743
+ db.logger.should == s
744
+ db.loggers.should == [s,t]
745
+ db.loggers = []
746
+ db.logger.should == nil
747
+ db.loggers.should == []
687
748
  end
688
749
  end
689
750
 
@@ -720,7 +781,7 @@ context "Database#fetch" do
720
781
  sql.should == "select * from xyz where x = 15 and y = 'abc'"
721
782
 
722
783
  # and Aman Gupta's example
723
- @db.fetch('select name from table where name = ? or id in (?)',
784
+ @db.fetch('select name from table where name = ? or id in ?',
724
785
  'aman', [3,4,7]) {|r| sql = r[:sql]}
725
786
  sql.should == "select name from table where name = 'aman' or id in (3, 4, 7)"
726
787
  end
@@ -739,7 +800,7 @@ context "Database#fetch" do
739
800
  ds.select_sql.should == 'select * from xyz'
740
801
  ds.sql.should == 'select * from xyz'
741
802
 
742
- ds.filter! {:price < 100}
803
+ ds.filter!(:price < 100)
743
804
  ds.select_sql.should == 'select * from xyz'
744
805
  ds.sql.should == 'select * from xyz'
745
806
  end