sequel 4.12.0 → 4.13.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.
- 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
|