sequel 0.2.0.2 → 0.2.1
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 +64 -0
- data/Rakefile +41 -1
- data/lib/sequel.rb +37 -37
- data/lib/sequel/core_ext.rb +3 -3
- data/lib/sequel/database.rb +8 -2
- data/lib/sequel/dataset.rb +103 -42
- data/lib/sequel/dataset/convenience.rb +46 -0
- data/lib/sequel/dataset/sequelizer.rb +34 -8
- data/lib/sequel/dataset/sql.rb +12 -8
- data/lib/sequel/model.rb +13 -237
- data/lib/sequel/model/base.rb +84 -0
- data/lib/sequel/model/hooks.rb +40 -0
- data/lib/sequel/model/record.rb +154 -0
- data/lib/sequel/model/relations.rb +26 -0
- data/lib/sequel/model/schema.rb +36 -0
- data/lib/sequel/mysql.rb +9 -7
- data/lib/sequel/postgres.rb +5 -4
- data/lib/sequel/schema/schema_generator.rb +1 -0
- data/lib/sequel/sqlite.rb +2 -2
- data/spec/core_ext_spec.rb +14 -0
- data/spec/database_spec.rb +12 -1
- data/spec/dataset_spec.rb +274 -0
- data/spec/model_spec.rb +286 -3
- data/spec/sequelizer_spec.rb +49 -9
- data/spec/spec_helper.rb +27 -5
- metadata +8 -2
data/spec/core_ext_spec.rb
CHANGED
@@ -136,6 +136,20 @@ context "Symbol#to_field_name" do
|
|
136
136
|
:xyz___x.to_field_name.should == 'xyz AS x'
|
137
137
|
:abc__def___x.to_field_name.should == 'abc.def AS x'
|
138
138
|
end
|
139
|
+
|
140
|
+
specify "should support names with digits" do
|
141
|
+
:abc2.to_field_name.should == 'abc2'
|
142
|
+
:xx__yy3.to_field_name.should == 'xx.yy3'
|
143
|
+
:ab34__temp3_4ax.to_field_name.should == 'ab34.temp3_4ax'
|
144
|
+
:x1___y2.to_field_name.should == 'x1 AS y2'
|
145
|
+
:abc2__def3___ggg4.to_field_name.should == 'abc2.def3 AS ggg4'
|
146
|
+
end
|
147
|
+
|
148
|
+
specify "should support upper case and lower case" do
|
149
|
+
:ABC.to_field_name.should == 'ABC'
|
150
|
+
:Zvashtoy__aBcD.to_field_name.should == 'Zvashtoy.aBcD'
|
151
|
+
|
152
|
+
end
|
139
153
|
end
|
140
154
|
|
141
155
|
context "FieldCompositionMethods#field_title" do
|
data/spec/database_spec.rb
CHANGED
@@ -476,6 +476,17 @@ context "A database" do
|
|
476
476
|
db = Sequel::Database.new(:max_options => 4)
|
477
477
|
db.should be_single_threaded
|
478
478
|
db.should_not be_multi_threaded
|
479
|
-
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
context "Database#dataset" do
|
483
|
+
setup do
|
484
|
+
@db = Sequel::Database.new
|
485
|
+
end
|
486
|
+
|
487
|
+
specify "should delegate to Dataset#query if block is provided" do
|
488
|
+
@d = @db.query {select :x; from :y}
|
489
|
+
@d.should be_a_kind_of(Sequel::Dataset)
|
490
|
+
@d.sql.should == "SELECT x FROM y"
|
480
491
|
end
|
481
492
|
end
|
data/spec/dataset_spec.rb
CHANGED
@@ -446,6 +446,24 @@ context "a grouped dataset" do
|
|
446
446
|
end
|
447
447
|
end
|
448
448
|
|
449
|
+
context "Dataset#group_by" do
|
450
|
+
setup do
|
451
|
+
@dataset = Sequel::Dataset.new(nil).from(:test).group_by(:type_id)
|
452
|
+
end
|
453
|
+
|
454
|
+
specify "should raise when trying to generate an update statement" do
|
455
|
+
proc {@dataset.update_sql(:id => 0)}.should raise_error
|
456
|
+
end
|
457
|
+
|
458
|
+
specify "should raise when trying to generate a delete statement" do
|
459
|
+
proc {@dataset.delete_sql}.should raise_error
|
460
|
+
end
|
461
|
+
|
462
|
+
specify "should specify the grouping in generated select statement" do
|
463
|
+
@dataset.select_sql.should ==
|
464
|
+
"SELECT * FROM test GROUP BY type_id"
|
465
|
+
end
|
466
|
+
end
|
449
467
|
|
450
468
|
context "Dataset#literal" do
|
451
469
|
setup do
|
@@ -600,6 +618,32 @@ context "Dataset#order" do
|
|
600
618
|
end
|
601
619
|
end
|
602
620
|
|
621
|
+
context "Dataset#order_by" do
|
622
|
+
setup do
|
623
|
+
@dataset = Sequel::Dataset.new(nil).from(:test)
|
624
|
+
end
|
625
|
+
|
626
|
+
specify "should include an ORDER BY clause in the select statement" do
|
627
|
+
@dataset.order_by(:name).sql.should ==
|
628
|
+
'SELECT * FROM test ORDER BY name'
|
629
|
+
end
|
630
|
+
|
631
|
+
specify "should accept multiple arguments" do
|
632
|
+
@dataset.order_by(:name, :price.DESC).sql.should ==
|
633
|
+
'SELECT * FROM test ORDER BY name, price DESC'
|
634
|
+
end
|
635
|
+
|
636
|
+
specify "should overrun a previous ordering" do
|
637
|
+
@dataset.order_by(:name).order(:stamp).sql.should ==
|
638
|
+
'SELECT * FROM test ORDER BY stamp'
|
639
|
+
end
|
640
|
+
|
641
|
+
specify "should accept a string" do
|
642
|
+
@dataset.order_by('dada ASC').sql.should ==
|
643
|
+
'SELECT * FROM test ORDER BY dada ASC'
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
603
647
|
context "Dataset#reverse_order" do
|
604
648
|
setup do
|
605
649
|
@dataset = Sequel::Dataset.new(nil).from(:test)
|
@@ -769,6 +813,26 @@ context "Dataset#count" do
|
|
769
813
|
end
|
770
814
|
end
|
771
815
|
|
816
|
+
context "Dataset#empty?" do
|
817
|
+
specify "should return true if #count == 0" do
|
818
|
+
@c = Class.new(Sequel::Dataset) do
|
819
|
+
def count
|
820
|
+
0
|
821
|
+
end
|
822
|
+
end
|
823
|
+
@dataset = @c.new(nil).from(:test)
|
824
|
+
@dataset.empty?.should be_true
|
825
|
+
|
826
|
+
@c = Class.new(Sequel::Dataset) do
|
827
|
+
def count
|
828
|
+
1
|
829
|
+
end
|
830
|
+
end
|
831
|
+
@dataset = @c.new(nil).from(:test)
|
832
|
+
@dataset.empty?.should be_false
|
833
|
+
end
|
834
|
+
end
|
835
|
+
|
772
836
|
context "Dataset#join_table" do
|
773
837
|
setup do
|
774
838
|
@d = Sequel::Dataset.new(nil).from(:items)
|
@@ -1157,6 +1221,33 @@ context "Dataset#single_value" do
|
|
1157
1221
|
end
|
1158
1222
|
end
|
1159
1223
|
|
1224
|
+
context "Dataset#set_row_proc" do
|
1225
|
+
setup do
|
1226
|
+
@c = Class.new(Sequel::Dataset) do
|
1227
|
+
def fetch_rows(sql, &block)
|
1228
|
+
# yield a hash with kind as the 1 bit of a number
|
1229
|
+
(1..10).each {|i| block.call({:kind => i[0]})}
|
1230
|
+
end
|
1231
|
+
end
|
1232
|
+
@dataset = @c.new(nil).from(:items)
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
specify "should cause dataset to pass all rows through the filter" do
|
1236
|
+
@dataset.set_row_proc {|h| h[:der] = h[:kind] + 2; h}
|
1237
|
+
|
1238
|
+
rows = @dataset.all
|
1239
|
+
rows.size.should == 10
|
1240
|
+
|
1241
|
+
rows.each {|r| r[:der].should == (r[:kind] + 2)}
|
1242
|
+
end
|
1243
|
+
|
1244
|
+
specify "should be copied over when dataset is cloned" do
|
1245
|
+
@dataset.set_row_proc {|h| h[:der] = h[:kind] + 2; h}
|
1246
|
+
|
1247
|
+
@dataset.filter(:a => 1).first.should == {:kind => 1, :der => 3}
|
1248
|
+
end
|
1249
|
+
end
|
1250
|
+
|
1160
1251
|
context "Dataset#set_model" do
|
1161
1252
|
setup do
|
1162
1253
|
@c = Class.new(Sequel::Dataset) do
|
@@ -1570,4 +1661,187 @@ context "Dataset#multi_insert" do
|
|
1570
1661
|
'COMMIT;'
|
1571
1662
|
]
|
1572
1663
|
end
|
1664
|
+
end
|
1665
|
+
|
1666
|
+
context "Dataset#query" do
|
1667
|
+
setup do
|
1668
|
+
@d = Sequel::Dataset.new(nil)
|
1669
|
+
end
|
1670
|
+
|
1671
|
+
specify "should support #from" do
|
1672
|
+
q = @d.query {from :xxx}
|
1673
|
+
q.class.should == @d.class
|
1674
|
+
q.sql.should == "SELECT * FROM xxx"
|
1675
|
+
end
|
1676
|
+
|
1677
|
+
specify "should support #select" do
|
1678
|
+
q = @d.query do
|
1679
|
+
select :a, :b___mongo
|
1680
|
+
from :yyy
|
1681
|
+
end
|
1682
|
+
q.class.should == @d.class
|
1683
|
+
q.sql.should == "SELECT a, b AS mongo FROM yyy"
|
1684
|
+
end
|
1685
|
+
|
1686
|
+
specify "should support #where" do
|
1687
|
+
q = @d.query do
|
1688
|
+
from :zzz
|
1689
|
+
where {:x + 2 > :y + 3}
|
1690
|
+
end
|
1691
|
+
q.class.should == @d.class
|
1692
|
+
q.sql.should == "SELECT * FROM zzz WHERE ((x + 2) > (y + 3))"
|
1693
|
+
|
1694
|
+
q = @d.from(:zzz).query do
|
1695
|
+
where {:x > 1 && :y > 2}
|
1696
|
+
end
|
1697
|
+
q.class.should == @d.class
|
1698
|
+
q.sql.should == "SELECT * FROM zzz WHERE ((x > 1) AND (y > 2))"
|
1699
|
+
|
1700
|
+
q = @d.from(:zzz).query do
|
1701
|
+
where :x => 33
|
1702
|
+
end
|
1703
|
+
q.class.should == @d.class
|
1704
|
+
q.sql.should == "SELECT * FROM zzz WHERE (x = 33)"
|
1705
|
+
end
|
1706
|
+
|
1707
|
+
specify "should support #group_by and #having" do
|
1708
|
+
q = @d.query do
|
1709
|
+
from :abc
|
1710
|
+
group_by :id
|
1711
|
+
having {:x >= 2}
|
1712
|
+
end
|
1713
|
+
q.class.should == @d.class
|
1714
|
+
q.sql.should == "SELECT * FROM abc GROUP BY id HAVING (x >= 2)"
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
specify "should support #order, #order_by" do
|
1718
|
+
q = @d.query do
|
1719
|
+
from :xyz
|
1720
|
+
order_by :stamp
|
1721
|
+
end
|
1722
|
+
q.class.should == @d.class
|
1723
|
+
q.sql.should == "SELECT * FROM xyz ORDER BY stamp"
|
1724
|
+
end
|
1725
|
+
|
1726
|
+
specify "should raise on non-chainable method calls" do
|
1727
|
+
proc {@d.query {count}}.should raise_error(SequelError)
|
1728
|
+
end
|
1729
|
+
|
1730
|
+
specify "should raise on each, insert, update, delete" do
|
1731
|
+
proc {@d.query {each}}.should raise_error(SequelError)
|
1732
|
+
proc {@d.query {insert(:x => 1)}}.should raise_error(SequelError)
|
1733
|
+
proc {@d.query {update(:x => 1)}}.should raise_error(SequelError)
|
1734
|
+
proc {@d.query {delete}}.should raise_error(SequelError)
|
1735
|
+
end
|
1736
|
+
end
|
1737
|
+
|
1738
|
+
context "Dataset" do
|
1739
|
+
setup do
|
1740
|
+
@d = Sequel::Dataset.new(nil).from(:x)
|
1741
|
+
end
|
1742
|
+
|
1743
|
+
specify "should support self-changing select!" do
|
1744
|
+
@d.select!(:y)
|
1745
|
+
@d.sql.should == "SELECT y FROM x"
|
1746
|
+
end
|
1747
|
+
|
1748
|
+
specify "should support self-changing from!" do
|
1749
|
+
@d.from!(:y)
|
1750
|
+
@d.sql.should == "SELECT * FROM y"
|
1751
|
+
end
|
1752
|
+
|
1753
|
+
specify "should support self-changing order!" do
|
1754
|
+
@d.order!(:y)
|
1755
|
+
@d.sql.should == "SELECT * FROM x ORDER BY y"
|
1756
|
+
end
|
1757
|
+
|
1758
|
+
specify "should support self-changing filter!" do
|
1759
|
+
@d.filter!(:y => 1)
|
1760
|
+
@d.sql.should == "SELECT * FROM x WHERE (y = 1)"
|
1761
|
+
end
|
1762
|
+
|
1763
|
+
specify "should support self-changing filter! with block" do
|
1764
|
+
@d.filter! {:y == 2}
|
1765
|
+
@d.sql.should == "SELECT * FROM x WHERE (y = 2)"
|
1766
|
+
end
|
1767
|
+
|
1768
|
+
specify "should raise for ! methods that don't return a dataset" do
|
1769
|
+
proc {@d.opts!}.should raise_error(NameError)
|
1770
|
+
end
|
1771
|
+
|
1772
|
+
specify "should raise for missing methods" do
|
1773
|
+
proc {@d.xuyz}.should raise_error(NameError)
|
1774
|
+
proc {@d.xyz!}.should raise_error(NameError)
|
1775
|
+
proc {@d.xyz?}.should raise_error(NameError)
|
1776
|
+
end
|
1777
|
+
|
1778
|
+
specify "should support chaining of bang methods" do
|
1779
|
+
@d.order!(:y)
|
1780
|
+
@d.filter!(:y => 1)
|
1781
|
+
@d.sql.should == "SELECT * FROM x WHERE (y = 1) ORDER BY y"
|
1782
|
+
end
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
context "Dataset#transform" do
|
1786
|
+
setup do
|
1787
|
+
@c = Class.new(Sequel::Dataset) do
|
1788
|
+
attr_accessor :raw
|
1789
|
+
attr_accessor :sql
|
1790
|
+
|
1791
|
+
def fetch_rows(sql, &block)
|
1792
|
+
block[@raw]
|
1793
|
+
end
|
1794
|
+
|
1795
|
+
def insert(v)
|
1796
|
+
@sql = insert_sql(v)
|
1797
|
+
end
|
1798
|
+
|
1799
|
+
def update(v)
|
1800
|
+
@sql = update_sql(v)
|
1801
|
+
end
|
1802
|
+
end
|
1803
|
+
|
1804
|
+
@ds = @c.new(nil).from(:items)
|
1805
|
+
@ds.transform(:x => [
|
1806
|
+
proc {|v| Marshal.load(v)},
|
1807
|
+
proc {|v| Marshal.dump(v)}
|
1808
|
+
])
|
1809
|
+
end
|
1810
|
+
|
1811
|
+
specify "should change the dataset to transform values loaded from the database" do
|
1812
|
+
@ds.raw = {:x => Marshal.dump([1, 2, 3]), :y => 'hello'}
|
1813
|
+
@ds.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
1814
|
+
end
|
1815
|
+
|
1816
|
+
specify "should change the dataset to transform values saved to the database" do
|
1817
|
+
@ds.insert(:x => :toast)
|
1818
|
+
@ds.sql.should == "INSERT INTO items (x) VALUES ('#{Marshal.dump(:toast)}');"
|
1819
|
+
|
1820
|
+
@ds.insert(:y => 'butter')
|
1821
|
+
@ds.sql.should == "INSERT INTO items (y) VALUES ('butter');"
|
1822
|
+
|
1823
|
+
@ds.update(:x => ['dream'])
|
1824
|
+
@ds.sql.should == "UPDATE items SET x = '#{Marshal.dump(['dream'])}'"
|
1825
|
+
end
|
1826
|
+
|
1827
|
+
specify "should be transferred to cloned datasets" do
|
1828
|
+
@ds2 = @ds.filter(:a => 1)
|
1829
|
+
|
1830
|
+
@ds2.raw = {:x => Marshal.dump([1, 2, 3]), :y => 'hello'}
|
1831
|
+
@ds2.first.should == {:x => [1, 2, 3], :y => 'hello'}
|
1832
|
+
|
1833
|
+
@ds2.insert(:x => :toast)
|
1834
|
+
@ds2.sql.should == "INSERT INTO items (x) VALUES ('#{Marshal.dump(:toast)}');"
|
1835
|
+
end
|
1836
|
+
|
1837
|
+
specify "should work correctly together with set_row_proc" do
|
1838
|
+
@ds.set_row_proc {|r| r[:z] = r[:x] * 2; r}
|
1839
|
+
@ds.raw = {:x => Marshal.dump("wow"), :y => 'hello'}
|
1840
|
+
@ds.first.should == {:x => "wow", :y => 'hello', :z => "wowwow"}
|
1841
|
+
|
1842
|
+
f = nil
|
1843
|
+
@ds.raw = {:x => Marshal.dump("wow"), :y => 'hello'}
|
1844
|
+
@ds.each(:naked => true) {|r| f = r}
|
1845
|
+
f.should == {:x => "wow", :y => 'hello'}
|
1846
|
+
end
|
1573
1847
|
end
|
data/spec/model_spec.rb
CHANGED
@@ -1,6 +1,132 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
2
|
|
3
|
-
Sequel::Model.db =
|
3
|
+
Sequel::Model.db = MODEL_DB = MockDatabase.new
|
4
|
+
|
5
|
+
context "A model class" do
|
6
|
+
specify "should be associated with a dataset" do
|
7
|
+
@m = Class.new(Sequel::Model) do
|
8
|
+
set_dataset MODEL_DB[:items]
|
9
|
+
end
|
10
|
+
|
11
|
+
@m.dataset.should be_a_kind_of(MockDataset)
|
12
|
+
@m.dataset.opts[:from].should == [:items]
|
13
|
+
|
14
|
+
@m2 = Class.new(Sequel::Model) do
|
15
|
+
set_dataset MODEL_DB[:zzz]
|
16
|
+
end
|
17
|
+
|
18
|
+
@m2.dataset.should be_a_kind_of(MockDataset)
|
19
|
+
@m2.dataset.opts[:from].should == [:zzz]
|
20
|
+
@m.dataset.opts[:from].should == [:items]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "A model's primary key" do
|
25
|
+
specify "should default to id" do
|
26
|
+
@m = Class.new(Sequel::Model) do
|
27
|
+
end
|
28
|
+
|
29
|
+
@m.primary_key.should == :id
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "should be changeable through Model.set_primary_key" do
|
33
|
+
@m = Class.new(Sequel::Model) do
|
34
|
+
set_primary_key :xxx
|
35
|
+
end
|
36
|
+
|
37
|
+
@m.primary_key.should == :xxx
|
38
|
+
end
|
39
|
+
|
40
|
+
specify "should support composite primary keys" do
|
41
|
+
@m = Class.new(Sequel::Model) do
|
42
|
+
set_primary_key [:node_id, :session_id]
|
43
|
+
end
|
44
|
+
@m.primary_key.should == [:node_id, :session_id]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "A model without a primary key" do
|
49
|
+
setup do
|
50
|
+
@m = Class.new(Sequel::Model) do
|
51
|
+
no_primary_key
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "should return nil for primary_key" do
|
56
|
+
@m.primary_key.should be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
specify "should raise on #this" do
|
60
|
+
o = @m.new
|
61
|
+
proc {o.this}.should raise_error(SequelError)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "Model#this" do
|
66
|
+
setup do
|
67
|
+
@m = Class.new(Sequel::Model(:items)) do
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
specify "should return a dataset identifying the record" do
|
72
|
+
o = @m.new(:id => 3)
|
73
|
+
o.this.sql.should == "SELECT * FROM items WHERE (id = 3)"
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "should support arbitrary primary keys" do
|
77
|
+
@m.set_primary_key(:xxx)
|
78
|
+
|
79
|
+
o = @m.new(:xxx => 3)
|
80
|
+
o.this.sql.should == "SELECT * FROM items WHERE (xxx = 3)"
|
81
|
+
end
|
82
|
+
|
83
|
+
specify "should support composite primary keys" do
|
84
|
+
@m.set_primary_key [:x, :y]
|
85
|
+
o = @m.new(:x => 4, :y => 5)
|
86
|
+
|
87
|
+
o.this.sql.should =~ /^SELECT \* FROM items WHERE (\(x = 4\) AND \(y = 5\))|(\(y = 5\) AND \(x = 4\))$/
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "A new model instance" do
|
92
|
+
setup do
|
93
|
+
@m = Class.new(Sequel::Model) do
|
94
|
+
set_dataset MODEL_DB[:items]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
specify "should be marked as new?" do
|
99
|
+
o = @m.new
|
100
|
+
o.should be_new
|
101
|
+
end
|
102
|
+
|
103
|
+
specify "should not be marked as new? once it is saved" do
|
104
|
+
o = @m.new(:x => 1)
|
105
|
+
o.should be_new
|
106
|
+
o.save
|
107
|
+
o.should_not be_new
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "should use the last inserted id as primary key if not in values" do
|
111
|
+
d = @m.dataset
|
112
|
+
def d.insert(*args)
|
113
|
+
super
|
114
|
+
1234
|
115
|
+
end
|
116
|
+
|
117
|
+
def d.first
|
118
|
+
{:x => 1, :id => 1234}
|
119
|
+
end
|
120
|
+
|
121
|
+
o = @m.new(:x => 1)
|
122
|
+
o.save
|
123
|
+
o.id.should == 1234
|
124
|
+
|
125
|
+
o = @m.new(:x => 1, :id => 333)
|
126
|
+
o.save
|
127
|
+
o.id.should == 333
|
128
|
+
end
|
129
|
+
end
|
4
130
|
|
5
131
|
describe Sequel::Model do
|
6
132
|
before do
|
@@ -20,8 +146,8 @@ describe Sequel::Model do
|
|
20
146
|
@model.primary_key.should == :ssn
|
21
147
|
end
|
22
148
|
|
23
|
-
it "allows
|
24
|
-
@model.
|
149
|
+
it "allows dataset change" do
|
150
|
+
@model.set_dataset(MODEL_DB[:foo])
|
25
151
|
@model.table_name.should == :foo
|
26
152
|
end
|
27
153
|
|
@@ -55,4 +181,161 @@ context "Sequel::Model()" do
|
|
55
181
|
eval "class DummyModelBased < Sequel::Model(:blog); end"
|
56
182
|
end.should_not raise_error
|
57
183
|
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "A model class" do
|
187
|
+
setup do
|
188
|
+
MODEL_DB.reset
|
189
|
+
@c = Class.new(Sequel::Model(:items))
|
190
|
+
end
|
191
|
+
|
192
|
+
specify "should be able to create rows in the associated table" do
|
193
|
+
o = @c.create(:x => 1)
|
194
|
+
o.class.should == @c
|
195
|
+
MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1);']
|
196
|
+
end
|
197
|
+
|
198
|
+
specify "should be able to create rows without any values specified" do
|
199
|
+
o = @c.create
|
200
|
+
o.class.should == @c
|
201
|
+
MODEL_DB.sqls.should == ['INSERT INTO items DEFAULT VALUES;']
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "A model class without a primary key" do
|
206
|
+
setup do
|
207
|
+
MODEL_DB.reset
|
208
|
+
@c = Class.new(Sequel::Model(:items)) do
|
209
|
+
no_primary_key
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
specify "should be able to insert records without selecting them back" do
|
214
|
+
i = nil
|
215
|
+
proc {i = @c.create(:x => 1)}.should_not raise_error
|
216
|
+
i.class.should be(@c)
|
217
|
+
i.values.should == {:x => 1}
|
218
|
+
|
219
|
+
MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1);']
|
220
|
+
end
|
221
|
+
|
222
|
+
specify "should raise when deleting" do
|
223
|
+
o = @c.new
|
224
|
+
proc {o.delete}.should raise_error
|
225
|
+
end
|
226
|
+
|
227
|
+
specify "should insert a record when saving" do
|
228
|
+
o = @c.new(:x => 2)
|
229
|
+
o.should be_new
|
230
|
+
o.save
|
231
|
+
MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (2);']
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context "Model#serialize" do
|
236
|
+
setup do
|
237
|
+
MODEL_DB.reset
|
238
|
+
end
|
239
|
+
|
240
|
+
specify "should translate values to YAML when creating records" do
|
241
|
+
@c = Class.new(Sequel::Model(:items)) do
|
242
|
+
no_primary_key
|
243
|
+
serialize :abc
|
244
|
+
end
|
245
|
+
|
246
|
+
@c.create(:abc => 1)
|
247
|
+
@c.create(:abc => "hello")
|
248
|
+
|
249
|
+
MODEL_DB.sqls.should == [ \
|
250
|
+
"INSERT INTO items (abc) VALUES ('--- 1\n');", \
|
251
|
+
"INSERT INTO items (abc) VALUES ('--- hello\n');", \
|
252
|
+
]
|
253
|
+
end
|
254
|
+
|
255
|
+
specify "should translate values to and from YAML using accessor methods" do
|
256
|
+
@c = Class.new(Sequel::Model(:items)) do
|
257
|
+
serialize :abc, :def
|
258
|
+
end
|
259
|
+
|
260
|
+
ds = @c.dataset
|
261
|
+
ds.extend(Module.new {
|
262
|
+
attr_accessor :raw
|
263
|
+
|
264
|
+
def fetch_rows(sql, &block)
|
265
|
+
block.call(@raw)
|
266
|
+
end
|
267
|
+
|
268
|
+
@@sqls = nil
|
269
|
+
|
270
|
+
def insert(*args)
|
271
|
+
@@sqls = insert_sql(*args)
|
272
|
+
end
|
273
|
+
|
274
|
+
def update(*args)
|
275
|
+
@@sqls = update_sql(*args)
|
276
|
+
end
|
277
|
+
|
278
|
+
def sqls
|
279
|
+
@@sqls
|
280
|
+
end
|
281
|
+
|
282
|
+
def columns
|
283
|
+
[:id, :abc, :def]
|
284
|
+
end
|
285
|
+
})
|
286
|
+
|
287
|
+
ds.raw = {:id => 1, :abc => "--- 1\n", :def => "--- hello\n"}
|
288
|
+
o = @c.first
|
289
|
+
o.id.should == 1
|
290
|
+
o.abc.should == 1
|
291
|
+
o.def.should == "hello"
|
292
|
+
|
293
|
+
o.set(:abc => 23)
|
294
|
+
ds.sqls.should == "UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)"
|
295
|
+
|
296
|
+
o = @c.create(:abc => [1, 2, 3])
|
297
|
+
ds.sqls.should == "INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}');"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
context "Model attribute accessors" do
|
302
|
+
setup do
|
303
|
+
MODEL_DB.reset
|
304
|
+
|
305
|
+
@c = Class.new(Sequel::Model(:items)) do
|
306
|
+
def columns
|
307
|
+
[:id, :x, :y]
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
ds = @c.dataset
|
312
|
+
ds.extend(Module.new {
|
313
|
+
def columns
|
314
|
+
[:id, :x, :y]
|
315
|
+
end
|
316
|
+
})
|
317
|
+
end
|
318
|
+
|
319
|
+
specify "should be created dynamically" do
|
320
|
+
o = @c.new
|
321
|
+
|
322
|
+
o.should_not be_respond_to(:x)
|
323
|
+
o.x.should be_nil
|
324
|
+
o.should be_respond_to(:x)
|
325
|
+
|
326
|
+
o.should_not be_respond_to(:x=)
|
327
|
+
o.x = 34
|
328
|
+
o.x.should == 34
|
329
|
+
o.should be_respond_to(:x=)
|
330
|
+
end
|
331
|
+
|
332
|
+
specify "should raise for a column that doesn't exist in the dataset" do
|
333
|
+
o = @c.new
|
334
|
+
|
335
|
+
proc {o.x}.should_not raise_error
|
336
|
+
proc {o.xx}.should raise_error(SequelError)
|
337
|
+
|
338
|
+
proc {o.x = 3}.should_not raise_error
|
339
|
+
proc {o.yy = 4}.should raise_error
|
340
|
+
end
|
58
341
|
end
|