sequel 3.33.0 → 3.34.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 +140 -0
- data/Rakefile +7 -0
- data/bin/sequel +22 -2
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/mass_assignment.rdoc +3 -1
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +23 -3
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/schema_modification.rdoc +18 -2
- data/doc/virtual_rows.rdoc +49 -0
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/ibmdb.rb +9 -4
- data/lib/sequel/adapters/jdbc.rb +9 -4
- data/lib/sequel/adapters/jdbc/h2.rb +8 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
- data/lib/sequel/adapters/mock.rb +24 -3
- data/lib/sequel/adapters/mysql.rb +29 -50
- data/lib/sequel/adapters/mysql2.rb +13 -28
- data/lib/sequel/adapters/oracle.rb +8 -2
- data/lib/sequel/adapters/postgres.rb +115 -20
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +14 -3
- data/lib/sequel/adapters/shared/mysql.rb +59 -11
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +127 -30
- data/lib/sequel/adapters/shared/sqlite.rb +55 -38
- data/lib/sequel/adapters/sqlite.rb +9 -3
- data/lib/sequel/adapters/swift.rb +2 -2
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +10 -0
- data/lib/sequel/ast_transformer.rb +4 -0
- data/lib/sequel/connection_pool.rb +8 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -0
- data/lib/sequel/core.rb +24 -3
- data/lib/sequel/database/connecting.rb +24 -14
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +16 -25
- data/lib/sequel/database/query.rb +20 -2
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +120 -23
- data/lib/sequel/dataset/actions.rb +91 -18
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -2
- data/lib/sequel/dataset/sql.rb +68 -51
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +227 -31
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +11 -2
- data/lib/sequel/model/associations.rb +35 -7
- data/lib/sequel/model/base.rb +159 -36
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +11 -3
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +4 -3
- data/lib/sequel/plugins/prepared_statements.rb +3 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +417 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +12 -15
- data/spec/adapters/mysql_spec.rb +81 -23
- data/spec/adapters/postgres_spec.rb +444 -77
- data/spec/adapters/spec_helper.rb +2 -0
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +85 -0
- data/spec/core/database_spec.rb +29 -5
- data/spec/core/dataset_spec.rb +171 -3
- data/spec/core/expression_filters_spec.rb +364 -0
- data/spec/core/mock_adapter_spec.rb +17 -3
- data/spec/core/schema_spec.rb +133 -0
- data/spec/extensions/association_dependencies_spec.rb +13 -13
- data/spec/extensions/caching_spec.rb +26 -3
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +5 -2
- data/spec/extensions/identity_map_spec.rb +17 -0
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +2 -2
- data/spec/extensions/list_spec.rb +4 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +6 -2
- data/spec/extensions/nested_attributes_spec.rb +20 -0
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_spec.rb +4 -0
- data/spec/extensions/pretty_table_spec.rb +6 -0
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +231 -11
- data/spec/extensions/schema_spec.rb +14 -2
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/sharding_spec.rb +6 -6
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +2 -1
- data/spec/extensions/sql_expr_spec.rb +28 -19
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +9 -1
- data/spec/integration/associations_test.rb +6 -6
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +89 -26
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +85 -22
- data/spec/integration/prepared_statement_test.rb +28 -8
- data/spec/integration/schema_test.rb +78 -7
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +4 -6
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +94 -8
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/hooks_spec.rb +2 -2
- data/spec/model/model_spec.rb +19 -7
- data/spec/model/record_spec.rb +135 -58
- data/spec/model/spec_helper.rb +1 -0
- metadata +35 -7
|
@@ -78,7 +78,7 @@ describe "An SQLite database" do
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
specify "should provide a list of existing tables" do
|
|
81
|
-
@db.drop_table(:testing)
|
|
81
|
+
@db.drop_table?(:testing)
|
|
82
82
|
@db.tables.should be_a_kind_of(Array)
|
|
83
83
|
@db.tables.should_not include(:testing)
|
|
84
84
|
@db.create_table! :testing do
|
|
@@ -145,12 +145,12 @@ describe "SQLite type conversion" do
|
|
|
145
145
|
@integer_booleans = @db.integer_booleans
|
|
146
146
|
@db.integer_booleans = true
|
|
147
147
|
@ds = @db[:items]
|
|
148
|
-
@db.drop_table(:items)
|
|
148
|
+
@db.drop_table?(:items)
|
|
149
149
|
end
|
|
150
150
|
after do
|
|
151
151
|
@db.integer_booleans = @integer_booleans
|
|
152
152
|
Sequel.datetime_class = Time
|
|
153
|
-
@db.drop_table(:items)
|
|
153
|
+
@db.drop_table?(:items)
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
specify "should handle integers in boolean columns" do
|
|
@@ -352,7 +352,7 @@ describe "SQLite dataset" do
|
|
|
352
352
|
@d << {:name => 'ghi', :value => 7.89}
|
|
353
353
|
end
|
|
354
354
|
after do
|
|
355
|
-
SQLITE_DB.drop_table(:test, :items)
|
|
355
|
+
SQLITE_DB.drop_table?(:test, :items)
|
|
356
356
|
end
|
|
357
357
|
|
|
358
358
|
specify "should be able to insert from a subquery" do
|
|
@@ -363,13 +363,13 @@ describe "SQLite dataset" do
|
|
|
363
363
|
end
|
|
364
364
|
|
|
365
365
|
specify "should support #explain" do
|
|
366
|
-
SQLITE_DB[:test].explain.should be_a_kind_of(
|
|
366
|
+
SQLITE_DB[:test].explain.should be_a_kind_of(String)
|
|
367
367
|
end
|
|
368
368
|
|
|
369
369
|
specify "should have #explain work when identifier_output_method is modified" do
|
|
370
370
|
ds = SQLITE_DB[:test]
|
|
371
371
|
ds.identifier_output_method = :upcase
|
|
372
|
-
ds.explain.should be_a_kind_of(
|
|
372
|
+
ds.explain.should be_a_kind_of(String)
|
|
373
373
|
end
|
|
374
374
|
end
|
|
375
375
|
|
|
@@ -457,7 +457,7 @@ describe "A SQLite database" do
|
|
|
457
457
|
@db[:test].filter(:name => 'foo').update(:id=>100)
|
|
458
458
|
@db[:test3][:name => 'abc'][:test_id].should == 100
|
|
459
459
|
|
|
460
|
-
@db.drop_table :test, :test3
|
|
460
|
+
@db.drop_table? :test, :test3
|
|
461
461
|
end
|
|
462
462
|
end
|
|
463
463
|
|
|
@@ -495,7 +495,7 @@ describe "A SQLite database" do
|
|
|
495
495
|
specify "should handle quoted tables when dropping or renaming columns" do
|
|
496
496
|
@db.quote_identifiers = true
|
|
497
497
|
table_name = "T T"
|
|
498
|
-
@db.drop_table(table_name)
|
|
498
|
+
@db.drop_table?(table_name)
|
|
499
499
|
@db.create_table! table_name do
|
|
500
500
|
Integer :"s s"
|
|
501
501
|
Integer :"i i"
|
|
@@ -228,6 +228,45 @@ describe "A connection pool with a max size of 1" do
|
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
shared_examples_for "A threaded connection pool" do
|
|
231
|
+
specify "should not have all_connections yield connections allocated to other threads" do
|
|
232
|
+
pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>2, :pool_timeout=>0)) {@invoked_count += 1}
|
|
233
|
+
q, q1 = Queue.new, Queue.new
|
|
234
|
+
t = Thread.new do
|
|
235
|
+
pool.hold do |c1|
|
|
236
|
+
q1.push nil
|
|
237
|
+
q.pop
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
pool.hold do |c1|
|
|
241
|
+
q1.pop
|
|
242
|
+
pool.all_connections{|c| c.should == c1}
|
|
243
|
+
q.push nil
|
|
244
|
+
end
|
|
245
|
+
t.join
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
specify "should not have all_connections yield all available connections" do
|
|
249
|
+
pool = Sequel::ConnectionPool.get_pool(@cp_opts.merge(:max_connections=>2, :pool_timeout=>0)){@invoked_count += 1}
|
|
250
|
+
q, q1 = Queue.new, Queue.new
|
|
251
|
+
b = []
|
|
252
|
+
t = Thread.new do
|
|
253
|
+
pool.hold do |c1|
|
|
254
|
+
b << c1
|
|
255
|
+
q1.push nil
|
|
256
|
+
q.pop
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
pool.hold do |c1|
|
|
260
|
+
q1.pop
|
|
261
|
+
b << c1
|
|
262
|
+
q.push nil
|
|
263
|
+
end
|
|
264
|
+
t.join
|
|
265
|
+
a = []
|
|
266
|
+
pool.all_connections{|c| a << c}
|
|
267
|
+
a.sort.should == b.sort
|
|
268
|
+
end
|
|
269
|
+
|
|
231
270
|
specify "should raise a PoolTimeout error if a connection couldn't be acquired before timeout" do
|
|
232
271
|
x = nil
|
|
233
272
|
q, q1 = Queue.new, Queue.new
|
|
@@ -370,6 +409,16 @@ describe "A connection pool with multiple servers" do
|
|
|
370
409
|
@pool = Sequel::ConnectionPool.get_pool(CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}})){|server| "#{server}#{@invoked_counts[server] += 1}"}
|
|
371
410
|
end
|
|
372
411
|
|
|
412
|
+
specify "#all_connections should return connections for all servers" do
|
|
413
|
+
@pool.hold{}
|
|
414
|
+
@pool.all_connections{|c1| c1.should == "default1"}
|
|
415
|
+
a = []
|
|
416
|
+
@pool.hold(:read_only) do |c|
|
|
417
|
+
@pool.all_connections{|c1| a << c1}
|
|
418
|
+
end
|
|
419
|
+
a.sort_by{|c| c.to_s}.should == ["default1", "read_only1"]
|
|
420
|
+
end
|
|
421
|
+
|
|
373
422
|
specify "#servers should return symbols for all servers" do
|
|
374
423
|
@pool.servers.sort_by{|s| s.to_s}.should == [:default, :read_only]
|
|
375
424
|
end
|
|
@@ -624,6 +673,16 @@ describe "A single threaded pool with multiple servers" do
|
|
|
624
673
|
@pool = Sequel::ConnectionPool.get_pool(ST_CONNECTION_POOL_DEFAULTS.merge(:disconnection_proc=>proc{|c| @max_size=3}, :servers=>{:read_only=>{}})){|server| server}
|
|
625
674
|
end
|
|
626
675
|
|
|
676
|
+
specify "#all_connections should return connections for all servers" do
|
|
677
|
+
@pool.hold{}
|
|
678
|
+
@pool.all_connections{|c1| c1.should == :default}
|
|
679
|
+
a = []
|
|
680
|
+
@pool.hold(:read_only) do
|
|
681
|
+
@pool.all_connections{|c1| a << c1}
|
|
682
|
+
end
|
|
683
|
+
a.sort_by{|c| c.to_s}.should == [:default, :read_only]
|
|
684
|
+
end
|
|
685
|
+
|
|
627
686
|
specify "#servers should return symbols for all servers" do
|
|
628
687
|
@pool.servers.sort_by{|s| s.to_s}.should == [:default, :read_only]
|
|
629
688
|
end
|
|
@@ -730,6 +789,32 @@ describe "A single threaded pool with multiple servers" do
|
|
|
730
789
|
end
|
|
731
790
|
|
|
732
791
|
shared_examples_for "All connection pools classes" do
|
|
792
|
+
specify "should have all_connections yield current and available connections" do
|
|
793
|
+
p = @class.new({}){123}
|
|
794
|
+
p.hold{|c| p.all_connections{|c1| c.should == c1}}
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
specify "should be able to modify after_connect proc after the pool is created" do
|
|
798
|
+
a = []
|
|
799
|
+
p = @class.new({}){123}
|
|
800
|
+
p.after_connect = pr = proc{|c| a << c}
|
|
801
|
+
p.after_connect.should == pr
|
|
802
|
+
a.should == []
|
|
803
|
+
p.hold{}
|
|
804
|
+
a.should == [123]
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
specify "should be able to modify disconnection_proc after the pool is created" do
|
|
808
|
+
a = []
|
|
809
|
+
p = @class.new({}){123}
|
|
810
|
+
p.disconnection_proc = pr = proc{|c| a << c}
|
|
811
|
+
p.disconnection_proc.should == pr
|
|
812
|
+
p.hold{}
|
|
813
|
+
a.should == []
|
|
814
|
+
p.disconnect
|
|
815
|
+
a.should == [123]
|
|
816
|
+
end
|
|
817
|
+
|
|
733
818
|
specify "should not raise an error when disconnecting twice" do
|
|
734
819
|
c = @class.new({}){123}
|
|
735
820
|
proc{c.disconnect}.should_not raise_error
|
data/spec/core/database_spec.rb
CHANGED
|
@@ -325,6 +325,10 @@ describe "Database#uri" do
|
|
|
325
325
|
@db.uri.should == 'mau://user:pass@localhost:9876/maumau'
|
|
326
326
|
end
|
|
327
327
|
|
|
328
|
+
specify "should return nil if a connection uri was not used" do
|
|
329
|
+
Sequel.mock.uri.should be_nil
|
|
330
|
+
end
|
|
331
|
+
|
|
328
332
|
specify "should be aliased as #url" do
|
|
329
333
|
@db.url.should == 'mau://user:pass@localhost:9876/maumau'
|
|
330
334
|
end
|
|
@@ -413,6 +417,13 @@ describe "Database#extend_datasets" do
|
|
|
413
417
|
@db.extend_datasets(@m)
|
|
414
418
|
end
|
|
415
419
|
|
|
420
|
+
specify "should clear a cached dataset" do
|
|
421
|
+
@db = Sequel::Database.new
|
|
422
|
+
@db.literal(1).should == '1'
|
|
423
|
+
@db.extend_datasets{def literal(v) '2' end}
|
|
424
|
+
@db.literal(1).should == '2'
|
|
425
|
+
end
|
|
426
|
+
|
|
416
427
|
specify "should change the dataset class to a subclass the first time it is called" do
|
|
417
428
|
@db.dataset_class.superclass.should == Sequel::Dataset
|
|
418
429
|
end
|
|
@@ -484,6 +495,12 @@ describe "Database#indexes" do
|
|
|
484
495
|
end
|
|
485
496
|
end
|
|
486
497
|
|
|
498
|
+
describe "Database#foreign_key_list" do
|
|
499
|
+
specify "should raise Sequel::NotImplemented" do
|
|
500
|
+
proc {Sequel::Database.new.foreign_key_list(:table)}.should raise_error(Sequel::NotImplemented)
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
487
504
|
describe "Database#run" do
|
|
488
505
|
before do
|
|
489
506
|
@db = Sequel.mock(:servers=>{:s1=>{}})
|
|
@@ -1061,21 +1078,20 @@ describe "A Database adapter with a scheme" do
|
|
|
1061
1078
|
proc {Sequel.ccc('abc', 'def')}.should raise_error(Sequel::Error)
|
|
1062
1079
|
|
|
1063
1080
|
c = Sequel.ccc('mydb')
|
|
1064
|
-
p = proc{c.opts.delete_if{|k,v| k == :disconnection_proc || k == :single_threaded}}
|
|
1065
1081
|
c.should be_a_kind_of(@ccc)
|
|
1066
|
-
|
|
1082
|
+
c.opts.values_at(:adapter, :database, :adapter_class).should == [:ccc, 'mydb', @ccc]
|
|
1067
1083
|
|
|
1068
1084
|
c = Sequel.ccc('mydb', :host => 'localhost')
|
|
1069
1085
|
c.should be_a_kind_of(@ccc)
|
|
1070
|
-
|
|
1086
|
+
c.opts.values_at(:adapter, :database, :host, :adapter_class).should == [:ccc, 'mydb', 'localhost', @ccc]
|
|
1071
1087
|
|
|
1072
1088
|
c = Sequel.ccc
|
|
1073
1089
|
c.should be_a_kind_of(@ccc)
|
|
1074
|
-
|
|
1090
|
+
c.opts.values_at(:adapter, :adapter_class).should == [:ccc, @ccc]
|
|
1075
1091
|
|
|
1076
1092
|
c = Sequel.ccc(:database => 'mydb', :host => 'localhost')
|
|
1077
1093
|
c.should be_a_kind_of(@ccc)
|
|
1078
|
-
|
|
1094
|
+
c.opts.values_at(:adapter, :database, :host, :adapter_class).should == [:ccc, 'mydb', 'localhost', @ccc]
|
|
1079
1095
|
end
|
|
1080
1096
|
|
|
1081
1097
|
specify "should be accessible through Sequel.connect with options" do
|
|
@@ -1336,6 +1352,14 @@ describe "Database#inspect" do
|
|
|
1336
1352
|
specify "should include the class name and the connection url" do
|
|
1337
1353
|
Sequel.connect('mock://foo/bar').inspect.should == '#<Sequel::Mock::Database: "mock://foo/bar">'
|
|
1338
1354
|
end
|
|
1355
|
+
|
|
1356
|
+
specify "should include the class name and the connection options if an options hash was given" do
|
|
1357
|
+
Sequel.connect(:adapter=>:mock).inspect.should =~ /#<Sequel::Mock::Database: \{:adapter=>:mock\}>/
|
|
1358
|
+
end
|
|
1359
|
+
|
|
1360
|
+
specify "should include the class name, uri, and connection options if uri and options hash was given" do
|
|
1361
|
+
Sequel.connect('mock://foo', :database=>'bar').inspect.should =~ /#<Sequel::Mock::Database: "mock:\/\/foo" \{:database=>"bar"\}>/
|
|
1362
|
+
end
|
|
1339
1363
|
end
|
|
1340
1364
|
|
|
1341
1365
|
describe "Database#get" do
|
data/spec/core/dataset_spec.rb
CHANGED
|
@@ -914,12 +914,18 @@ describe "Dataset#group_by" do
|
|
|
914
914
|
@dataset.meta_def(:supports_group_rollup?){true}
|
|
915
915
|
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id)"
|
|
916
916
|
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY ROLLUP(type_id, b)"
|
|
917
|
+
@dataset.meta_def(:uses_with_rollup?){true}
|
|
918
|
+
@dataset.group(:type_id).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY type_id WITH ROLLUP"
|
|
919
|
+
@dataset.group(:type_id, :b).group_rollup.select_sql.should == "SELECT * FROM test GROUP BY type_id, b WITH ROLLUP"
|
|
917
920
|
end
|
|
918
921
|
|
|
919
922
|
specify "should support a #group_cube method if the database supports it" do
|
|
920
923
|
@dataset.meta_def(:supports_group_cube?){true}
|
|
921
924
|
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id)"
|
|
922
925
|
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY CUBE(type_id, b)"
|
|
926
|
+
@dataset.meta_def(:uses_with_rollup?){true}
|
|
927
|
+
@dataset.group(:type_id).group_cube.select_sql.should == "SELECT * FROM test GROUP BY type_id WITH CUBE"
|
|
928
|
+
@dataset.group(:type_id, :b).group_cube.select_sql.should == "SELECT * FROM test GROUP BY type_id, b WITH CUBE"
|
|
923
929
|
end
|
|
924
930
|
|
|
925
931
|
specify "should have #group_cube and #group_rollup methods raise an Error if not supported it" do
|
|
@@ -935,6 +941,42 @@ describe "Dataset#as" do
|
|
|
935
941
|
end
|
|
936
942
|
end
|
|
937
943
|
|
|
944
|
+
describe "Dataset#literal" do
|
|
945
|
+
before do
|
|
946
|
+
@ds = Sequel::Database.new.dataset
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
specify "should convert qualified symbol notation into dot notation" do
|
|
950
|
+
@ds.literal(:abc__def).should == 'abc.def'
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
specify "should convert AS symbol notation into SQL AS notation" do
|
|
954
|
+
@ds.literal(:xyz___x).should == 'xyz AS x'
|
|
955
|
+
@ds.literal(:abc__def___x).should == 'abc.def AS x'
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
specify "should support names with digits" do
|
|
959
|
+
@ds.literal(:abc2).should == 'abc2'
|
|
960
|
+
@ds.literal(:xx__yy3).should == 'xx.yy3'
|
|
961
|
+
@ds.literal(:ab34__temp3_4ax).should == 'ab34.temp3_4ax'
|
|
962
|
+
@ds.literal(:x1___y2).should == 'x1 AS y2'
|
|
963
|
+
@ds.literal(:abc2__def3___ggg4).should == 'abc2.def3 AS ggg4'
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
specify "should support upper case and lower case" do
|
|
967
|
+
@ds.literal(:ABC).should == 'ABC'
|
|
968
|
+
@ds.literal(:Zvashtoy__aBcD).should == 'Zvashtoy.aBcD'
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
specify "should support spaces inside column names" do
|
|
972
|
+
@ds.quote_identifiers = true
|
|
973
|
+
@ds.literal(:"AB C").should == '"AB C"'
|
|
974
|
+
@ds.literal(:"Zvas htoy__aB cD").should == '"Zvas htoy"."aB cD"'
|
|
975
|
+
@ds.literal(:"aB cD___XX XX").should == '"aB cD" AS "XX XX"'
|
|
976
|
+
@ds.literal(:"Zva shtoy__aB cD___XX XX").should == '"Zva shtoy"."aB cD" AS "XX XX"'
|
|
977
|
+
end
|
|
978
|
+
end
|
|
979
|
+
|
|
938
980
|
describe "Dataset#literal" do
|
|
939
981
|
before do
|
|
940
982
|
@dataset = Sequel::Database.new.from(:test)
|
|
@@ -1105,6 +1147,17 @@ describe "Dataset#literal" do
|
|
|
1105
1147
|
@dataset.literal(BigDecimal.new("-Infinity")).should == "'-Infinity'"
|
|
1106
1148
|
end
|
|
1107
1149
|
|
|
1150
|
+
specify "should literalize PlaceholderLiteralStrings correctly" do
|
|
1151
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new('? = ?', [1, 2])).should == '1 = 2'
|
|
1152
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new('? = ?', [1, 2], true)).should == '(1 = 2)'
|
|
1153
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(':a = :b', :a=>1, :b=>2)).should == '1 = 2'
|
|
1154
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(':a = :b', {:a=>1, :b=>2}, true)).should == '(1 = 2)'
|
|
1155
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = ', ''], [1, 2])).should == '1 = 2'
|
|
1156
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = ', ''], [1, 2], true)).should == '(1 = 2)'
|
|
1157
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = '], [1, 2])).should == '1 = 2'
|
|
1158
|
+
@dataset.literal(Sequel::SQL::PlaceholderLiteralString.new(['', ' = '], [1, 2], true)).should == '(1 = 2)'
|
|
1159
|
+
end
|
|
1160
|
+
|
|
1108
1161
|
specify "should raise an Error if the object can't be literalized" do
|
|
1109
1162
|
proc{@dataset.literal(Object.new)}.should raise_error(Sequel::Error)
|
|
1110
1163
|
end
|
|
@@ -1720,7 +1773,45 @@ describe "Dataset#to_hash" do
|
|
|
1720
1773
|
@d.to_hash(:b).should == {4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12}}
|
|
1721
1774
|
@d.to_hash([:a, :b]).should == {[2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12}}
|
|
1722
1775
|
end
|
|
1776
|
+
end
|
|
1777
|
+
|
|
1778
|
+
describe "Dataset#to_hash_groups" do
|
|
1779
|
+
before do
|
|
1780
|
+
@d = Sequel.mock(:fetch=>[{:a => 1, :b => 2}, {:a => 3, :b => 4}, {:a => 1, :b => 6}, {:a => 7, :b => 4}])[:items]
|
|
1781
|
+
end
|
|
1723
1782
|
|
|
1783
|
+
specify "should provide a hash with the first column as key and the second as value" do
|
|
1784
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1785
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1786
|
+
end
|
|
1787
|
+
|
|
1788
|
+
specify "should provide a hash with the first column as key and the entire hash as value if the value column is blank or nil" do
|
|
1789
|
+
@d.to_hash_groups(:a).should == {1 => [{:a => 1, :b => 2}, {:a => 1, :b => 6}], 3 => [{:a => 3, :b => 4}], 7 => [{:a => 7, :b => 4}]}
|
|
1790
|
+
@d.to_hash_groups(:b).should == {2 => [{:a => 1, :b => 2}], 4 => [{:a => 3, :b => 4}, {:a => 7, :b => 4}], 6 => [{:a => 1, :b => 6}]}
|
|
1791
|
+
end
|
|
1792
|
+
|
|
1793
|
+
specify "should support using an array of columns as either the key or the value" do
|
|
1794
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1795
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1796
|
+
@d.to_hash_groups([:b, :a], [:a, :b]).should == {[2, 1] => [[1, 2]], [4, 3] => [[3, 4]], [6, 1] => [[1, 6]], [4, 7]=>[[7, 4]]}
|
|
1797
|
+
@d.to_hash_groups([:a, :b]).should == {[1, 2] => [{:a => 1, :b => 2}], [3, 4] => [{:a => 3, :b => 4}], [1, 6] => [{:a => 1, :b => 6}], [7, 4] => [{:a => 7, :b => 4}]}
|
|
1798
|
+
end
|
|
1799
|
+
|
|
1800
|
+
specify "should not call the row_proc if two arguments are given" do
|
|
1801
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1802
|
+
@d.to_hash_groups(:a, :b).should == {1 => [2, 6], 3 => [4], 7 => [4]}
|
|
1803
|
+
@d.to_hash_groups(:b, :a).should == {2 => [1], 4=>[3, 7], 6=>[1]}
|
|
1804
|
+
@d.to_hash_groups([:a, :b], :b).should == {[1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4]}
|
|
1805
|
+
@d.to_hash_groups(:b, [:a, :b]).should == {2 => [[1, 2]], 4 => [[3, 4], [7, 4]], 6 => [[1, 6]]}
|
|
1806
|
+
@d.to_hash_groups([:b, :a], [:a, :b]).should == {[2, 1] => [[1, 2]], [4, 3] => [[3, 4]], [6, 1] => [[1, 6]], [4, 7]=>[[7, 4]]}
|
|
1807
|
+
end
|
|
1808
|
+
|
|
1809
|
+
specify "should call the row_proc if only a single argument is given" do
|
|
1810
|
+
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
|
1811
|
+
@d.to_hash_groups(:a).should == {2 => [{:a => 2, :b => 4}, {:a => 2, :b => 12}], 6 => [{:a => 6, :b => 8}], 14 => [{:a => 14, :b => 8}]}
|
|
1812
|
+
@d.to_hash_groups(:b).should == {4 => [{:a => 2, :b => 4}], 8 => [{:a => 6, :b => 8}, {:a => 14, :b => 8}], 12 => [{:a => 2, :b => 12}]}
|
|
1813
|
+
@d.to_hash_groups([:a, :b]).should == {[2, 4] => [{:a => 2, :b => 4}], [6, 8] => [{:a => 6, :b => 8}], [2, 12] => [{:a => 2, :b => 12}], [14, 8] => [{:a => 14, :b => 8}]}
|
|
1814
|
+
end
|
|
1724
1815
|
end
|
|
1725
1816
|
|
|
1726
1817
|
describe "Dataset#distinct" do
|
|
@@ -3077,7 +3168,7 @@ describe "Dataset#grep" do
|
|
|
3077
3168
|
end
|
|
3078
3169
|
end
|
|
3079
3170
|
|
|
3080
|
-
describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #execute" do
|
|
3171
|
+
describe "Dataset default #fetch_rows, #insert, #update, #delete, #with_sql_delete, #truncate, #execute" do
|
|
3081
3172
|
before do
|
|
3082
3173
|
@db = Sequel::Database.new
|
|
3083
3174
|
@ds = @db[:items]
|
|
@@ -3094,6 +3185,14 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
|
|
|
3094
3185
|
@ds.delete
|
|
3095
3186
|
end
|
|
3096
3187
|
|
|
3188
|
+
specify "#with_sql_delete should execute delete SQL" do
|
|
3189
|
+
sql = 'DELETE FROM foo'
|
|
3190
|
+
@db.should_receive(:execute).once.with(sql, :server=>:default)
|
|
3191
|
+
@ds.with_sql_delete(sql)
|
|
3192
|
+
@db.should_receive(:execute_dui).once.with(sql, :server=>:default)
|
|
3193
|
+
@ds.with_sql_delete(sql)
|
|
3194
|
+
end
|
|
3195
|
+
|
|
3097
3196
|
specify "#insert should execute insert SQL" do
|
|
3098
3197
|
@db.should_receive(:execute).once.with('INSERT INTO items DEFAULT VALUES', :server=>:default)
|
|
3099
3198
|
@ds.insert([])
|
|
@@ -3136,12 +3235,14 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3136
3235
|
@ds.filter(:num=>:$n).call(:select, :n=>1)
|
|
3137
3236
|
@ds.filter(:num=>:$n).call([:map, :a], :n=>1)
|
|
3138
3237
|
@ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
|
|
3238
|
+
@ds.filter(:num=>:$n).call([:to_hash_groups, :a, :b], :n=>1)
|
|
3139
3239
|
@ds.filter(:num=>:$n).call(:first, :n=>1)
|
|
3140
3240
|
@ds.filter(:num=>:$n).call(:delete, :n=>1)
|
|
3141
3241
|
@ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
|
|
3142
3242
|
@ds.call(:insert, {:n=>1}, :num=>:$n)
|
|
3143
3243
|
@ds.call(:insert_select, {:n=>1}, :num=>:$n)
|
|
3144
3244
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3245
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3145
3246
|
'SELECT * FROM items WHERE (num = 1)',
|
|
3146
3247
|
'SELECT * FROM items WHERE (num = 1)',
|
|
3147
3248
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
@@ -3156,22 +3257,25 @@ describe "Dataset prepared statements and bound variables " do
|
|
|
3156
3257
|
pss << @ds.filter(:num=>:$n).prepare(:select, :sn)
|
|
3157
3258
|
pss << @ds.filter(:num=>:$n).prepare([:map, :a], :sm)
|
|
3158
3259
|
pss << @ds.filter(:num=>:$n).prepare([:to_hash, :a, :b], :sh)
|
|
3260
|
+
pss << @ds.filter(:num=>:$n).prepare([:to_hash_groups, :a, :b], :shg)
|
|
3159
3261
|
pss << @ds.filter(:num=>:$n).prepare(:first, :fn)
|
|
3160
3262
|
pss << @ds.filter(:num=>:$n).prepare(:delete, :dn)
|
|
3161
3263
|
pss << @ds.filter(:num=>:$n).prepare(:update, :un, :num=>:$n2)
|
|
3162
3264
|
pss << @ds.prepare(:insert, :in, :num=>:$n)
|
|
3163
3265
|
pss << @ds.prepare(:insert_select, :ins, :num=>:$n)
|
|
3164
|
-
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sh, :sm, :sn, :un]
|
|
3165
|
-
[:sn, :sm, :sh, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3266
|
+
@db.prepared_statements.keys.sort_by{|k| k.to_s}.should == [:dn, :fn, :in, :ins, :sh, :shg, :sm, :sn, :un]
|
|
3267
|
+
[:sn, :sm, :sh, :shg, :fn, :dn, :un, :in, :ins].each_with_index{|x, i| @db.prepared_statements[x].should == pss[i]}
|
|
3166
3268
|
@db.call(:sn, :n=>1)
|
|
3167
3269
|
@db.call(:sm, :n=>1)
|
|
3168
3270
|
@db.call(:sh, :n=>1)
|
|
3271
|
+
@db.call(:shg, :n=>1)
|
|
3169
3272
|
@db.call(:fn, :n=>1)
|
|
3170
3273
|
@db.call(:dn, :n=>1)
|
|
3171
3274
|
@db.call(:un, :n=>1, :n2=>2)
|
|
3172
3275
|
@db.call(:in, :n=>1)
|
|
3173
3276
|
@db.call(:ins, :n=>1)
|
|
3174
3277
|
@db.sqls.should == ['SELECT * FROM items WHERE (num = 1)',
|
|
3278
|
+
'SELECT * FROM items WHERE (num = 1)',
|
|
3175
3279
|
'SELECT * FROM items WHERE (num = 1)',
|
|
3176
3280
|
'SELECT * FROM items WHERE (num = 1)',
|
|
3177
3281
|
'SELECT * FROM items WHERE (num = 1) LIMIT 1',
|
|
@@ -3427,6 +3531,10 @@ describe "Sequel::Dataset#qualify_to_first_source" do
|
|
|
3427
3531
|
@ds.filter(':a > :b', :a=>:c, :b=>1).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.c > 1)'
|
|
3428
3532
|
end
|
|
3429
3533
|
|
|
3534
|
+
specify "should handle SQL::Wrappers" do
|
|
3535
|
+
@ds.filter(Sequel::SQL::Wrapper.new(:a)).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE t.a'
|
|
3536
|
+
end
|
|
3537
|
+
|
|
3430
3538
|
specify "should handle SQL::WindowFunctions" do
|
|
3431
3539
|
@ds.meta_def(:supports_window_functions?){true}
|
|
3432
3540
|
@ds.select{sum(:over, :args=>:a, :partition=>:b, :order=>:c){}}.qualify_to_first_source.sql.should == 'SELECT sum(t.a) OVER (PARTITION BY t.b ORDER BY t.c) FROM t'
|
|
@@ -3485,6 +3593,10 @@ describe "Sequel::Dataset#unbind" do
|
|
|
3485
3593
|
@u[@ds.filter{foo__bar > 1}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3486
3594
|
end
|
|
3487
3595
|
|
|
3596
|
+
specify "should handle wrapped objects" do
|
|
3597
|
+
@u[@ds.filter{Sequel::SQL::Wrapper.new(foo__bar) > Sequel::SQL::Wrapper.new(1)}].should == ["SELECT * FROM t WHERE (foo.bar > $foo.bar)", {:"foo.bar"=>1}]
|
|
3598
|
+
end
|
|
3599
|
+
|
|
3488
3600
|
specify "should handle deep nesting" do
|
|
3489
3601
|
@u[@ds.filter{foo > 1}.and{bar < 2}.or(:baz=>3).and({~{:x=>4}=>true}.case(false))].should == ["SELECT * FROM t WHERE ((((foo > $foo) AND (bar < $bar)) OR (baz = $baz)) AND (CASE WHEN (x != $x) THEN 't' ELSE 'f' END))", {:foo=>1, :bar=>2, :baz=>3, :x=>4}]
|
|
3490
3602
|
end
|
|
@@ -3972,6 +4084,62 @@ describe "Sequel::Dataset#select_hash" do
|
|
|
3972
4084
|
end
|
|
3973
4085
|
end
|
|
3974
4086
|
|
|
4087
|
+
describe "Sequel::Dataset#select_hash_groups" do
|
|
4088
|
+
before do
|
|
4089
|
+
@db = Sequel.mock(:fetch=>[{:a=>1, :b=>2}, {:a=>3, :b=>4}])
|
|
4090
|
+
@ds = @db[:t]
|
|
4091
|
+
end
|
|
4092
|
+
|
|
4093
|
+
specify "should do select and to_hash in one step" do
|
|
4094
|
+
@ds.select_hash_groups(:a, :b).should == {1=>[2], 3=>[4]}
|
|
4095
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4096
|
+
end
|
|
4097
|
+
|
|
4098
|
+
specify "should handle implicit qualifiers in arguments" do
|
|
4099
|
+
@ds.select_hash_groups(:t__a, :t__b).should == {1=>[2], 3=>[4]}
|
|
4100
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4101
|
+
end
|
|
4102
|
+
|
|
4103
|
+
specify "should handle implicit aliases in arguments" do
|
|
4104
|
+
@ds.select_hash_groups(:c___a, :d___b).should == {1=>[2], 3=>[4]}
|
|
4105
|
+
@ds.db.sqls.should == ['SELECT c AS a, d AS b FROM t']
|
|
4106
|
+
end
|
|
4107
|
+
|
|
4108
|
+
specify "should handle implicit qualifiers and aliases in arguments" do
|
|
4109
|
+
@ds.select_hash_groups(:t__c___a, :t__d___b).should == {1=>[2], 3=>[4]}
|
|
4110
|
+
@ds.db.sqls.should == ['SELECT t.c AS a, t.d AS b FROM t']
|
|
4111
|
+
end
|
|
4112
|
+
|
|
4113
|
+
specify "should handle SQL::Identifiers in arguments" do
|
|
4114
|
+
@ds.select_hash_groups(:a.identifier, :b.identifier).should == {1=>[2], 3=>[4]}
|
|
4115
|
+
@ds.db.sqls.should == ['SELECT a, b FROM t']
|
|
4116
|
+
end
|
|
4117
|
+
|
|
4118
|
+
specify "should handle SQL::QualifiedIdentifiers in arguments" do
|
|
4119
|
+
@ds.select_hash_groups(:a.qualify(:t), :b.identifier.qualify(:t)).should == {1=>[2], 3=>[4]}
|
|
4120
|
+
@ds.db.sqls.should == ['SELECT t.a, t.b FROM t']
|
|
4121
|
+
end
|
|
4122
|
+
|
|
4123
|
+
specify "should handle SQL::AliasedExpressions in arguments" do
|
|
4124
|
+
@ds.select_hash_groups(:c.as(:a), :t.as(:b)).should == {1=>[2], 3=>[4]}
|
|
4125
|
+
@ds.db.sqls.should == ['SELECT c AS a, t AS b FROM t']
|
|
4126
|
+
end
|
|
4127
|
+
|
|
4128
|
+
specify "should work with arrays of columns" do
|
|
4129
|
+
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
|
4130
|
+
@ds.select_hash_groups([:a, :c], :b).should == {[1, 3]=>[2], [4, 6]=>[5]}
|
|
4131
|
+
@ds.db.sqls.should == ['SELECT a, c, b FROM t']
|
|
4132
|
+
@ds.select_hash_groups(:a, [:b, :c]).should == {1=>[[2, 3]], 4=>[[5, 6]]}
|
|
4133
|
+
@ds.db.sqls.should == ['SELECT a, b, c FROM t']
|
|
4134
|
+
@ds.select_hash_groups([:a, :b], [:b, :c]).should == {[1, 2]=>[[2, 3]], [4, 5]=>[[5, 6]]}
|
|
4135
|
+
@ds.db.sqls.should == ['SELECT a, b, b, c FROM t']
|
|
4136
|
+
end
|
|
4137
|
+
|
|
4138
|
+
specify "should raise an error if the resulting symbol cannot be determined" do
|
|
4139
|
+
proc{@ds.select_hash_groups(:c.as(:a), :b.sql_function)}.should raise_error(Sequel::Error)
|
|
4140
|
+
end
|
|
4141
|
+
end
|
|
4142
|
+
|
|
3975
4143
|
describe "Modifying joined datasets" do
|
|
3976
4144
|
before do
|
|
3977
4145
|
@ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
|