sequel 4.12.0 → 4.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +64 -0
- data/Rakefile +3 -1
- data/bin/sequel +13 -5
- data/doc/release_notes/4.13.0.txt +169 -0
- data/doc/sql.rdoc +3 -3
- data/lib/sequel/adapters/do.rb +11 -23
- data/lib/sequel/adapters/do/mysql.rb +8 -0
- data/lib/sequel/adapters/do/postgres.rb +8 -0
- data/lib/sequel/adapters/do/{sqlite.rb → sqlite3.rb} +9 -0
- data/lib/sequel/adapters/jdbc.rb +16 -139
- data/lib/sequel/adapters/jdbc/as400.rb +9 -0
- data/lib/sequel/adapters/jdbc/cubrid.rb +9 -0
- data/lib/sequel/adapters/jdbc/db2.rb +9 -0
- data/lib/sequel/adapters/jdbc/derby.rb +9 -0
- data/lib/sequel/adapters/jdbc/{firebird.rb → firebirdsql.rb} +9 -0
- data/lib/sequel/adapters/jdbc/h2.rb +10 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -0
- data/lib/sequel/adapters/jdbc/{informix.rb → informix-sqli.rb} +9 -0
- data/lib/sequel/adapters/jdbc/{progress.rb → jdbcprogress.rb} +9 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +10 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +14 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +9 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -0
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +23 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +10 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -0
- data/lib/sequel/adapters/odbc.rb +6 -14
- data/lib/sequel/adapters/odbc/db2.rb +9 -0
- data/lib/sequel/adapters/odbc/mssql.rb +8 -0
- data/lib/sequel/adapters/odbc/progress.rb +8 -0
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +1 -1
- data/lib/sequel/adapters/shared/firebird.rb +8 -1
- data/lib/sequel/adapters/shared/mssql.rb +68 -27
- data/lib/sequel/adapters/shared/mysql.rb +3 -5
- data/lib/sequel/adapters/shared/oracle.rb +17 -3
- data/lib/sequel/adapters/shared/postgres.rb +9 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -6
- data/lib/sequel/database/connecting.rb +38 -17
- data/lib/sequel/dataset/actions.rb +6 -2
- data/lib/sequel/dataset/graph.rb +18 -20
- data/lib/sequel/dataset/misc.rb +37 -0
- data/lib/sequel/dataset/prepared_statements.rb +1 -2
- data/lib/sequel/dataset/query.rb +1 -0
- data/lib/sequel/dataset/sql.rb +17 -10
- data/lib/sequel/extensions/dataset_source_alias.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +14 -10
- data/lib/sequel/extensions/pg_enum.rb +135 -0
- data/lib/sequel/extensions/pg_hstore.rb +4 -6
- data/lib/sequel/extensions/pg_inet.rb +4 -5
- data/lib/sequel/extensions/pg_interval.rb +3 -3
- data/lib/sequel/extensions/pg_json.rb +16 -12
- data/lib/sequel/extensions/pg_range.rb +5 -3
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/round_timestamps.rb +52 -0
- data/lib/sequel/model.rb +5 -2
- data/lib/sequel/model/associations.rb +29 -3
- data/lib/sequel/model/base.rb +68 -29
- data/lib/sequel/plugins/class_table_inheritance.rb +25 -16
- data/lib/sequel/plugins/column_select.rb +57 -0
- data/lib/sequel/plugins/composition.rb +14 -16
- data/lib/sequel/plugins/dirty.rb +9 -11
- data/lib/sequel/plugins/insert_returning_select.rb +70 -0
- data/lib/sequel/plugins/instance_filters.rb +7 -9
- data/lib/sequel/plugins/lazy_attributes.rb +16 -4
- data/lib/sequel/plugins/list.rb +9 -0
- data/lib/sequel/plugins/modification_detection.rb +90 -0
- data/lib/sequel/plugins/serialization.rb +13 -15
- data/lib/sequel/plugins/serialization_modification_detection.rb +9 -9
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/timestamps.rb +6 -6
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +7 -0
- data/spec/adapters/postgres_spec.rb +41 -0
- data/spec/bin_spec.rb +4 -1
- data/spec/core/database_spec.rb +6 -0
- data/spec/core/dataset_spec.rb +100 -90
- data/spec/core/object_graph_spec.rb +5 -0
- data/spec/extensions/class_table_inheritance_spec.rb +18 -13
- data/spec/extensions/column_select_spec.rb +108 -0
- data/spec/extensions/composition_spec.rb +20 -0
- data/spec/extensions/dataset_source_alias_spec.rb +51 -0
- data/spec/extensions/insert_returning_select_spec.rb +46 -0
- data/spec/extensions/lazy_attributes_spec.rb +24 -20
- data/spec/extensions/list_spec.rb +5 -0
- data/spec/extensions/modification_detection_spec.rb +80 -0
- data/spec/extensions/pg_enum_spec.rb +64 -0
- data/spec/extensions/pg_json_spec.rb +7 -13
- data/spec/extensions/prepared_statements_spec.rb +6 -4
- data/spec/extensions/round_timestamps_spec.rb +43 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +10 -1
- data/spec/extensions/serialization_spec.rb +18 -0
- data/spec/extensions/single_table_inheritance_spec.rb +5 -0
- data/spec/extensions/timestamps_spec.rb +6 -0
- data/spec/integration/plugin_test.rb +14 -8
- data/spec/integration/prepared_statement_test.rb +12 -0
- data/spec/model/associations_spec.rb +24 -0
- data/spec/model/model_spec.rb +13 -3
- data/spec/model/record_spec.rb +24 -1
- metadata +22 -6
@@ -58,6 +58,11 @@ describe Sequel::Dataset, "graphing" do
|
|
58
58
|
ds.sql.should == 'SELECT points.id, points.x AS y, lines.id AS lines_id, lines.x, lines.y AS lines_y, lines.graph_id FROM points LEFT OUTER JOIN lines ON (lines.x = points.id)'
|
59
59
|
end
|
60
60
|
|
61
|
+
it "should requalify currently selected columns in new graph if current dataset joins tables" do
|
62
|
+
ds = @ds1.cross_join(:lines).select(:points__id, :lines__id___lid, :lines__x, :lines__y).graph(@ds3, :x=>:id)
|
63
|
+
ds.sql.should == 'SELECT points.id, points.lid, points.x, points.y, graphs.id AS graphs_id, graphs.name, graphs.x AS graphs_x, graphs.y AS graphs_y, graphs.lines_x FROM (SELECT points.id, lines.id AS lid, lines.x, lines.y FROM points CROSS JOIN lines) AS points LEFT OUTER JOIN graphs ON (graphs.x = points.id)'
|
64
|
+
end
|
65
|
+
|
61
66
|
it "should raise error if currently selected expressions cannot be handled" do
|
62
67
|
proc{@ds1.select(1).graph(@ds2, :x=>:id)}.should raise_error(Sequel::Error)
|
63
68
|
end
|
@@ -48,8 +48,8 @@ describe "class_table_inheritance plugin" do
|
|
48
48
|
Object.send(:remove_const, :Employee)
|
49
49
|
end
|
50
50
|
|
51
|
-
specify "should have simple_table = nil for
|
52
|
-
Employee.simple_table.should ==
|
51
|
+
specify "should have simple_table = nil for all classes" do
|
52
|
+
Employee.simple_table.should == nil
|
53
53
|
Manager.simple_table.should == nil
|
54
54
|
Executive.simple_table.should == nil
|
55
55
|
Staff.simple_table.should == nil
|
@@ -62,10 +62,10 @@ describe "class_table_inheritance plugin" do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
specify "should use a joined dataset in subclasses" do
|
65
|
-
Employee.dataset.sql.should == 'SELECT
|
66
|
-
Manager.dataset.sql.should == 'SELECT
|
67
|
-
Executive.dataset.sql.should == 'SELECT
|
68
|
-
Staff.dataset.sql.should == 'SELECT
|
65
|
+
Employee.dataset.sql.should == 'SELECT employees.id, employees.name, employees.kind FROM employees'
|
66
|
+
Manager.dataset.sql.should == 'SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)'
|
67
|
+
Executive.dataset.sql.should == 'SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id)'
|
68
|
+
Staff.dataset.sql.should == 'SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)'
|
69
69
|
end
|
70
70
|
|
71
71
|
it "should return rows with the correct class based on the polymorphic_key value" do
|
@@ -80,7 +80,7 @@ describe "class_table_inheritance plugin" do
|
|
80
80
|
|
81
81
|
it "should return rows with the current class if cti_key is nil" do
|
82
82
|
Employee.plugin(:class_table_inheritance)
|
83
|
-
|
83
|
+
Employee.dataset._fetch = [{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Staff'}]
|
84
84
|
Employee.all.collect{|x| x.class}.should == [Employee, Employee, Employee, Employee]
|
85
85
|
end
|
86
86
|
|
@@ -147,22 +147,27 @@ describe "class_table_inheritance plugin" do
|
|
147
147
|
o.valid?.should == true
|
148
148
|
end
|
149
149
|
|
150
|
+
it "should set the type column field even when not validating" do
|
151
|
+
Employee.new.save(:validate=>false)
|
152
|
+
@db.sqls.should == ["INSERT INTO employees (kind) VALUES ('Employee')"]
|
153
|
+
end
|
154
|
+
|
150
155
|
it "should raise an error if attempting to create an anonymous subclass" do
|
151
156
|
proc{Class.new(Manager)}.should raise_error(Sequel::Error)
|
152
157
|
end
|
153
158
|
|
154
159
|
it "should allow specifying a map of names to tables to override implicit mapping" do
|
155
|
-
Manager.dataset.sql.should == 'SELECT
|
156
|
-
Staff.dataset.sql.should == 'SELECT
|
160
|
+
Manager.dataset.sql.should == 'SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)'
|
161
|
+
Staff.dataset.sql.should == 'SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)'
|
157
162
|
end
|
158
163
|
|
159
164
|
it "should lazily load attributes for columns in subclass tables" do
|
160
165
|
Manager.instance_dataset._fetch = Manager.dataset._fetch = {:id=>1, :name=>'J', :kind=>'Executive', :num_staff=>2}
|
161
166
|
m = Manager[1]
|
162
|
-
@db.sqls.should == ['SELECT
|
167
|
+
@db.sqls.should == ['SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 1) LIMIT 1']
|
163
168
|
Executive.instance_dataset._fetch = Executive.dataset._fetch = {:num_managers=>3}
|
164
169
|
m.num_managers.should == 3
|
165
|
-
@db.sqls.should == ['SELECT num_managers FROM employees INNER JOIN managers
|
170
|
+
@db.sqls.should == ['SELECT executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id) WHERE (executives.id = 1) LIMIT 1']
|
166
171
|
m.values.should == {:id=>1, :name=>'J', :kind=>'Executive', :num_staff=>2, :num_managers=>3}
|
167
172
|
end
|
168
173
|
|
@@ -224,12 +229,12 @@ describe "class_table_inheritance plugin" do
|
|
224
229
|
it "should handle many_to_one relationships correctly" do
|
225
230
|
Manager.dataset._fetch = {:id=>3, :name=>'E', :kind=>'Executive', :num_managers=>3}
|
226
231
|
Staff.load(:manager_id=>3).manager.should == Executive.load(:id=>3, :name=>'E', :kind=>'Executive', :num_managers=>3)
|
227
|
-
@db.sqls.should == ['SELECT
|
232
|
+
@db.sqls.should == ['SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 3) LIMIT 1']
|
228
233
|
end
|
229
234
|
|
230
235
|
it "should handle one_to_many relationships correctly" do
|
231
236
|
Staff.dataset._fetch = {:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3}
|
232
237
|
Executive.load(:id=>3).staff_members.should == [Staff.load(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)]
|
233
|
-
@db.sqls.should == ['SELECT
|
238
|
+
@db.sqls.should == ['SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id) WHERE (staff.manager_id = 3)']
|
234
239
|
end
|
235
240
|
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::ColumnSelect" do
|
4
|
+
def set_cols(*cols)
|
5
|
+
@cols.replace(cols)
|
6
|
+
end
|
7
|
+
|
8
|
+
before do
|
9
|
+
cols = @cols = []
|
10
|
+
@db = Sequel.mock
|
11
|
+
@db.extend_datasets(Module.new{define_method(:columns){cols}})
|
12
|
+
set_cols :id, :a, :b, :c
|
13
|
+
@Album = Class.new(Sequel::Model(@db[:albums]))
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should add a explicit column selections to existing dataset without explicit selection" do
|
17
|
+
@Album.plugin :column_select
|
18
|
+
@Album.dataset.sql.should == 'SELECT albums.id, albums.a, albums.b, albums.c FROM albums'
|
19
|
+
|
20
|
+
@Album.dataset = :albs
|
21
|
+
@Album.dataset.sql.should == 'SELECT albs.id, albs.a, albs.b, albs.c FROM albs'
|
22
|
+
|
23
|
+
@Album.dataset = Sequel.identifier(:albs)
|
24
|
+
@Album.dataset.sql.should == 'SELECT albs.id, albs.a, albs.b, albs.c FROM albs'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should handle qualified tables" do
|
28
|
+
@Album.dataset = :s__albums
|
29
|
+
@Album.plugin :column_select
|
30
|
+
@Album.dataset.sql.should == 'SELECT s.albums.id, s.albums.a, s.albums.b, s.albums.c FROM s.albums'
|
31
|
+
|
32
|
+
@Album.dataset = Sequel.qualify(:s2, :albums)
|
33
|
+
@Album.dataset.sql.should == 'SELECT s2.albums.id, s2.albums.a, s2.albums.b, s2.albums.c FROM s2.albums'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should handle aliases" do
|
37
|
+
@Album.dataset = :albums___a
|
38
|
+
@Album.plugin :column_select
|
39
|
+
@Album.dataset.sql.should == 'SELECT a.id, a.a, a.b, a.c FROM albums AS a'
|
40
|
+
|
41
|
+
@Album.dataset = Sequel.as(:albums, :b)
|
42
|
+
@Album.dataset.sql.should == 'SELECT b.id, b.a, b.b, b.c FROM albums AS b'
|
43
|
+
|
44
|
+
@Album.dataset = :s__albums___a
|
45
|
+
@Album.dataset.sql.should == 'SELECT a.id, a.a, a.b, a.c FROM s.albums AS a'
|
46
|
+
|
47
|
+
@Album.dataset = @Album.db[:albums].from_self
|
48
|
+
@Album.dataset.sql.should == 'SELECT t1.id, t1.a, t1.b, t1.c FROM (SELECT * FROM albums) AS t1'
|
49
|
+
|
50
|
+
@Album.dataset = Sequel.as(@Album.db[:albums], :b)
|
51
|
+
@Album.dataset.sql.should == 'SELECT b.id, b.a, b.b, b.c FROM (SELECT * FROM albums) AS b'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not add a explicit column selection selection on existing dataset with explicit selection" do
|
55
|
+
@Album.dataset = @Album.dataset.select(:name)
|
56
|
+
@Album.plugin :column_select
|
57
|
+
@Album.dataset.sql.should == 'SELECT name FROM albums'
|
58
|
+
|
59
|
+
@Album.dataset = @Album.dataset.select(:name, :artist)
|
60
|
+
@Album.dataset.sql.should == 'SELECT name, artist FROM albums'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not add a explicit column selection on existing dataset with multiple tables" do
|
64
|
+
@Album.dataset = @Album.db.from(:a1, :a2)
|
65
|
+
@Album.plugin :column_select
|
66
|
+
@Album.dataset.sql.should == 'SELECT * FROM a1, a2'
|
67
|
+
|
68
|
+
@Album.dataset = @Album.db.from(:a1).cross_join(:a2)
|
69
|
+
@Album.dataset.sql.should == 'SELECT * FROM a1 CROSS JOIN a2'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should use explicit column selection for many_to_many associations" do
|
73
|
+
@Album.plugin :column_select
|
74
|
+
@Album.many_to_many :albums, :class=>@Album, :left_key=>:l, :right_key=>:r, :join_table=>:j
|
75
|
+
@Album.load(:id=>1).albums_dataset.sql.should == 'SELECT albums.id, albums.a, albums.b, albums.c FROM albums INNER JOIN j ON (j.r = albums.id) WHERE (j.l = 1)'
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should set not explicit column selection for many_to_many associations when overriding select" do
|
79
|
+
@Album.plugin :column_select
|
80
|
+
@Album.dataset = @Album.dataset.select(:a)
|
81
|
+
@Album.many_to_many :albums, :class=>@Album, :left_key=>:l, :right_key=>:r, :join_table=>:j
|
82
|
+
@Album.load(:id=>1).albums_dataset.sql.should == 'SELECT albums.* FROM albums INNER JOIN j ON (j.r = albums.id) WHERE (j.l = 1)'
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should use the schema to get columns if available" do
|
86
|
+
def @db.supports_schema_parsing?() true end
|
87
|
+
def @db.schema(t, *)
|
88
|
+
[[:t, {}], [:d, {}]]
|
89
|
+
end
|
90
|
+
@Album.plugin :column_select
|
91
|
+
@Album.dataset.sql.should == 'SELECT albums.t, albums.d FROM albums'
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should handle case where schema parsing does not produce results" do
|
95
|
+
def @db.supports_schema_parsing?() true end
|
96
|
+
def @db.schema_parse_table(t, *) [] end
|
97
|
+
@Album.plugin :column_select
|
98
|
+
@Album.dataset.sql.should == 'SELECT albums.id, albums.a, albums.b, albums.c FROM albums'
|
99
|
+
end
|
100
|
+
|
101
|
+
it "works correctly when loaded on model without a dataset" do
|
102
|
+
c = Class.new(Sequel::Model)
|
103
|
+
c.plugin :column_select
|
104
|
+
sc = Class.new(c)
|
105
|
+
sc.dataset = @db[:a]
|
106
|
+
sc.dataset.sql.should == "SELECT a.id, a.a, a.b, a.c FROM a"
|
107
|
+
end
|
108
|
+
end
|
@@ -27,6 +27,26 @@ describe "Composition plugin" do
|
|
27
27
|
proc{@c.composition :date, :mapping=>[]}.should_not raise_error
|
28
28
|
end
|
29
29
|
|
30
|
+
it "should handle validations of underlying columns" do
|
31
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
32
|
+
o = @c.new
|
33
|
+
def o.validate
|
34
|
+
[:year, :month, :day].each{|c| errors.add(c, "not present") unless send(c)}
|
35
|
+
end
|
36
|
+
o.valid?.should == false
|
37
|
+
o.date = Date.new(1, 2, 3)
|
38
|
+
o.valid?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should set column values even when not validating" do
|
42
|
+
@c.composition :date, :mapping=>[:year, :month, :day]
|
43
|
+
@c.load({}).set(:date=>Date.new(4, 8, 12)).save(:validate=>false)
|
44
|
+
sql = DB.sqls.last
|
45
|
+
sql.should include("year = 4")
|
46
|
+
sql.should include("month = 8")
|
47
|
+
sql.should include("day = 12")
|
48
|
+
end
|
49
|
+
|
30
50
|
it ".compositions should return the reflection hash of compositions" do
|
31
51
|
@c.compositions.should == {}
|
32
52
|
@c.composition :date, :mapping=>[:year, :month, :day]
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "dataset_source_alias extension" do
|
4
|
+
before do
|
5
|
+
@db = Sequel.mock
|
6
|
+
@db.extension(:dataset_source_alias)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should automatically alias datasets to their first source in #from" do
|
10
|
+
@db[@db[:a]].sql.should == 'SELECT * FROM (SELECT * FROM a) AS a'
|
11
|
+
@db[:a, @db[:b]].sql.should == 'SELECT * FROM a, (SELECT * FROM b) AS b'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should handle virtual row blocks in #from" do
|
15
|
+
@db.dataset.from{|_| @db[:a]}.sql.should == 'SELECT * FROM (SELECT * FROM a) AS a'
|
16
|
+
@db.dataset.from(:a){|_| @db[:b]}.sql.should == 'SELECT * FROM a, (SELECT * FROM b) AS b'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should automatically alias datasets to their first source in #join" do
|
20
|
+
@db[:a].cross_join(@db[:b]).sql.should == 'SELECT * FROM a CROSS JOIN (SELECT * FROM b) AS b'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should handle :table_alias option when joining" do
|
24
|
+
@db[:a].cross_join(@db[:b], :table_alias=>:c).sql.should == 'SELECT * FROM a CROSS JOIN (SELECT * FROM b) AS c'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should handle aliasing issues automatically" do
|
28
|
+
@db[:a, @db[:a]].sql.should == 'SELECT * FROM a, (SELECT * FROM a) AS a_0'
|
29
|
+
@db.dataset.from(:a, @db[:a]){|_| @db[:a]}.sql.should == 'SELECT * FROM a, (SELECT * FROM a) AS a_0, (SELECT * FROM a) AS a_1'
|
30
|
+
@db.dataset.from(:a, @db[:a]){|_| @db[:a]}.cross_join(@db[:a]).sql.should == 'SELECT * FROM a, (SELECT * FROM a) AS a_0, (SELECT * FROM a) AS a_1 CROSS JOIN (SELECT * FROM a) AS a_2'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should handle from_self" do
|
34
|
+
@db[:a].from_self.sql.should == 'SELECT * FROM (SELECT * FROM a) AS a'
|
35
|
+
@db[:a].from_self.from_self.sql.should == 'SELECT * FROM (SELECT * FROM (SELECT * FROM a) AS a) AS a'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should handle datasets without sources" do
|
39
|
+
@db[@db.select(1)].sql.should == 'SELECT * FROM (SELECT 1) AS t1'
|
40
|
+
@db[:t, @db.select(1)].sql.should == 'SELECT * FROM t, (SELECT 1) AS t1'
|
41
|
+
@db[:a].cross_join(@db.select(1)).sql.should == 'SELECT * FROM a CROSS JOIN (SELECT 1) AS t1'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should handle datasets selecting from functions" do
|
45
|
+
@db.dataset.from{|o| @db[o.f(:a)]}.sql.should == 'SELECT * FROM (SELECT * FROM f(a)) AS t1'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should handle datasets with literal SQL" do
|
49
|
+
@db.from(@db['SELECT c FROM d']).sql.should == 'SELECT * FROM (SELECT c FROM d) AS t1'
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::InsertReturningSelect" do
|
4
|
+
before do
|
5
|
+
@db = Sequel.mock(:fetch=>{:id=>1, :x=>2}, :autoid=>1)
|
6
|
+
@db.extend_datasets do
|
7
|
+
def supports_returning?(_) true end
|
8
|
+
def insert_select(*v) with_sql_first("#{insert_sql(*v)} RETURNING #{opts[:returning].map{|x| literal(x)}.join(', ')}") end
|
9
|
+
end
|
10
|
+
@Album = Class.new(Sequel::Model(@db[:albums].select(:id, :x)))
|
11
|
+
@Album.columns :id, :x
|
12
|
+
@db.sqls
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should add a returning clause when inserting using selected columns" do
|
16
|
+
@Album.plugin :insert_returning_select
|
17
|
+
@Album.create(:x=>2).should == @Album.load(:id=>1, :x=>2)
|
18
|
+
@db.sqls.should == ['INSERT INTO albums (x) VALUES (2) RETURNING id, x']
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not add a returning clause if selection does not consist of just columns" do
|
22
|
+
@Album.dataset = @Album.dataset.select_append(Sequel.as(1, :b))
|
23
|
+
@Album.plugin :insert_returning_select
|
24
|
+
@db.sqls.clear
|
25
|
+
@Album.create(:x=>2).should == @Album.load(:id=>1, :x=>2)
|
26
|
+
@db.sqls.should == ['INSERT INTO albums (x) VALUES (2)', 'SELECT id, x, 1 AS b FROM albums WHERE (id = 1) LIMIT 1']
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not add a returning clause if database doesn't support it" do
|
30
|
+
@db.extend_datasets{def supports_returning?(_) false end}
|
31
|
+
@Album.plugin :insert_returning_select
|
32
|
+
@Album.create(:x=>2).should == @Album.load(:id=>1, :x=>2)
|
33
|
+
@db.sqls.should == ['INSERT INTO albums (x) VALUES (2)', 'SELECT id, x FROM albums WHERE (id = 1) LIMIT 1']
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should work correctly with subclasses" do
|
37
|
+
c = Class.new(Sequel::Model)
|
38
|
+
c.plugin :insert_returning_select
|
39
|
+
b = Class.new(c)
|
40
|
+
b.columns :id, :x
|
41
|
+
b.dataset = @db[:albums].select(:id, :x)
|
42
|
+
@db.sqls.clear
|
43
|
+
b.create(:x=>2).should == b.load(:id=>1, :x=>2)
|
44
|
+
@db.sqls.should == ['INSERT INTO albums (x) VALUES (2) RETURNING id, x']
|
45
|
+
end
|
46
|
+
end
|
@@ -25,7 +25,7 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
25
25
|
elsif sql =~ /id = (\d)/
|
26
26
|
[$1]
|
27
27
|
end.map do |x|
|
28
|
-
if sql =~ /SELECT name FROM/
|
28
|
+
if sql =~ /SELECT (la.)?name FROM/
|
29
29
|
{:name=>x.to_s}
|
30
30
|
else
|
31
31
|
{:id=>x.to_i, :name=>x.to_s}
|
@@ -46,7 +46,6 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
46
46
|
@c.set_dataset(@ds.select(:id, :blah))
|
47
47
|
@c.dataset.sql.should == 'SELECT id, blah FROM la'
|
48
48
|
@c.plugin :lazy_attributes, :blah
|
49
|
-
@c.dataset.opts[:select].should == [:id]
|
50
49
|
@c.dataset.sql.should == 'SELECT id FROM la'
|
51
50
|
end
|
52
51
|
|
@@ -54,13 +53,18 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
54
53
|
@c.set_dataset(@ds.select(:id, :blah))
|
55
54
|
@c.dataset.sql.should == 'SELECT id, blah FROM la'
|
56
55
|
@c.lazy_attributes :blah
|
57
|
-
@c.dataset.opts[:select].should == [:id]
|
58
56
|
@c.dataset.sql.should == 'SELECT id FROM la'
|
59
57
|
end
|
60
58
|
|
59
|
+
it "should handle lazy attributes that are qualified in the selection" do
|
60
|
+
@c.set_dataset(@ds.select(:la__id, :la__blah))
|
61
|
+
@c.dataset.sql.should == 'SELECT la.id, la.blah FROM la'
|
62
|
+
@c.plugin :lazy_attributes, :blah
|
63
|
+
@c.dataset.sql.should == 'SELECT la.id FROM la'
|
64
|
+
end
|
65
|
+
|
61
66
|
it "should remove the attributes given from the SELECT columns of the model's dataset" do
|
62
|
-
@ds.
|
63
|
-
@ds.sql.should == 'SELECT id FROM la'
|
67
|
+
@ds.sql.should == 'SELECT la.id FROM la'
|
64
68
|
end
|
65
69
|
|
66
70
|
it "should still typecast correctly in lazy loaded column setters" do
|
@@ -80,16 +84,16 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
80
84
|
m.values.should == {:id=>1}
|
81
85
|
m.name.should == '1'
|
82
86
|
m.values.should == {:id=>1, :name=>'1'}
|
83
|
-
@db.sqls.should == ['SELECT id FROM la LIMIT 1', 'SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
87
|
+
@db.sqls.should == ['SELECT la.id FROM la LIMIT 1', 'SELECT la.name FROM la WHERE (id = 1) LIMIT 1']
|
84
88
|
end
|
85
89
|
|
86
90
|
it "should lazily load the attribute for a frozen model object" do
|
87
91
|
m = @c.first
|
88
92
|
m.freeze
|
89
93
|
m.name.should == '1'
|
90
|
-
@db.sqls.should == ['SELECT id FROM la LIMIT 1', 'SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
94
|
+
@db.sqls.should == ['SELECT la.id FROM la LIMIT 1', 'SELECT la.name FROM la WHERE (id = 1) LIMIT 1']
|
91
95
|
m.name.should == '1'
|
92
|
-
@db.sqls.should == ['SELECT name FROM la WHERE (id = 1) LIMIT 1']
|
96
|
+
@db.sqls.should == ['SELECT la.name FROM la WHERE (id = 1) LIMIT 1']
|
93
97
|
end
|
94
98
|
|
95
99
|
it "should not lazily load the attribute for a single model object if the value already exists" do
|
@@ -98,7 +102,7 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
98
102
|
m[:name] = '1'
|
99
103
|
m.name.should == '1'
|
100
104
|
m.values.should == {:id=>1, :name=>'1'}
|
101
|
-
@db.sqls.should == ['SELECT id FROM la LIMIT 1']
|
105
|
+
@db.sqls.should == ['SELECT la.id FROM la LIMIT 1']
|
102
106
|
end
|
103
107
|
|
104
108
|
it "should not lazily load the attribute for a single model object if it is a new record" do
|
@@ -114,16 +118,16 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
114
118
|
ms.map{|m| m.name}.should == %w'1 2'
|
115
119
|
ms.map{|m| m.values}.should == [{:id=>1, :name=>'1'}, {:id=>2, :name=>'2'}]
|
116
120
|
sqls = @db.sqls
|
117
|
-
['SELECT id, name FROM la WHERE (id IN (1, 2))',
|
118
|
-
'SELECT id, name FROM la WHERE (id IN (2, 1))'].should include(sqls.pop)
|
119
|
-
sqls.should == ['SELECT id FROM la']
|
121
|
+
['SELECT la.id, la.name FROM la WHERE (la.id IN (1, 2))',
|
122
|
+
'SELECT la.id, la.name FROM la WHERE (la.id IN (2, 1))'].should include(sqls.pop)
|
123
|
+
sqls.should == ['SELECT la.id FROM la']
|
120
124
|
end
|
121
125
|
|
122
126
|
it "should not eagerly load the attribute if model instance is frozen, and deal with other frozen instances if not frozen" do
|
123
127
|
ms = @c.all
|
124
128
|
ms.first.freeze
|
125
129
|
ms.map{|m| m.name}.should == %w'1 2'
|
126
|
-
@db.sqls.should == ['SELECT id FROM la', 'SELECT name FROM la WHERE (id = 1) LIMIT 1', 'SELECT id, name FROM la WHERE (id IN (2))']
|
130
|
+
@db.sqls.should == ['SELECT la.id FROM la', 'SELECT la.name FROM la WHERE (id = 1) LIMIT 1', 'SELECT la.id, la.name FROM la WHERE (la.id IN (2))']
|
127
131
|
end
|
128
132
|
|
129
133
|
it "should add the accessors to a module included in the class, so they can be easily overridden" do
|
@@ -137,9 +141,9 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
137
141
|
ms.map{|m| m.name}.should == %w'1-blah 2-blah'
|
138
142
|
ms.map{|m| m.values}.should == [{:id=>1, :name=>'1'}, {:id=>2, :name=>'2'}]
|
139
143
|
sqls = @db.sqls
|
140
|
-
['SELECT id, name FROM la WHERE (id IN (1, 2))',
|
141
|
-
'SELECT id, name FROM la WHERE (id IN (2, 1))'].should include(sqls.pop)
|
142
|
-
sqls.should == ['SELECT id FROM la']
|
144
|
+
['SELECT la.id, la.name FROM la WHERE (la.id IN (1, 2))',
|
145
|
+
'SELECT la.id, la.name FROM la WHERE (la.id IN (2, 1))'].should include(sqls.pop)
|
146
|
+
sqls.should == ['SELECT la.id FROM la']
|
143
147
|
end
|
144
148
|
|
145
149
|
it "should work with the serialization plugin" do
|
@@ -152,15 +156,15 @@ describe "Sequel::Plugins::LazyAttributes" do
|
|
152
156
|
ms.map{|m| m.deserialized_values}.should == [{:name=>3}, {:name=>6}]
|
153
157
|
ms.map{|m| m.name}.should == [3,6]
|
154
158
|
sqls = @db.sqls
|
155
|
-
['SELECT id, name FROM la WHERE (id IN (1, 2))',
|
156
|
-
'SELECT id, name FROM la WHERE (id IN (2, 1))'].should include(sqls.pop)
|
157
|
-
sqls.should == ['SELECT id FROM la']
|
159
|
+
['SELECT la.id, la.name FROM la WHERE (la.id IN (1, 2))',
|
160
|
+
'SELECT la.id, la.name FROM la WHERE (la.id IN (2, 1))'].should include(sqls.pop)
|
161
|
+
sqls.should == ['SELECT la.id FROM la']
|
158
162
|
m = @ds.first
|
159
163
|
m.values.should == {:id=>1}
|
160
164
|
m.name.should == 3
|
161
165
|
m.values.should == {:id=>1, :name=>"--- 3\n"}
|
162
166
|
m.deserialized_values.should == {:name=>3}
|
163
167
|
m.name.should == 3
|
164
|
-
@db.sqls.should == ["SELECT id FROM la LIMIT 1", "SELECT name FROM la WHERE (id = 1) LIMIT 1"]
|
168
|
+
@db.sqls.should == ["SELECT la.id FROM la LIMIT 1", "SELECT la.name FROM la WHERE (id = 1) LIMIT 1"]
|
165
169
|
end
|
166
170
|
end
|