sequel 3.26.0 → 3.27.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 +26 -0
- data/Rakefile +2 -3
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +9 -533
- data/doc/prepared_statements.rdoc +8 -7
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/testing.rdoc +64 -0
- data/lib/sequel/adapters/amalgalite.rb +4 -0
- data/lib/sequel/adapters/jdbc.rb +3 -1
- data/lib/sequel/adapters/jdbc/h2.rb +11 -5
- data/lib/sequel/adapters/mysql.rb +4 -122
- data/lib/sequel/adapters/mysql2.rb +4 -13
- data/lib/sequel/adapters/odbc.rb +4 -1
- data/lib/sequel/adapters/odbc/db2.rb +21 -0
- data/lib/sequel/adapters/shared/mysql.rb +12 -0
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +143 -0
- data/lib/sequel/adapters/tinytds.rb +122 -3
- data/lib/sequel/core.rb +4 -3
- data/lib/sequel/database/misc.rb +7 -10
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/sql.rb +7 -0
- data/lib/sequel/model/associations.rb +2 -2
- data/lib/sequel/model/base.rb +60 -10
- data/lib/sequel/plugins/prepared_statements_safe.rb +17 -7
- data/lib/sequel/sql.rb +5 -0
- data/lib/sequel/timezones.rb +12 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +25 -21
- data/spec/core/database_spec.rb +200 -0
- data/spec/core/dataset_spec.rb +6 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +10 -0
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/integration/schema_test.rb +30 -1
- data/spec/integration/type_test.rb +10 -3
- data/spec/model/base_spec.rb +44 -0
- data/spec/model/model_spec.rb +14 -0
- data/spec/model/record_spec.rb +131 -12
- metadata +14 -4
data/lib/sequel/version.rb
CHANGED
@@ -3,7 +3,7 @@ module Sequel
|
|
3
3
|
MAJOR = 3
|
4
4
|
# The minor version of Sequel. Bumped for every non-patch level
|
5
5
|
# release, generally around once a month.
|
6
|
-
MINOR =
|
6
|
+
MINOR = 27
|
7
7
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
8
8
|
# releases that fix regressions from previous versions.
|
9
9
|
TINY = 0
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -956,7 +956,7 @@ describe "MySQL::Dataset#calc_found_rows" do
|
|
956
956
|
end
|
957
957
|
end
|
958
958
|
|
959
|
-
if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
|
959
|
+
if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc or MYSQL_DB.adapter_scheme == :mysql2
|
960
960
|
describe "MySQL Stored Procedures" do
|
961
961
|
before do
|
962
962
|
MYSQL_DB.create_table(:items){Integer :id; Integer :value}
|
@@ -977,26 +977,30 @@ if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
|
|
977
977
|
MYSQL_DB[:items].count.should == 0
|
978
978
|
end
|
979
979
|
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
980
|
+
# Mysql2 doesn't support stored procedures that return result sets, probably because
|
981
|
+
# CLIENT_MULTI_RESULTS is not set.
|
982
|
+
unless MYSQL_DB.adapter_scheme == :mysql2
|
983
|
+
specify "should be callable on the dataset object" do
|
984
|
+
MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(a INTEGER) BEGIN SELECT *, a AS b FROM items; END')
|
985
|
+
MYSQL_DB[:items].delete
|
986
|
+
@d = MYSQL_DB[:items]
|
987
|
+
@d.call_sproc(:select, :test_sproc, 3).should == []
|
988
|
+
@d.insert(:value=>1)
|
989
|
+
@d.call_sproc(:select, :test_sproc, 4).should == [{:id=>nil, :value=>1, :b=>4}]
|
990
|
+
@d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
|
991
|
+
@d.call_sproc(:select, :test_sproc, 3).should == [{:id=>nil, :value=>2, :b=>6}]
|
992
|
+
end
|
993
|
+
|
994
|
+
specify "should be callable on the dataset object with multiple arguments" do
|
995
|
+
MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(a INTEGER, c INTEGER) BEGIN SELECT *, a AS b, c AS d FROM items; END')
|
996
|
+
MYSQL_DB[:items].delete
|
997
|
+
@d = MYSQL_DB[:items]
|
998
|
+
@d.call_sproc(:select, :test_sproc, 3, 4).should == []
|
999
|
+
@d.insert(:value=>1)
|
1000
|
+
@d.call_sproc(:select, :test_sproc, 4, 5).should == [{:id=>nil, :value=>1, :b=>4, :d=>5}]
|
1001
|
+
@d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
|
1002
|
+
@d.call_sproc(:select, :test_sproc, 3, 4).should == [{:id=>nil, :value=>2, :b=>6, :d => 8}]
|
1003
|
+
end
|
1000
1004
|
end
|
1001
1005
|
|
1002
1006
|
specify "should deal with nil values" do
|
data/spec/core/database_spec.rb
CHANGED
@@ -1344,6 +1344,206 @@ describe "Database#typecast_value" do
|
|
1344
1344
|
@db.typecast_value(:integer, "0x80").should == 128
|
1345
1345
|
end
|
1346
1346
|
|
1347
|
+
specify "should typecast blobs as as Sequel::SQL::Blob" do
|
1348
|
+
v = @db.typecast_value(:blob, "0x013")
|
1349
|
+
v.should be_a_kind_of(Sequel::SQL::Blob)
|
1350
|
+
v.should == Sequel::SQL::Blob.new("0x013")
|
1351
|
+
@db.typecast_value(:blob, v).object_id.should == v.object_id
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
specify "should typecast boolean values to true, false, or nil" do
|
1355
|
+
@db.typecast_value(:boolean, false).should be_false
|
1356
|
+
@db.typecast_value(:boolean, 0).should be_false
|
1357
|
+
@db.typecast_value(:boolean, "0").should be_false
|
1358
|
+
@db.typecast_value(:boolean, 'f').should be_false
|
1359
|
+
@db.typecast_value(:boolean, 'false').should be_false
|
1360
|
+
@db.typecast_value(:boolean, true).should be_true
|
1361
|
+
@db.typecast_value(:boolean, 1).should be_true
|
1362
|
+
@db.typecast_value(:boolean, '1').should be_true
|
1363
|
+
@db.typecast_value(:boolean, 't').should be_true
|
1364
|
+
@db.typecast_value(:boolean, 'true').should be_true
|
1365
|
+
@db.typecast_value(:boolean, '').should be_nil
|
1366
|
+
end
|
1367
|
+
|
1368
|
+
specify "should typecast date values to Date" do
|
1369
|
+
@db.typecast_value(:date, Date.today).should == Date.today
|
1370
|
+
@db.typecast_value(:date, DateTime.now).should == Date.today
|
1371
|
+
@db.typecast_value(:date, Time.now).should == Date.today
|
1372
|
+
@db.typecast_value(:date, Date.today.to_s).should == Date.today
|
1373
|
+
@db.typecast_value(:date, :year=>Date.today.year, :month=>Date.today.month, :day=>Date.today.day).should == Date.today
|
1374
|
+
end
|
1375
|
+
|
1376
|
+
specify "should typecast datetime values to Sequel.datetime_class with correct timezone handling" do
|
1377
|
+
t = Time.utc(2011, 1, 2, 3, 4, 5) # UTC Time
|
1378
|
+
t2 = Time.mktime(2011, 1, 2, 3, 4, 5) # Local Time
|
1379
|
+
t3 = Time.utc(2011, 1, 2, 3, 4, 5) - (t - t2) # Local Time in UTC Time
|
1380
|
+
t4 = Time.mktime(2011, 1, 2, 3, 4, 5) + (t - t2) # UTC Time in Local Time
|
1381
|
+
dt = DateTime.civil(2011, 1, 2, 3, 4, 5)
|
1382
|
+
r1 = defined?(Rational) ? Rational(t2.utc_offset, 86400) : t2.utc_offset/86400.0
|
1383
|
+
r2 = defined?(Rational) ? Rational((t - t2).to_i, 86400) : (t - t2).to_i/86400.0
|
1384
|
+
dt2 = DateTime.civil(2011, 1, 2, 3, 4, 5, r1)
|
1385
|
+
dt3 = DateTime.civil(2011, 1, 2, 3, 4, 5) - r2
|
1386
|
+
dt4 = DateTime.civil(2011, 1, 2, 3, 4, 5, r1) + r2
|
1387
|
+
|
1388
|
+
t.should == t4
|
1389
|
+
t2.should == t3
|
1390
|
+
dt.should == dt4
|
1391
|
+
dt2.should == dt3
|
1392
|
+
|
1393
|
+
check = proc do |i, o|
|
1394
|
+
v = @db.typecast_value(:datetime, i)
|
1395
|
+
v.should == o
|
1396
|
+
if o.is_a?(Time)
|
1397
|
+
v.utc_offset.should == o.utc_offset
|
1398
|
+
else
|
1399
|
+
v.offset.should == o.offset
|
1400
|
+
end
|
1401
|
+
end
|
1402
|
+
begin
|
1403
|
+
@db.typecast_value(:datetime, dt).should == t
|
1404
|
+
@db.typecast_value(:datetime, dt2).should == t2
|
1405
|
+
@db.typecast_value(:datetime, t).should == t
|
1406
|
+
@db.typecast_value(:datetime, t2).should == t2
|
1407
|
+
@db.typecast_value(:datetime, dt.to_s).should == t
|
1408
|
+
@db.typecast_value(:datetime, dt.strftime('%F %T')).should == t2
|
1409
|
+
@db.typecast_value(:datetime, Date.civil(2011, 1, 2)).should == Time.mktime(2011, 1, 2, 0, 0, 0)
|
1410
|
+
@db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec).should == t2
|
1411
|
+
|
1412
|
+
Sequel.datetime_class = DateTime
|
1413
|
+
@db.typecast_value(:datetime, dt).should == dt
|
1414
|
+
@db.typecast_value(:datetime, dt2).should == dt2
|
1415
|
+
@db.typecast_value(:datetime, t).should == dt
|
1416
|
+
@db.typecast_value(:datetime, t2).should == dt2
|
1417
|
+
@db.typecast_value(:datetime, dt.to_s).should == dt
|
1418
|
+
@db.typecast_value(:datetime, dt.strftime('%F %T')).should == dt
|
1419
|
+
@db.typecast_value(:datetime, Date.civil(2011, 1, 2)).should == DateTime.civil(2011, 1, 2, 0, 0, 0)
|
1420
|
+
@db.typecast_value(:datetime, :year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec).should == dt
|
1421
|
+
|
1422
|
+
Sequel.application_timezone = :utc
|
1423
|
+
Sequel.typecast_timezone = :local
|
1424
|
+
Sequel.datetime_class = Time
|
1425
|
+
check[dt, t]
|
1426
|
+
check[dt2, t3]
|
1427
|
+
check[t, t]
|
1428
|
+
check[t2, t3]
|
1429
|
+
check[dt.to_s, t]
|
1430
|
+
check[dt.strftime('%F %T'), t3]
|
1431
|
+
check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
|
1432
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t3]
|
1433
|
+
|
1434
|
+
Sequel.datetime_class = DateTime
|
1435
|
+
check[dt, dt]
|
1436
|
+
check[dt2, dt3]
|
1437
|
+
check[t, dt]
|
1438
|
+
check[t2, dt3]
|
1439
|
+
check[dt.to_s, dt]
|
1440
|
+
check[dt.strftime('%F %T'), dt3]
|
1441
|
+
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
|
1442
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt3]
|
1443
|
+
|
1444
|
+
Sequel.typecast_timezone = :utc
|
1445
|
+
Sequel.datetime_class = Time
|
1446
|
+
check[dt, t]
|
1447
|
+
check[dt2, t3]
|
1448
|
+
check[t, t]
|
1449
|
+
check[t2, t3]
|
1450
|
+
check[dt.to_s, t]
|
1451
|
+
check[dt.strftime('%F %T'), t]
|
1452
|
+
check[Date.civil(2011, 1, 2), Time.utc(2011, 1, 2, 0, 0, 0)]
|
1453
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t]
|
1454
|
+
|
1455
|
+
Sequel.datetime_class = DateTime
|
1456
|
+
check[dt, dt]
|
1457
|
+
check[dt2, dt3]
|
1458
|
+
check[t, dt]
|
1459
|
+
check[t2, dt3]
|
1460
|
+
check[dt.to_s, dt]
|
1461
|
+
check[dt.strftime('%F %T'), dt]
|
1462
|
+
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0)]
|
1463
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt]
|
1464
|
+
|
1465
|
+
Sequel.application_timezone = :local
|
1466
|
+
Sequel.datetime_class = Time
|
1467
|
+
check[dt, t4]
|
1468
|
+
check[dt2, t2]
|
1469
|
+
check[t, t4]
|
1470
|
+
check[t2, t2]
|
1471
|
+
check[dt.to_s, t4]
|
1472
|
+
check[dt.strftime('%F %T'), t4]
|
1473
|
+
check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
|
1474
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t4]
|
1475
|
+
|
1476
|
+
Sequel.datetime_class = DateTime
|
1477
|
+
check[dt, dt4]
|
1478
|
+
check[dt2, dt2]
|
1479
|
+
check[t, dt4]
|
1480
|
+
check[t2, dt2]
|
1481
|
+
check[dt.to_s, dt4]
|
1482
|
+
check[dt.strftime('%F %T'), dt4]
|
1483
|
+
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
|
1484
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt4]
|
1485
|
+
|
1486
|
+
Sequel.typecast_timezone = :local
|
1487
|
+
Sequel.datetime_class = Time
|
1488
|
+
check[dt, t4]
|
1489
|
+
check[dt2, t2]
|
1490
|
+
check[t, t4]
|
1491
|
+
check[t2, t2]
|
1492
|
+
check[dt.to_s, t4]
|
1493
|
+
check[dt.strftime('%F %T'), t2]
|
1494
|
+
check[Date.civil(2011, 1, 2), Time.local(2011, 1, 2, 0, 0, 0)]
|
1495
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, t2]
|
1496
|
+
|
1497
|
+
Sequel.datetime_class = DateTime
|
1498
|
+
check[dt, dt4]
|
1499
|
+
check[dt2, dt2]
|
1500
|
+
check[t, dt4]
|
1501
|
+
check[t2, dt2]
|
1502
|
+
check[dt.to_s, dt4]
|
1503
|
+
check[dt.strftime('%F %T'), dt2]
|
1504
|
+
check[Date.civil(2011, 1, 2), DateTime.civil(2011, 1, 2, 0, 0, 0, r1)]
|
1505
|
+
check[{:year=>dt.year, :month=>dt.month, :day=>dt.day, :hour=>dt.hour, :minute=>dt.min, :second=>dt.sec}, dt2]
|
1506
|
+
|
1507
|
+
ensure
|
1508
|
+
Sequel.default_timezone = nil
|
1509
|
+
Sequel.datetime_class = Time
|
1510
|
+
end
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
specify "should typecast decimal values to BigDecimal" do
|
1514
|
+
[1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
|
1515
|
+
v = @db.typecast_value(:decimal, i)
|
1516
|
+
v.should be_a_kind_of(BigDecimal)
|
1517
|
+
v.should == BigDecimal.new('1.0')
|
1518
|
+
end
|
1519
|
+
end
|
1520
|
+
|
1521
|
+
specify "should typecast float values to Float" do
|
1522
|
+
[1.0, 1, '1.0', BigDecimal('1.0')].each do |i|
|
1523
|
+
v = @db.typecast_value(:float, i)
|
1524
|
+
v.should be_a_kind_of(Float)
|
1525
|
+
v.should == 1.0
|
1526
|
+
end
|
1527
|
+
end
|
1528
|
+
|
1529
|
+
specify "should typecast string values to String" do
|
1530
|
+
[1.0, '1.0', '1.0'.to_sequel_blob].each do |i|
|
1531
|
+
v = @db.typecast_value(:string, i)
|
1532
|
+
v.should be_an_instance_of(String)
|
1533
|
+
v.should == "1.0"
|
1534
|
+
end
|
1535
|
+
end
|
1536
|
+
|
1537
|
+
specify "should typecast time values to SQLTime" do
|
1538
|
+
t = Time.now
|
1539
|
+
st = Sequel::SQLTime.local(t.year, t.month, t.day, 1, 2, 3)
|
1540
|
+
[st, Time.utc(t.year, t.month, t.day, 1, 2, 3), Time.local(t.year, t.month, t.day, 1, 2, 3), '01:02:03', {:hour=>1, :minute=>2, :second=>3}].each do |i|
|
1541
|
+
v = @db.typecast_value(:time, i)
|
1542
|
+
v.should be_an_instance_of(Sequel::SQLTime)
|
1543
|
+
v.should == st
|
1544
|
+
end
|
1545
|
+
end
|
1546
|
+
|
1347
1547
|
specify "should have an underlying exception class available at wrapped_exception" do
|
1348
1548
|
begin
|
1349
1549
|
@db.typecast_value(:date, 'a')
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -1020,6 +1020,12 @@ describe "Dataset#literal" do
|
|
1020
1020
|
d.literal(d).should == "(#{d.sql})"
|
1021
1021
|
end
|
1022
1022
|
|
1023
|
+
specify "should literalize Sequel::SQLTime properly" do
|
1024
|
+
t = Sequel::SQLTime.now
|
1025
|
+
s = t.strftime("'%H:%M:%S")
|
1026
|
+
@dataset.literal(t).should == "#{s}.#{sprintf('%06i', t.usec)}'"
|
1027
|
+
end
|
1028
|
+
|
1023
1029
|
specify "should literalize Time properly" do
|
1024
1030
|
t = Time.now
|
1025
1031
|
s = t.strftime("'%Y-%m-%d %H:%M:%S")
|
@@ -66,4 +66,14 @@ describe "prepared_statements_safe plugin" do
|
|
66
66
|
@p.update(:i=>3)
|
67
67
|
@sqls[1].should =~ /UPDATE people SET (name = 'foo'|i = 3), (name = 'foo'|i = 3) WHERE \(id = 1\)/
|
68
68
|
end
|
69
|
+
|
70
|
+
specify "should work with abstract classes" do
|
71
|
+
c = Class.new(Sequel::Model)
|
72
|
+
c.plugin :prepared_statements_safe
|
73
|
+
c1 = Class.new(c)
|
74
|
+
c1.meta_def(:get_db_schema){@db_schema = {:i=>{:default=>'f(x)'}, :name=>{:ruby_default=>'foo'}, :id=>{:primary_key=>true}}}
|
75
|
+
c1.set_dataset(:people)
|
76
|
+
c1.prepared_statements_column_defaults.should == {:name=>'foo'}
|
77
|
+
Class.new(c1).prepared_statements_column_defaults.should == {:name=>'foo'}
|
78
|
+
end
|
69
79
|
end
|
@@ -263,8 +263,8 @@ END_MIG
|
|
263
263
|
s.each{|_, c| c[:ruby_default] = column_schema_to_ruby_default(c[:default], c[:type])}
|
264
264
|
s
|
265
265
|
end
|
266
|
-
@d.dump_table_schema(:t4).gsub(/[+-]\d\d:\d\d"\)/, '")').should == "create_table(:t4) do\n TrueClass :c1, :default=>false\n String :c2, :default=>\"blah\"\n Integer :c3, :default=>-1\n Float :c4, :default=>1.0\n BigDecimal :c5, :default=>BigDecimal.new(\"0.1005E3\")\n File :c6, :default=>Sequel::SQL::Blob.new(\"blah\")\n Date :c7, :default=>Date.parse(\"2008-10-29\")\n DateTime :c8, :default=>DateTime.parse(\"2008-10-29T10:20:30\")\n Time :c9, :default=>
|
267
|
-
@d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d:\d\d"\)/, '")').should == "create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>BigDecimal.new(\"0.1005E3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.parse(\"2008-10-29\")\n column :c8, \"datetime\", :default=>DateTime.parse(\"2008-10-29T10:20:30\")\n column :c9, \"time\", :default=>
|
266
|
+
@d.dump_table_schema(:t4).gsub(/[+-]\d\d:\d\d"\)/, '")').should == "create_table(:t4) do\n TrueClass :c1, :default=>false\n String :c2, :default=>\"blah\"\n Integer :c3, :default=>-1\n Float :c4, :default=>1.0\n BigDecimal :c5, :default=>BigDecimal.new(\"0.1005E3\")\n File :c6, :default=>Sequel::SQL::Blob.new(\"blah\")\n Date :c7, :default=>Date.parse(\"2008-10-29\")\n DateTime :c8, :default=>DateTime.parse(\"2008-10-29T10:20:30\")\n Time :c9, :default=>Sequel::SQLTime.parse(\"10:20:30\"), :only_time=>true\n String :c10\nend"
|
267
|
+
@d.dump_table_schema(:t4, :same_db=>true).gsub(/[+-]\d\d:\d\d"\)/, '")').should == "create_table(:t4) do\n column :c1, \"boolean\", :default=>false\n column :c2, \"varchar\", :default=>\"blah\"\n column :c3, \"integer\", :default=>-1\n column :c4, \"float\", :default=>1.0\n column :c5, \"decimal\", :default=>BigDecimal.new(\"0.1005E3\")\n column :c6, \"blob\", :default=>Sequel::SQL::Blob.new(\"blah\")\n column :c7, \"date\", :default=>Date.parse(\"2008-10-29\")\n column :c8, \"datetime\", :default=>DateTime.parse(\"2008-10-29T10:20:30\")\n column :c9, \"time\", :default=>Sequel::SQLTime.parse(\"10:20:30\")\n column :c10, \"interval\", :default=>\"'6 weeks'\".lit\nend"
|
268
268
|
end
|
269
269
|
|
270
270
|
it "should not use a '...'.lit as a fallback if using MySQL with the :same_db option" do
|
@@ -246,6 +246,15 @@ describe "Database schema modifiers" do
|
|
246
246
|
@db.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :id]
|
247
247
|
@ds.columns!.should == [:number, :id]
|
248
248
|
@ds.map(:number).should == [10]
|
249
|
+
proc{@ds.insert(:id=>@ds.map(:id).first)}.should raise_error
|
250
|
+
end
|
251
|
+
|
252
|
+
cspecify "should drop primary key constraints from tables correctly", :sqlite do
|
253
|
+
@db.create_table!(:items){Integer :number; primary_key [:number], :name=>:items_pk}
|
254
|
+
@ds.insert(:number=>10)
|
255
|
+
@db.alter_table(:items){drop_constraint :items_pk, :type=>:primary_key}
|
256
|
+
@ds.map(:number).should == [10]
|
257
|
+
proc{@ds.insert(10)}.should_not raise_error
|
249
258
|
end
|
250
259
|
|
251
260
|
specify "should add foreign key columns to tables correctly" do
|
@@ -320,13 +329,33 @@ describe "Database schema modifiers" do
|
|
320
329
|
end
|
321
330
|
|
322
331
|
cspecify "should add unique constraints and foreign key table constraints correctly", :sqlite do
|
323
|
-
@db.create_table!(:items){Integer :id; Integer :item_id}
|
332
|
+
@db.create_table!(:items, :engine=>:InnoDB){Integer :id; Integer :item_id}
|
324
333
|
@db.alter_table(:items) do
|
325
334
|
add_unique_constraint [:item_id, :id]
|
326
335
|
add_foreign_key [:id, :item_id], :items, :key=>[:item_id, :id]
|
327
336
|
end
|
328
337
|
@db.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :item_id]
|
329
338
|
@ds.columns!.should == [:id, :item_id]
|
339
|
+
proc{@ds.insert(1, 1)}.should_not raise_error
|
340
|
+
proc{@ds.insert(1, 1)}.should raise_error
|
341
|
+
proc{@ds.insert(1, 2)}.should raise_error
|
342
|
+
end
|
343
|
+
|
344
|
+
cspecify "should drop unique constraints and foreign key table constraints correctly", :sqlite do
|
345
|
+
@db.create_table!(:items) do
|
346
|
+
Integer :id
|
347
|
+
Integer :item_id
|
348
|
+
unique [:item_id, :id], :name=>:items_uk
|
349
|
+
foreign_key [:id, :item_id], :items, :key=>[:item_id, :id], :name=>:items_fk
|
350
|
+
end
|
351
|
+
@db.alter_table(:items) do
|
352
|
+
drop_constraint(:items_fk, :type=>:foreign_key)
|
353
|
+
drop_constraint(:items_uk, :type=>:unique)
|
354
|
+
end
|
355
|
+
@db.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :item_id]
|
356
|
+
@ds.columns!.should == [:id, :item_id]
|
357
|
+
proc{@ds.insert(1, 2)}.should_not raise_error
|
358
|
+
proc{@ds.insert(1, 2)}.should_not raise_error
|
330
359
|
end
|
331
360
|
|
332
361
|
cspecify "should remove columns from tables correctly", :h2, :mssql do
|
@@ -68,11 +68,18 @@ describe "Supported types" do
|
|
68
68
|
ds.first[:dat].to_s.should == d.to_s
|
69
69
|
end
|
70
70
|
|
71
|
-
cspecify "should support generic time type", [:do], [:swift], [:odbc], [:jdbc, :mssql], [:tinytds] do
|
71
|
+
cspecify "should support generic time type", [:do], [:swift], [:odbc], [:jdbc, :mssql], [:jdbc, :postgres], [:mysql2], [:tinytds] do
|
72
72
|
ds = create_items_table_with_column(:tim, Time, :only_time=>true)
|
73
|
-
t =
|
73
|
+
t = Sequel::SQLTime.now
|
74
74
|
ds.insert(:tim => t)
|
75
|
-
ds.first[:tim]
|
75
|
+
v = ds.first[:tim]
|
76
|
+
ds.literal(v).should == ds.literal(t)
|
77
|
+
v.should be_a_kind_of(Sequel::SQLTime)
|
78
|
+
ds.delete
|
79
|
+
ds.insert(:tim => v)
|
80
|
+
v2 = ds.first[:tim]
|
81
|
+
ds.literal(v2).should == ds.literal(t)
|
82
|
+
v2.should be_a_kind_of(Sequel::SQLTime)
|
76
83
|
end
|
77
84
|
|
78
85
|
cspecify "should support generic datetime type", [:do, :sqlite], [:jdbc, :sqlite] do
|
data/spec/model/base_spec.rb
CHANGED
@@ -131,6 +131,50 @@ describe Sequel::Model, ".def_dataset_method" do
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
+
describe Sequel::Model, ".dataset_module" do
|
135
|
+
before do
|
136
|
+
@c = Class.new(Sequel::Model(:items))
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should extend the dataset with the module if the model has a dataset" do
|
140
|
+
@c.instance_eval{dataset_module{def return_3() 3 end}}
|
141
|
+
@c.dataset.return_3.should == 3
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should add methods defined in the module to the class" do
|
145
|
+
@c.instance_eval{dataset_module{def return_3() 3 end}}
|
146
|
+
@c.return_3.should == 3
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should cache calls and readd methods if set_dataset is used" do
|
150
|
+
@c.instance_eval{dataset_module{def return_3() 3 end}}
|
151
|
+
@c.set_dataset :items
|
152
|
+
@c.return_3.should == 3
|
153
|
+
@c.dataset.return_3.should == 3
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should readd methods to subclasses, if set_dataset is used in a subclass" do
|
157
|
+
@c.instance_eval{dataset_module{def return_3() 3 end}}
|
158
|
+
c = Class.new(@c)
|
159
|
+
c.set_dataset :items
|
160
|
+
c.return_3.should == 3
|
161
|
+
c.dataset.return_3.should == 3
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should only have a single dataset_module per class" do
|
165
|
+
@c.instance_eval{dataset_module{def return_3() 3 end}}
|
166
|
+
@c.instance_eval{dataset_module{def return_3() 3 + (begin; super; rescue NoMethodError; 1; end) end}}
|
167
|
+
@c.return_3.should == 4
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should not have subclasses share the dataset_module" do
|
171
|
+
@c.instance_eval{dataset_module{def return_3() 3 end}}
|
172
|
+
c = Class.new(@c)
|
173
|
+
c.instance_eval{dataset_module{def return_3() 3 + (begin; super; rescue NoMethodError; 1; end) end}}
|
174
|
+
c.return_3.should == 6
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
134
178
|
describe "A model class with implicit table name" do
|
135
179
|
before do
|
136
180
|
class Donkey < Sequel::Model
|
data/spec/model/model_spec.rb
CHANGED
@@ -40,6 +40,13 @@ describe "Sequel::Model()" do
|
|
40
40
|
c.table_name.should == :boo
|
41
41
|
end
|
42
42
|
|
43
|
+
it "should return a model subclass with the given dataset if given a dataset using an SQL::Identifier" do
|
44
|
+
ds = @db[:blah.identifier]
|
45
|
+
c = Sequel::Model(ds)
|
46
|
+
c.superclass.should == Sequel::Model
|
47
|
+
c.dataset.should == ds
|
48
|
+
end
|
49
|
+
|
43
50
|
it "should return a model subclass associated to the given database if given a database" do
|
44
51
|
db = Sequel::Database.new
|
45
52
|
c = Sequel::Model(db)
|
@@ -98,6 +105,13 @@ describe "Sequel::Model()" do
|
|
98
105
|
class ::Album < Sequel::Model(@db[:table]); end
|
99
106
|
end.should_not raise_error
|
100
107
|
end
|
108
|
+
|
109
|
+
it "should work without raising an exception with a dataset with an SQL::Identifier" do
|
110
|
+
proc do
|
111
|
+
class ::Album < Sequel::Model(@db[:table.identifier]); end
|
112
|
+
class ::Album < Sequel::Model(@db[:table.identifier]); end
|
113
|
+
end.should_not raise_error
|
114
|
+
end
|
101
115
|
end
|
102
116
|
end
|
103
117
|
|