sequel 3.26.0 → 3.27.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|