sequel 3.28.0 → 3.29.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +119 -3
- data/Rakefile +5 -3
- data/bin/sequel +1 -5
- data/doc/model_hooks.rdoc +9 -1
- data/doc/opening_databases.rdoc +49 -40
- data/doc/prepared_statements.rdoc +27 -6
- data/doc/release_notes/3.28.0.txt +2 -2
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +18 -9
- data/doc/transactions.rdoc +41 -1
- data/lib/sequel/adapters/ado.rb +28 -17
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/amalgalite.rb +11 -7
- data/lib/sequel/adapters/db2.rb +122 -70
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do.rb +5 -36
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/firebird.rb +3 -6
- data/lib/sequel/adapters/ibmdb.rb +24 -16
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +47 -11
- data/lib/sequel/adapters/jdbc/as400.rb +5 -24
- data/lib/sequel/adapters/jdbc/db2.rb +0 -5
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
- data/lib/sequel/adapters/jdbc/h2.rb +10 -12
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
- data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +64 -51
- data/lib/sequel/adapters/mysql2.rb +15 -9
- data/lib/sequel/adapters/odbc.rb +13 -6
- data/lib/sequel/adapters/odbc/db2.rb +0 -4
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +333 -51
- data/lib/sequel/adapters/postgres.rb +80 -27
- data/lib/sequel/adapters/shared/access.rb +0 -6
- data/lib/sequel/adapters/shared/db2.rb +13 -15
- data/lib/sequel/adapters/shared/firebird.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +23 -18
- data/lib/sequel/adapters/shared/mysql.rb +6 -6
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -30
- data/lib/sequel/adapters/shared/postgres.rb +35 -18
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +116 -37
- data/lib/sequel/adapters/sqlite.rb +16 -8
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/tinytds.rb +13 -10
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
- data/lib/sequel/core.rb +40 -0
- data/lib/sequel/database/connecting.rb +1 -2
- data/lib/sequel/database/dataset.rb +3 -3
- data/lib/sequel/database/dataset_defaults.rb +58 -0
- data/lib/sequel/database/misc.rb +62 -2
- data/lib/sequel/database/query.rb +113 -49
- data/lib/sequel/database/schema_methods.rb +7 -2
- data/lib/sequel/dataset/actions.rb +37 -19
- data/lib/sequel/dataset/features.rb +24 -0
- data/lib/sequel/dataset/graph.rb +7 -6
- data/lib/sequel/dataset/misc.rb +11 -3
- data/lib/sequel/dataset/mutation.rb +2 -3
- data/lib/sequel/dataset/prepared_statements.rb +6 -4
- data/lib/sequel/dataset/query.rb +46 -15
- data/lib/sequel/dataset/sql.rb +28 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/model.rb +2 -1
- data/lib/sequel/model/associations.rb +115 -33
- data/lib/sequel/model/base.rb +91 -31
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +6 -10
- data/lib/sequel/plugins/prepared_statements.rb +12 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/sharding.rb +0 -5
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/timezones.rb +42 -42
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +29 -29
- data/spec/adapters/mysql_spec.rb +86 -104
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +98 -33
- data/spec/adapters/spec_helper.rb +0 -5
- data/spec/adapters/sqlite_spec.rb +24 -21
- data/spec/core/connection_pool_spec.rb +9 -15
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +491 -227
- data/spec/core/dataset_spec.rb +638 -1051
- data/spec/core/expression_filters_spec.rb +0 -1
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +51 -114
- data/spec/core/spec_helper.rb +3 -90
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +3 -0
- data/spec/extensions/schema_spec.rb +1 -1
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/spec_helper.rb +4 -0
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/integration/associations_test.rb +123 -12
- data/spec/integration/dataset_test.rb +140 -47
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +179 -128
- data/spec/integration/prepared_statement_test.rb +92 -91
- data/spec/integration/schema_test.rb +42 -23
- data/spec/integration/spec_helper.rb +25 -31
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +161 -34
- data/spec/integration/type_test.rb +3 -3
- data/spec/model/association_reflection_spec.rb +83 -7
- data/spec/model/associations_spec.rb +393 -676
- data/spec/model/base_spec.rb +186 -116
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +343 -867
- data/spec/model/hooks_spec.rb +160 -79
- data/spec/model/model_spec.rb +118 -165
- data/spec/model/plugins_spec.rb +7 -13
- data/spec/model/record_spec.rb +138 -207
- data/spec/model/spec_helper.rb +10 -73
- metadata +14 -8
data/lib/sequel/timezones.rb
CHANGED
@@ -39,6 +39,48 @@ module Sequel
|
|
39
39
|
convert_output_timestamp(v, Sequel.database_timezone)
|
40
40
|
end
|
41
41
|
|
42
|
+
# Converts the object to the given +output_timezone+.
|
43
|
+
def convert_output_timestamp(v, output_timezone)
|
44
|
+
if output_timezone
|
45
|
+
if v.is_a?(DateTime)
|
46
|
+
case output_timezone
|
47
|
+
when :utc
|
48
|
+
v.new_offset(0)
|
49
|
+
when :local
|
50
|
+
v.new_offset(local_offset_for_datetime(v))
|
51
|
+
else
|
52
|
+
convert_output_datetime_other(v, output_timezone)
|
53
|
+
end
|
54
|
+
else
|
55
|
+
v.send(output_timezone == :utc ? :getutc : :getlocal)
|
56
|
+
end
|
57
|
+
else
|
58
|
+
v
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Converts the given object from the given input timezone to the
|
63
|
+
# +application_timezone+ using +convert_input_timestamp+ and
|
64
|
+
# +convert_output_timestamp+.
|
65
|
+
def convert_timestamp(v, input_timezone)
|
66
|
+
begin
|
67
|
+
if v.is_a?(Date) && !v.is_a?(DateTime)
|
68
|
+
# Dates handled specially as they are assumed to already be in the application_timezone
|
69
|
+
if datetime_class == DateTime
|
70
|
+
DateTime.civil(v.year, v.month, v.day, 0, 0, 0, application_timezone == :local ? (defined?(Rational) ? Rational(Time.local(v.year, v.month, v.day).utc_offset, 86400) : Time.local(v.year, v.month, v.day).utc_offset/86400.0) : 0)
|
71
|
+
else
|
72
|
+
Time.send(application_timezone == :utc ? :utc : :local, v.year, v.month, v.day)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
convert_output_timestamp(convert_input_timestamp(v, input_timezone), application_timezone)
|
76
|
+
end
|
77
|
+
rescue InvalidValue
|
78
|
+
raise
|
79
|
+
rescue => e
|
80
|
+
raise convert_exception_class(e, InvalidValue)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
42
84
|
# Convert the given object into an object of <tt>Sequel.datetime_class</tt> in the
|
43
85
|
# +application_timezone+. Used when coverting datetime/timestamp columns
|
44
86
|
# returned by the database.
|
@@ -135,48 +177,6 @@ module Sequel
|
|
135
177
|
raise InvalidValue, "Invalid output_timezone: #{output_timezone.inspect}"
|
136
178
|
end
|
137
179
|
|
138
|
-
# Converts the object to the given +output_timezone+.
|
139
|
-
def convert_output_timestamp(v, output_timezone)
|
140
|
-
if output_timezone
|
141
|
-
if v.is_a?(DateTime)
|
142
|
-
case output_timezone
|
143
|
-
when :utc
|
144
|
-
v.new_offset(0)
|
145
|
-
when :local
|
146
|
-
v.new_offset(local_offset_for_datetime(v))
|
147
|
-
else
|
148
|
-
convert_output_datetime_other(v, output_timezone)
|
149
|
-
end
|
150
|
-
else
|
151
|
-
v.send(output_timezone == :utc ? :getutc : :getlocal)
|
152
|
-
end
|
153
|
-
else
|
154
|
-
v
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
# Converts the given object from the given input timezone to the
|
159
|
-
# +application_timezone+ using +convert_input_timestamp+ and
|
160
|
-
# +convert_output_timestamp+.
|
161
|
-
def convert_timestamp(v, input_timezone)
|
162
|
-
begin
|
163
|
-
if v.is_a?(Date) && !v.is_a?(DateTime)
|
164
|
-
# Dates handled specially as they are assumed to already be in the application_timezone
|
165
|
-
if datetime_class == DateTime
|
166
|
-
DateTime.civil(v.year, v.month, v.day, 0, 0, 0, application_timezone == :local ? (defined?(Rational) ? Rational(Time.local(v.year, v.month, v.day).utc_offset, 86400) : Time.local(v.year, v.month, v.day).utc_offset/86400.0) : 0)
|
167
|
-
else
|
168
|
-
Time.send(application_timezone == :utc ? :utc : :local, v.year, v.month, v.day)
|
169
|
-
end
|
170
|
-
else
|
171
|
-
convert_output_timestamp(convert_input_timestamp(v, input_timezone), application_timezone)
|
172
|
-
end
|
173
|
-
rescue InvalidValue
|
174
|
-
raise
|
175
|
-
rescue => e
|
176
|
-
raise convert_exception_class(e, InvalidValue)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
180
|
# Convert the timezone setter argument. Returns argument given by default,
|
181
181
|
# exists for easier overriding in extensions.
|
182
182
|
def convert_timezone_setter_arg(tz)
|
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 = 29
|
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/mssql_spec.rb
CHANGED
@@ -63,12 +63,12 @@ end
|
|
63
63
|
describe "MSSQL Dataset#join_table" do
|
64
64
|
specify "should emulate the USING clause with ON" do
|
65
65
|
MSSQL_DB[:items].join(:categories, [:id]).sql.should ==
|
66
|
-
'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON (CATEGORIES.ID = ITEMS.ID)'
|
67
|
-
['SELECT * FROM ITEMS INNER JOIN CATEGORIES ON ((CATEGORIES.ID1 = ITEMS.ID1) AND (CATEGORIES.ID2 = ITEMS.ID2))',
|
68
|
-
'SELECT * FROM ITEMS INNER JOIN CATEGORIES ON ((CATEGORIES.ID2 = ITEMS.ID2) AND (CATEGORIES.ID1 = ITEMS.ID1))'].
|
66
|
+
'SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON ([CATEGORIES].[ID] = [ITEMS].[ID])'
|
67
|
+
['SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON (([CATEGORIES].[ID1] = [ITEMS].[ID1]) AND ([CATEGORIES].[ID2] = [ITEMS].[ID2]))',
|
68
|
+
'SELECT * FROM [ITEMS] INNER JOIN [CATEGORIES] ON (([CATEGORIES].[ID2] = [ITEMS].[ID2]) AND ([CATEGORIES].[ID1] = [ITEMS].[ID1]))'].
|
69
69
|
should include(MSSQL_DB[:items].join(:categories, [:id1, :id2]).sql)
|
70
70
|
MSSQL_DB[:items___i].join(:categories___c, [:id]).sql.should ==
|
71
|
-
'SELECT * FROM ITEMS AS I INNER JOIN CATEGORIES AS C ON (C.ID = I.ID)'
|
71
|
+
'SELECT * FROM [ITEMS] AS [I] INNER JOIN [CATEGORIES] AS [C] ON ([C].[ID] = [I].[ID])'
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -86,44 +86,44 @@ describe "MSSQL Dataset#output" do
|
|
86
86
|
|
87
87
|
specify "should format OUTPUT clauses without INTO for DELETE statements" do
|
88
88
|
@ds.output(nil, [:deleted__name, :deleted__value]).delete_sql.should =~
|
89
|
-
/DELETE FROM ITEMS OUTPUT DELETED
|
89
|
+
/DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\]/
|
90
90
|
@ds.output(nil, [:deleted.*]).delete_sql.should =~
|
91
|
-
/DELETE FROM ITEMS OUTPUT DELETED.*/
|
91
|
+
/DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].*/
|
92
92
|
end
|
93
93
|
|
94
94
|
specify "should format OUTPUT clauses with INTO for DELETE statements" do
|
95
95
|
@ds.output(:out, [:deleted__name, :deleted__value]).delete_sql.should =~
|
96
|
-
/DELETE FROM ITEMS OUTPUT DELETED
|
96
|
+
/DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\] INTO \[OUT\]/
|
97
97
|
@ds.output(:out, {:name => :deleted__name, :value => :deleted__value}).delete_sql.should =~
|
98
|
-
/DELETE FROM ITEMS OUTPUT DELETED
|
98
|
+
/DELETE FROM \[ITEMS\] OUTPUT \[DELETED\].\[(NAME|VALUE)\], \[DELETED\].\[(NAME|VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\)/
|
99
99
|
end
|
100
100
|
|
101
101
|
specify "should format OUTPUT clauses without INTO for INSERT statements" do
|
102
102
|
@ds.output(nil, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
|
103
|
-
/INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED
|
103
|
+
/INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] VALUES \((N'name'|1), (N'name'|1)\)/
|
104
104
|
@ds.output(nil, [:inserted.*]).insert_sql(:name => "name", :value => 1).should =~
|
105
|
-
/INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED.* VALUES \((N'name'|1), (N'name'|1)\)/
|
105
|
+
/INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].* VALUES \((N'name'|1), (N'name'|1)\)/
|
106
106
|
end
|
107
107
|
|
108
108
|
specify "should format OUTPUT clauses with INTO for INSERT statements" do
|
109
109
|
@ds.output(:out, [:inserted__name, :inserted__value]).insert_sql(:name => "name", :value => 1).should =~
|
110
|
-
/INSERT INTO ITEMS \((NAME
|
110
|
+
/INSERT INTO \[ITEMS\] \((\[NAME\]|\[VALUE\]), (\[NAME\]|\[VALUE\])\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] INTO \[OUT\] VALUES \((N'name'|1), (N'name'|1)\)/
|
111
111
|
@ds.output(:out, {:name => :inserted__name, :value => :inserted__value}).insert_sql(:name => "name", :value => 1).should =~
|
112
|
-
/INSERT INTO ITEMS \((NAME|VALUE), (NAME|VALUE)\) OUTPUT INSERTED
|
112
|
+
/INSERT INTO \[ITEMS\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) OUTPUT \[INSERTED\].\[(NAME|VALUE)\], \[INSERTED\].\[(NAME|VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\) VALUES \((N'name'|1), (N'name'|1)\)/
|
113
113
|
end
|
114
114
|
|
115
115
|
specify "should format OUTPUT clauses without INTO for UPDATE statements" do
|
116
116
|
@ds.output(nil, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
|
117
|
-
/UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED
|
117
|
+
/UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\]/
|
118
118
|
@ds.output(nil, [:inserted.*]).update_sql(:value => 2).should =~
|
119
|
-
/UPDATE ITEMS SET VALUE = 2 OUTPUT INSERTED.*/
|
119
|
+
/UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[INSERTED\].*/
|
120
120
|
end
|
121
121
|
|
122
122
|
specify "should format OUTPUT clauses with INTO for UPDATE statements" do
|
123
123
|
@ds.output(:out, [:inserted__name, :deleted__value]).update_sql(:value => 2).should =~
|
124
|
-
/UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED
|
124
|
+
/UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\] INTO \[OUT\]/
|
125
125
|
@ds.output(:out, {:name => :inserted__name, :value => :deleted__value}).update_sql(:value => 2).should =~
|
126
|
-
/UPDATE ITEMS SET VALUE = 2 OUTPUT (INSERTED
|
126
|
+
/UPDATE \[ITEMS\] SET \[VALUE\] = 2 OUTPUT \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\], \[(INSERTED\].\[NAME|DELETED\].\[VALUE)\] INTO \[OUT\] \(\[(NAME|VALUE)\], \[(NAME|VALUE)\]\)/
|
127
127
|
end
|
128
128
|
|
129
129
|
specify "should execute OUTPUT clauses in DELETE statements" do
|
@@ -164,23 +164,23 @@ describe "MSSQL dataset" do
|
|
164
164
|
end
|
165
165
|
|
166
166
|
specify "should prepend UPDATE statements with WITH clause" do
|
167
|
-
@ds1.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X) UPDATE T SET X = Y'
|
168
|
-
@ds2.update_sql(:x => :y).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) UPDATE T SET X = Y'
|
167
|
+
@ds1.update_sql(:x => :y).should == 'WITH [T] AS (SELECT * FROM [X]) UPDATE [T] SET [X] = [Y]'
|
168
|
+
@ds2.update_sql(:x => :y).should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) UPDATE [T] SET [X] = [Y]'
|
169
169
|
end
|
170
170
|
|
171
171
|
specify "should prepend DELETE statements with WITH clause" do
|
172
|
-
@ds1.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X) DELETE FROM T WHERE (Y = 1)'
|
173
|
-
@ds2.filter(:y => 1).delete_sql.should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) DELETE FROM T WHERE (Y = 1)'
|
172
|
+
@ds1.filter(:y => 1).delete_sql.should == 'WITH [T] AS (SELECT * FROM [X]) DELETE FROM [T] WHERE ([Y] = 1)'
|
173
|
+
@ds2.filter(:y => 1).delete_sql.should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) DELETE FROM [T] WHERE ([Y] = 1)'
|
174
174
|
end
|
175
175
|
|
176
176
|
specify "should prepend INSERT statements with WITH clause" do
|
177
|
-
@ds1.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X) INSERT INTO T SELECT * FROM T'
|
178
|
-
@ds2.insert_sql(@db[:t]).should == 'WITH T AS (SELECT * FROM X UNION ALL SELECT * FROM T) INSERT INTO T SELECT * FROM T'
|
177
|
+
@ds1.insert_sql(@db[:t]).should == 'WITH [T] AS (SELECT * FROM [X]) INSERT INTO [T] SELECT * FROM [T]'
|
178
|
+
@ds2.insert_sql(@db[:t]).should == 'WITH [T] AS (SELECT * FROM [X] UNION ALL SELECT * FROM [T]) INSERT INTO [T] SELECT * FROM [T]'
|
179
179
|
end
|
180
180
|
|
181
181
|
specify "should move WITH clause on joined dataset to top level" do
|
182
|
-
@db[:s].inner_join(@ds1).sql.should == "WITH T AS (SELECT * FROM X) SELECT * FROM S INNER JOIN (SELECT * FROM T) AS T1"
|
183
|
-
@ds1.inner_join(@db[:s].with(:s, @db[:y])).sql.should == "WITH T AS (SELECT * FROM X), S AS (SELECT * FROM Y) SELECT * FROM T INNER JOIN (SELECT * FROM S) AS T1"
|
182
|
+
@db[:s].inner_join(@ds1).sql.should == "WITH [T] AS (SELECT * FROM [X]) SELECT * FROM [S] INNER JOIN (SELECT * FROM [T]) AS [T1]"
|
183
|
+
@ds1.inner_join(@db[:s].with(:s, @db[:y])).sql.should == "WITH [T] AS (SELECT * FROM [X]), [S] AS (SELECT * FROM [Y]) SELECT * FROM [T] INNER JOIN (SELECT * FROM [S]) AS [T1]"
|
184
184
|
end
|
185
185
|
|
186
186
|
describe "on #import" do
|
@@ -208,10 +208,10 @@ describe "MSSQL dataset" do
|
|
208
208
|
@db[:items].with(:items, @db[:inventory].group(:type)).import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
209
209
|
@db.import_sqls.should == [
|
210
210
|
'BEGIN',
|
211
|
-
"WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 1, 2 UNION ALL SELECT 3, 4",
|
211
|
+
"WITH [ITEMS] AS (SELECT * FROM [INVENTORY] GROUP BY [TYPE]) INSERT INTO [ITEMS] ([X], [Y]) SELECT 1, 2 UNION ALL SELECT 3, 4",
|
212
212
|
'COMMIT',
|
213
213
|
'BEGIN',
|
214
|
-
"WITH ITEMS AS (SELECT * FROM INVENTORY GROUP BY TYPE) INSERT INTO ITEMS (X, Y) SELECT 5, 6",
|
214
|
+
"WITH [ITEMS] AS (SELECT * FROM [INVENTORY] GROUP BY [TYPE]) INSERT INTO [ITEMS] ([X], [Y]) SELECT 5, 6",
|
215
215
|
'COMMIT'
|
216
216
|
]
|
217
217
|
end
|
@@ -226,12 +226,12 @@ describe "MSSQL joined datasets" do
|
|
226
226
|
|
227
227
|
specify "should format DELETE statements" do
|
228
228
|
@db[:t1].inner_join(:t2, :t1__pk => :t2__pk).delete_sql.should ==
|
229
|
-
"DELETE FROM T1 FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
|
229
|
+
"DELETE FROM [T1] FROM [T1] INNER JOIN [T2] ON ([T1].[PK] = [T2].[PK])"
|
230
230
|
end
|
231
231
|
|
232
232
|
specify "should format UPDATE statements" do
|
233
233
|
@db[:t1].inner_join(:t2, :t1__pk => :t2__pk).update_sql(:pk => :t2__pk).should ==
|
234
|
-
"UPDATE T1 SET PK = T2.PK FROM T1 INNER JOIN T2 ON (T1.PK = T2.PK)"
|
234
|
+
"UPDATE [T1] SET [PK] = [T2].[PK] FROM [T1] INNER JOIN [T2] ON ([T1].[PK] = [T2].[PK])"
|
235
235
|
end
|
236
236
|
end
|
237
237
|
|
@@ -370,7 +370,7 @@ describe "MSSSQL::Dataset#into" do
|
|
370
370
|
end
|
371
371
|
|
372
372
|
specify "should format SELECT statement" do
|
373
|
-
@db[:t].into(:new).select_sql.should == "SELECT * INTO NEW FROM T"
|
373
|
+
@db[:t].into(:new).select_sql.should == "SELECT * INTO [NEW] FROM [T]"
|
374
374
|
end
|
375
375
|
|
376
376
|
specify "should select rows into a new table" do
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -45,22 +45,22 @@ describe "MySQL", '#create_table' do
|
|
45
45
|
|
46
46
|
specify "should allow to specify options for MySQL" do
|
47
47
|
@db.create_table(:dolls, :engine => 'MyISAM', :charset => 'latin2'){text :name}
|
48
|
-
@db.sqls.should == ["CREATE TABLE dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
|
48
|
+
@db.sqls.should == ["CREATE TABLE `dolls` (`name` text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
|
49
49
|
end
|
50
50
|
|
51
51
|
specify "should create a temporary table" do
|
52
52
|
@db.create_table(:tmp_dolls, :temp => true, :engine => 'MyISAM', :charset => 'latin2'){text :name}
|
53
|
-
@db.sqls.should == ["CREATE TEMPORARY TABLE tmp_dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
|
53
|
+
@db.sqls.should == ["CREATE TEMPORARY TABLE `tmp_dolls` (`name` text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
|
54
54
|
end
|
55
55
|
|
56
56
|
specify "should not use a default for a String :text=>true type" do
|
57
57
|
@db.create_table(:dolls){String :name, :text=>true, :default=>'blah'}
|
58
|
-
@db.sqls.should == ["CREATE TABLE dolls (name text)"]
|
58
|
+
@db.sqls.should == ["CREATE TABLE `dolls` (`name` text)"]
|
59
59
|
end
|
60
60
|
|
61
61
|
specify "should not use a default for a File type" do
|
62
62
|
@db.create_table(:dolls){File :name, :default=>'blah'}
|
63
|
-
@db.sqls.should == ["CREATE TABLE dolls (name blob)"]
|
63
|
+
@db.sqls.should == ["CREATE TABLE `dolls` (`name` blob)"]
|
64
64
|
end
|
65
65
|
|
66
66
|
specify "should respect the size option for File type" do
|
@@ -112,18 +112,18 @@ if MYSQL_DB.adapter_scheme == :mysql
|
|
112
112
|
@ds = @db[:booltest]
|
113
113
|
end
|
114
114
|
after do
|
115
|
-
|
115
|
+
@db.convert_tinyint_to_bool = true
|
116
116
|
@db.drop_table(:booltest)
|
117
117
|
end
|
118
118
|
|
119
119
|
specify "should consider tinyint(1) datatypes as boolean if set, but not larger tinyints" do
|
120
120
|
@db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:boolean, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
|
121
|
-
|
121
|
+
@db.convert_tinyint_to_bool = false
|
122
122
|
@db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
|
123
123
|
end
|
124
124
|
|
125
125
|
specify "should return tinyint(1)s as bools and tinyint(4)s as integers when set" do
|
126
|
-
|
126
|
+
@db.convert_tinyint_to_bool = true
|
127
127
|
@ds.delete
|
128
128
|
@ds << {:b=>true, :i=>10}
|
129
129
|
@ds.all.should == [{:b=>true, :i=>10}]
|
@@ -136,7 +136,7 @@ if MYSQL_DB.adapter_scheme == :mysql
|
|
136
136
|
end
|
137
137
|
|
138
138
|
specify "should return all tinyints as integers when unset" do
|
139
|
-
|
139
|
+
@db.convert_tinyint_to_bool = false
|
140
140
|
@ds.delete
|
141
141
|
@ds << {:b=>true, :i=>10}
|
142
142
|
@ds.all.should == [{:b=>1, :i=>10}]
|
@@ -226,12 +226,12 @@ describe "A MySQL dataset" do
|
|
226
226
|
|
227
227
|
specify "should support ORDER clause in UPDATE statements" do
|
228
228
|
@d.order(:name).update_sql(:value => 1).should == \
|
229
|
-
'UPDATE items SET value = 1 ORDER BY name'
|
229
|
+
'UPDATE `items` SET `value` = 1 ORDER BY `name`'
|
230
230
|
end
|
231
231
|
|
232
232
|
specify "should support LIMIT clause in UPDATE statements" do
|
233
233
|
@d.limit(10).update_sql(:value => 1).should == \
|
234
|
-
'UPDATE items SET value = 1 LIMIT 10'
|
234
|
+
'UPDATE `items` SET `value` = 1 LIMIT 10'
|
235
235
|
end
|
236
236
|
|
237
237
|
specify "should support regexps" do
|
@@ -299,43 +299,43 @@ describe "MySQL join expressions" do
|
|
299
299
|
end
|
300
300
|
specify "should support natural left joins" do
|
301
301
|
@ds.join_table(:natural_left, :nodes).sql.should == \
|
302
|
-
'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
|
302
|
+
'SELECT * FROM `nodes` NATURAL LEFT JOIN `nodes`'
|
303
303
|
end
|
304
304
|
specify "should support natural right joins" do
|
305
305
|
@ds.join_table(:natural_right, :nodes).sql.should == \
|
306
|
-
'SELECT * FROM nodes NATURAL RIGHT JOIN nodes'
|
306
|
+
'SELECT * FROM `nodes` NATURAL RIGHT JOIN `nodes`'
|
307
307
|
end
|
308
308
|
specify "should support natural left outer joins" do
|
309
309
|
@ds.join_table(:natural_left_outer, :nodes).sql.should == \
|
310
|
-
'SELECT * FROM nodes NATURAL LEFT OUTER JOIN nodes'
|
310
|
+
'SELECT * FROM `nodes` NATURAL LEFT OUTER JOIN `nodes`'
|
311
311
|
end
|
312
312
|
specify "should support natural right outer joins" do
|
313
313
|
@ds.join_table(:natural_right_outer, :nodes).sql.should == \
|
314
|
-
'SELECT * FROM nodes NATURAL RIGHT OUTER JOIN nodes'
|
314
|
+
'SELECT * FROM `nodes` NATURAL RIGHT OUTER JOIN `nodes`'
|
315
315
|
end
|
316
316
|
specify "should support natural inner joins" do
|
317
317
|
@ds.join_table(:natural_inner, :nodes).sql.should == \
|
318
|
-
'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
|
318
|
+
'SELECT * FROM `nodes` NATURAL LEFT JOIN `nodes`'
|
319
319
|
end
|
320
320
|
specify "should support cross joins" do
|
321
321
|
@ds.join_table(:cross, :nodes).sql.should == \
|
322
|
-
'SELECT * FROM nodes CROSS JOIN nodes'
|
322
|
+
'SELECT * FROM `nodes` CROSS JOIN `nodes`'
|
323
323
|
end
|
324
324
|
specify "should support cross joins as inner joins if conditions are used" do
|
325
325
|
@ds.join_table(:cross, :nodes, :id=>:id).sql.should == \
|
326
|
-
'SELECT * FROM nodes INNER JOIN nodes ON (nodes
|
326
|
+
'SELECT * FROM `nodes` INNER JOIN `nodes` ON (`nodes`.`id` = `nodes`.`id`)'
|
327
327
|
end
|
328
328
|
specify "should support straight joins (force left table to be read before right)" do
|
329
329
|
@ds.join_table(:straight, :nodes).sql.should == \
|
330
|
-
'SELECT * FROM nodes STRAIGHT_JOIN nodes'
|
330
|
+
'SELECT * FROM `nodes` STRAIGHT_JOIN `nodes`'
|
331
331
|
end
|
332
332
|
specify "should support natural joins on multiple tables." do
|
333
333
|
@ds.join_table(:natural_left_outer, [:nodes, :branches]).sql.should == \
|
334
|
-
'SELECT * FROM nodes NATURAL LEFT OUTER JOIN (nodes
|
334
|
+
'SELECT * FROM `nodes` NATURAL LEFT OUTER JOIN (`nodes`, `branches`)'
|
335
335
|
end
|
336
336
|
specify "should support straight joins on multiple tables." do
|
337
337
|
@ds.join_table(:straight, [:nodes,:branches]).sql.should == \
|
338
|
-
'SELECT * FROM nodes STRAIGHT_JOIN (nodes
|
338
|
+
'SELECT * FROM `nodes` STRAIGHT_JOIN (`nodes`, `branches`)'
|
339
339
|
end
|
340
340
|
end
|
341
341
|
|
@@ -354,12 +354,12 @@ describe "Joined MySQL dataset" do
|
|
354
354
|
proc {@ds.having('blah')}.should_not raise_error
|
355
355
|
|
356
356
|
@ds.having('blah').sql.should == \
|
357
|
-
"SELECT * FROM nodes HAVING (blah)"
|
357
|
+
"SELECT * FROM `nodes` HAVING (blah)"
|
358
358
|
end
|
359
359
|
|
360
360
|
specify "should put a having clause before an order by clause" do
|
361
361
|
@ds.order(:aaa).having(:bbb => :ccc).sql.should == \
|
362
|
-
"SELECT * FROM nodes HAVING (bbb = ccc) ORDER BY aaa"
|
362
|
+
"SELECT * FROM `nodes` HAVING (`bbb` = `ccc`) ORDER BY `aaa`"
|
363
363
|
end
|
364
364
|
end
|
365
365
|
|
@@ -453,17 +453,17 @@ describe "A MySQL database with table options" do
|
|
453
453
|
|
454
454
|
specify "should allow to pass custom options (engine, charset, collate) for table creation" do
|
455
455
|
@db.create_table(:items, @options){Integer :size; text :name}
|
456
|
-
@db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=MyISAM DEFAULT CHARSET=latin1 DEFAULT COLLATE=latin1_swedish_ci"]
|
456
|
+
@db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text) ENGINE=MyISAM DEFAULT CHARSET=latin1 DEFAULT COLLATE=latin1_swedish_ci"]
|
457
457
|
end
|
458
458
|
|
459
459
|
specify "should use default options if specified (engine, charset, collate) for table creation" do
|
460
460
|
@db.create_table(:items){Integer :size; text :name}
|
461
|
-
@db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci"]
|
461
|
+
@db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci"]
|
462
462
|
end
|
463
463
|
|
464
464
|
specify "should not use default if option has a nil value" do
|
465
465
|
@db.create_table(:items, :engine=>nil, :charset=>nil, :collate=>nil){Integer :size; text :name}
|
466
|
-
@db.sqls.should == ["CREATE TABLE items (size integer, name text)"]
|
466
|
+
@db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text)"]
|
467
467
|
end
|
468
468
|
end
|
469
469
|
|
@@ -479,24 +479,24 @@ describe "A MySQL database" do
|
|
479
479
|
|
480
480
|
specify "should support defaults for boolean columns" do
|
481
481
|
@db.create_table(:items){TrueClass :active1, :default=>true; FalseClass :active2, :default => false}
|
482
|
-
@db.sqls.should == ["CREATE TABLE items (active1 tinyint(1) DEFAULT 1, active2 tinyint(1) DEFAULT 0)"]
|
482
|
+
@db.sqls.should == ["CREATE TABLE `items` (`active1` tinyint(1) DEFAULT 1, `active2` tinyint(1) DEFAULT 0)"]
|
483
483
|
end
|
484
484
|
|
485
485
|
specify "should correctly format CREATE TABLE statements with foreign keys" do
|
486
486
|
@db.create_table(:items){Integer :id; foreign_key :p_id, :items, :key => :id, :null => false, :on_delete => :cascade}
|
487
|
-
@db.sqls.should == ["CREATE TABLE items (id integer, p_id integer NOT NULL, FOREIGN KEY (p_id) REFERENCES items(id) ON DELETE CASCADE)"]
|
487
|
+
@db.sqls.should == ["CREATE TABLE `items` (`id` integer, `p_id` integer NOT NULL, FOREIGN KEY (`p_id`) REFERENCES `items`(`id`) ON DELETE CASCADE)"]
|
488
488
|
end
|
489
489
|
|
490
490
|
specify "should correctly format ALTER TABLE statements with foreign keys" do
|
491
491
|
@db.create_table(:items){Integer :id}
|
492
492
|
@db.alter_table(:items){add_foreign_key :p_id, :users, :key => :id, :null => false, :on_delete => :cascade}
|
493
|
-
@db.sqls.should == ["CREATE TABLE items (id integer)", "ALTER TABLE items ADD COLUMN p_id integer NOT NULL", "ALTER TABLE items ADD FOREIGN KEY (p_id) REFERENCES users(id) ON DELETE CASCADE"]
|
493
|
+
@db.sqls.should == ["CREATE TABLE `items` (`id` integer)", "ALTER TABLE `items` ADD COLUMN `p_id` integer NOT NULL", "ALTER TABLE `items` ADD FOREIGN KEY (`p_id`) REFERENCES `users`(`id`) ON DELETE CASCADE"]
|
494
494
|
end
|
495
495
|
|
496
496
|
specify "should have rename_column support keep existing options" do
|
497
497
|
@db.create_table(:items){String :id, :null=>false, :default=>'blah'}
|
498
498
|
@db.alter_table(:items){rename_column :id, :nid}
|
499
|
-
@db.sqls.should == ["CREATE TABLE items (id varchar(255) NOT NULL DEFAULT 'blah')", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id nid varchar(255) NOT NULL DEFAULT 'blah'"]
|
499
|
+
@db.sqls.should == ["CREATE TABLE `items` (`id` varchar(255) NOT NULL DEFAULT 'blah')", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `nid` varchar(255) NOT NULL DEFAULT 'blah'"]
|
500
500
|
@db[:items].insert
|
501
501
|
@db[:items].all.should == [{:nid=>'blah'}]
|
502
502
|
proc{@db[:items].insert(:nid=>nil)}.should raise_error(Sequel::DatabaseError)
|
@@ -505,7 +505,7 @@ describe "A MySQL database" do
|
|
505
505
|
specify "should have set_column_type support keep existing options" do
|
506
506
|
@db.create_table(:items){Integer :id, :null=>false, :default=>5}
|
507
507
|
@db.alter_table(:items){set_column_type :id, Bignum}
|
508
|
-
@db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id bigint NOT NULL DEFAULT 5"]
|
508
|
+
@db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` bigint NOT NULL DEFAULT 5"]
|
509
509
|
@db[:items].insert
|
510
510
|
@db[:items].all.should == [{:id=>5}]
|
511
511
|
proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
|
@@ -517,13 +517,13 @@ describe "A MySQL database" do
|
|
517
517
|
specify "should have set_column_type pass through options" do
|
518
518
|
@db.create_table(:items){integer :id; enum :list, :elements=>%w[one]}
|
519
519
|
@db.alter_table(:items){set_column_type :id, :int, :unsigned=>true, :size=>8; set_column_type :list, :enum, :elements=>%w[two]}
|
520
|
-
@db.sqls.should == ["CREATE TABLE items (id integer, list enum('one'))", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(8) UNSIGNED NULL", "ALTER TABLE items CHANGE COLUMN list list enum('two') NULL"]
|
520
|
+
@db.sqls.should == ["CREATE TABLE `items` (`id` integer, `list` enum('one'))", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(8) UNSIGNED NULL", "ALTER TABLE `items` CHANGE COLUMN `list` `list` enum('two') NULL"]
|
521
521
|
end
|
522
522
|
|
523
523
|
specify "should have set_column_default support keep existing options" do
|
524
524
|
@db.create_table(:items){Integer :id, :null=>false, :default=>5}
|
525
525
|
@db.alter_table(:items){set_column_default :id, 6}
|
526
|
-
@db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NOT NULL DEFAULT 6"]
|
526
|
+
@db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(11) NOT NULL DEFAULT 6"]
|
527
527
|
@db[:items].insert
|
528
528
|
@db[:items].all.should == [{:id=>6}]
|
529
529
|
proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
|
@@ -532,7 +532,7 @@ describe "A MySQL database" do
|
|
532
532
|
specify "should have set_column_allow_null support keep existing options" do
|
533
533
|
@db.create_table(:items){Integer :id, :null=>false, :default=>5}
|
534
534
|
@db.alter_table(:items){set_column_allow_null :id, true}
|
535
|
-
@db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NULL DEFAULT 5"]
|
535
|
+
@db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(11) NULL DEFAULT 5"]
|
536
536
|
@db[:items].insert
|
537
537
|
@db[:items].all.should == [{:id=>5}]
|
538
538
|
proc{@db[:items].insert(:id=>nil)}.should_not
|
@@ -618,9 +618,9 @@ describe "A MySQL database" do
|
|
618
618
|
specify "should support fulltext indexes and full_text_search" do
|
619
619
|
@db.create_table(:posts){text :title; text :body; full_text_index :title; full_text_index [:title, :body]}
|
620
620
|
@db.sqls.should == [
|
621
|
-
"CREATE TABLE posts (title text, body text)",
|
622
|
-
"CREATE FULLTEXT INDEX posts_title_index ON posts (title)",
|
623
|
-
"CREATE FULLTEXT INDEX posts_title_body_index ON posts (title
|
621
|
+
"CREATE TABLE `posts` (`title` text, `body` text)",
|
622
|
+
"CREATE FULLTEXT INDEX `posts_title_index` ON `posts` (`title`)",
|
623
|
+
"CREATE FULLTEXT INDEX `posts_title_body_index` ON `posts` (`title`, `body`)"
|
624
624
|
]
|
625
625
|
|
626
626
|
@db[:posts].insert(:title=>'ruby rails', :body=>'y')
|
@@ -632,32 +632,32 @@ describe "A MySQL database" do
|
|
632
632
|
@db[:posts].full_text_search([:title, :body], ['sequel', 'ruby']).all.should == [{:title=>'sequel', :body=>'ruby'}]
|
633
633
|
@db[:posts].full_text_search(:title, '+ruby -rails', :boolean => true).all.should == [{:title=>'ruby scooby', :body=>'x'}]
|
634
634
|
@db.sqls.should == [
|
635
|
-
"SELECT * FROM posts WHERE (MATCH (title) AGAINST ('rails'))",
|
636
|
-
"SELECT * FROM posts WHERE (MATCH (title
|
637
|
-
"SELECT * FROM posts WHERE (MATCH (title) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"]
|
635
|
+
"SELECT * FROM `posts` WHERE (MATCH (`title`) AGAINST ('rails'))",
|
636
|
+
"SELECT * FROM `posts` WHERE (MATCH (`title`, `body`) AGAINST ('sequel ruby'))",
|
637
|
+
"SELECT * FROM `posts` WHERE (MATCH (`title`) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"]
|
638
638
|
end
|
639
639
|
|
640
640
|
specify "should support spatial indexes" do
|
641
641
|
@db.create_table(:posts){point :geom, :null=>false; spatial_index [:geom]}
|
642
642
|
@db.sqls.should == [
|
643
|
-
"CREATE TABLE posts (geom point NOT NULL)",
|
644
|
-
"CREATE SPATIAL INDEX posts_geom_index ON posts (geom)"
|
643
|
+
"CREATE TABLE `posts` (`geom` point NOT NULL)",
|
644
|
+
"CREATE SPATIAL INDEX `posts_geom_index` ON `posts` (`geom`)"
|
645
645
|
]
|
646
646
|
end
|
647
647
|
|
648
648
|
specify "should support indexes with index type" do
|
649
649
|
@db.create_table(:posts){Integer :id; index :id, :type => :btree}
|
650
650
|
@db.sqls.should == [
|
651
|
-
"CREATE TABLE posts (id integer)",
|
652
|
-
"CREATE INDEX posts_id_index USING btree ON posts (id)"
|
651
|
+
"CREATE TABLE `posts` (`id` integer)",
|
652
|
+
"CREATE INDEX `posts_id_index` USING btree ON `posts` (`id`)"
|
653
653
|
]
|
654
654
|
end
|
655
655
|
|
656
656
|
specify "should support unique indexes with index type" do
|
657
657
|
@db.create_table(:posts){Integer :id; index :id, :type => :btree, :unique => true}
|
658
658
|
@db.sqls.should == [
|
659
|
-
"CREATE TABLE posts (id integer)",
|
660
|
-
"CREATE UNIQUE INDEX posts_id_index USING btree ON posts (id)"
|
659
|
+
"CREATE TABLE `posts` (`id` integer)",
|
660
|
+
"CREATE UNIQUE INDEX `posts_id_index` USING btree ON `posts` (`id`)"
|
661
661
|
]
|
662
662
|
end
|
663
663
|
|
@@ -686,38 +686,20 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
686
686
|
|
687
687
|
specify "#insert should insert record with default values when no arguments given" do
|
688
688
|
@d.insert
|
689
|
-
|
690
|
-
|
691
|
-
"INSERT INTO items () VALUES ()"
|
692
|
-
]
|
693
|
-
|
694
|
-
@d.all.should == [
|
695
|
-
{:name => nil, :value => nil}
|
696
|
-
]
|
689
|
+
MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
|
690
|
+
@d.all.should == [{:name => nil, :value => nil}]
|
697
691
|
end
|
698
692
|
|
699
693
|
specify "#insert should insert record with default values when empty hash given" do
|
700
694
|
@d.insert({})
|
701
|
-
|
702
|
-
|
703
|
-
"INSERT INTO items () VALUES ()"
|
704
|
-
]
|
705
|
-
|
706
|
-
@d.all.should == [
|
707
|
-
{:name => nil, :value => nil}
|
708
|
-
]
|
695
|
+
MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
|
696
|
+
@d.all.should == [{:name => nil, :value => nil}]
|
709
697
|
end
|
710
698
|
|
711
699
|
specify "#insert should insert record with default values when empty array given" do
|
712
700
|
@d.insert []
|
713
|
-
|
714
|
-
|
715
|
-
"INSERT INTO items () VALUES ()"
|
716
|
-
]
|
717
|
-
|
718
|
-
@d.all.should == [
|
719
|
-
{:name => nil, :value => nil}
|
720
|
-
]
|
701
|
+
MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
|
702
|
+
@d.all.should == [{:name => nil, :value => nil}]
|
721
703
|
end
|
722
704
|
|
723
705
|
specify "#on_duplicate_key_update should work with regular inserts" do
|
@@ -728,9 +710,9 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
728
710
|
@d.on_duplicate_key_update(:name, :value => 6).insert(:name => 'def', :value => 2)
|
729
711
|
|
730
712
|
MYSQL_DB.sqls.length.should == 3
|
731
|
-
MYSQL_DB.sqls[0].should =~ /\AINSERT INTO items \((name|value)
|
732
|
-
MYSQL_DB.sqls[1].should =~ /\AINSERT INTO items \((name|value)
|
733
|
-
MYSQL_DB.sqls[2].should =~ /\AINSERT INTO items \((name|value)
|
713
|
+
MYSQL_DB.sqls[0].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('abc'|1), (1|'abc')\)\z/
|
714
|
+
MYSQL_DB.sqls[1].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('abc'|1), (1|'abc')\) ON DUPLICATE KEY UPDATE `name`=VALUES\(`name`\), `value`=6\z/
|
715
|
+
MYSQL_DB.sqls[2].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('def'|2), (2|'def')\) ON DUPLICATE KEY UPDATE `name`=VALUES\(`name`\), `value`=6\z/
|
734
716
|
|
735
717
|
@d.all.should == [{:name => 'abc', :value => 6}, {:name => 'def', :value => 2}]
|
736
718
|
end
|
@@ -740,7 +722,7 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
740
722
|
|
741
723
|
MYSQL_DB.sqls.should == [
|
742
724
|
SQL_BEGIN,
|
743
|
-
"INSERT INTO items (name) VALUES ('abc'), ('def')",
|
725
|
+
"INSERT INTO `items` (`name`) VALUES ('abc'), ('def')",
|
744
726
|
SQL_COMMIT
|
745
727
|
]
|
746
728
|
|
@@ -755,10 +737,10 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
755
737
|
|
756
738
|
MYSQL_DB.sqls.should == [
|
757
739
|
SQL_BEGIN,
|
758
|
-
"INSERT INTO items (value) VALUES (1), (2)",
|
740
|
+
"INSERT INTO `items` (`value`) VALUES (1), (2)",
|
759
741
|
SQL_COMMIT,
|
760
742
|
SQL_BEGIN,
|
761
|
-
"INSERT INTO items (value) VALUES (3), (4)",
|
743
|
+
"INSERT INTO `items` (`value`) VALUES (3), (4)",
|
762
744
|
SQL_COMMIT
|
763
745
|
]
|
764
746
|
|
@@ -776,10 +758,10 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
776
758
|
|
777
759
|
MYSQL_DB.sqls.should == [
|
778
760
|
SQL_BEGIN,
|
779
|
-
"INSERT INTO items (value) VALUES (1), (2)",
|
761
|
+
"INSERT INTO `items` (`value`) VALUES (1), (2)",
|
780
762
|
SQL_COMMIT,
|
781
763
|
SQL_BEGIN,
|
782
|
-
"INSERT INTO items (value) VALUES (3), (4)",
|
764
|
+
"INSERT INTO `items` (`value`) VALUES (3), (4)",
|
783
765
|
SQL_COMMIT
|
784
766
|
]
|
785
767
|
|
@@ -796,7 +778,7 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
796
778
|
|
797
779
|
MYSQL_DB.sqls.should == [
|
798
780
|
SQL_BEGIN,
|
799
|
-
"INSERT INTO items (name
|
781
|
+
"INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2)",
|
800
782
|
SQL_COMMIT
|
801
783
|
]
|
802
784
|
|
@@ -811,7 +793,7 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
811
793
|
|
812
794
|
MYSQL_DB.sqls.should == [
|
813
795
|
SQL_BEGIN,
|
814
|
-
"INSERT IGNORE INTO items (name) VALUES ('abc'), ('def')",
|
796
|
+
"INSERT IGNORE INTO `items` (`name`) VALUES ('abc'), ('def')",
|
815
797
|
SQL_COMMIT
|
816
798
|
]
|
817
799
|
|
@@ -822,7 +804,7 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
822
804
|
|
823
805
|
specify "#insert_ignore should add the IGNORE keyword for single inserts" do
|
824
806
|
@d.insert_ignore.insert(:name => 'ghi')
|
825
|
-
MYSQL_DB.sqls.should == ["INSERT IGNORE INTO items (name) VALUES ('ghi')"]
|
807
|
+
MYSQL_DB.sqls.should == ["INSERT IGNORE INTO `items` (`name`) VALUES ('ghi')"]
|
826
808
|
@d.all.should == [{:name => 'ghi', :value => nil}]
|
827
809
|
end
|
828
810
|
|
@@ -830,9 +812,9 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
830
812
|
@d.on_duplicate_key_update.import([:name,:value], [['abc', 1], ['def',2]])
|
831
813
|
|
832
814
|
MYSQL_DB.sqls.should == [
|
833
|
-
"SELECT * FROM items LIMIT 1",
|
815
|
+
"SELECT * FROM `items` LIMIT 1",
|
834
816
|
SQL_BEGIN,
|
835
|
-
"INSERT INTO items (name
|
817
|
+
"INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`), `value`=VALUES(`value`)",
|
836
818
|
SQL_COMMIT
|
837
819
|
]
|
838
820
|
|
@@ -848,7 +830,7 @@ describe "MySQL::Dataset#insert and related methods" do
|
|
848
830
|
|
849
831
|
MYSQL_DB.sqls.should == [
|
850
832
|
SQL_BEGIN,
|
851
|
-
"INSERT INTO items (name
|
833
|
+
"INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)",
|
852
834
|
SQL_COMMIT
|
853
835
|
]
|
854
836
|
|
@@ -907,25 +889,25 @@ describe "MySQL::Dataset#complex_expression_sql" do
|
|
907
889
|
end
|
908
890
|
|
909
891
|
specify "should handle pattern matches correctly" do
|
910
|
-
@d.literal(:x.like('a')).should == "(x LIKE BINARY 'a')"
|
911
|
-
@d.literal(~:x.like('a')).should == "(x NOT LIKE BINARY 'a')"
|
912
|
-
@d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
|
913
|
-
@d.literal(~:x.ilike('a')).should == "(x NOT LIKE 'a')"
|
914
|
-
@d.literal(:x.like(/a/)).should == "(x REGEXP BINARY 'a')"
|
915
|
-
@d.literal(~:x.like(/a/)).should == "(x NOT REGEXP BINARY 'a')"
|
916
|
-
@d.literal(:x.like(/a/i)).should == "(x REGEXP 'a')"
|
917
|
-
@d.literal(~:x.like(/a/i)).should == "(x NOT REGEXP 'a')"
|
892
|
+
@d.literal(:x.like('a')).should == "(`x` LIKE BINARY 'a')"
|
893
|
+
@d.literal(~:x.like('a')).should == "(`x` NOT LIKE BINARY 'a')"
|
894
|
+
@d.literal(:x.ilike('a')).should == "(`x` LIKE 'a')"
|
895
|
+
@d.literal(~:x.ilike('a')).should == "(`x` NOT LIKE 'a')"
|
896
|
+
@d.literal(:x.like(/a/)).should == "(`x` REGEXP BINARY 'a')"
|
897
|
+
@d.literal(~:x.like(/a/)).should == "(`x` NOT REGEXP BINARY 'a')"
|
898
|
+
@d.literal(:x.like(/a/i)).should == "(`x` REGEXP 'a')"
|
899
|
+
@d.literal(~:x.like(/a/i)).should == "(`x` NOT REGEXP 'a')"
|
918
900
|
end
|
919
901
|
|
920
902
|
specify "should handle string concatenation with CONCAT if more than one record" do
|
921
|
-
@d.literal([:x, :y].sql_string_join).should == "CONCAT(x
|
922
|
-
@d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(x
|
923
|
-
@d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y.sql_subscript(1))).should == "CONCAT(x(y), y[1], '1', y[1], z)"
|
903
|
+
@d.literal([:x, :y].sql_string_join).should == "CONCAT(`x`, `y`)"
|
904
|
+
@d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(`x`, ' ', `y`)"
|
905
|
+
@d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y.sql_subscript(1))).should == "CONCAT(x(`y`), `y`[1], '1', `y`[1], z)"
|
924
906
|
end
|
925
907
|
|
926
908
|
specify "should handle string concatenation as simple string if just one record" do
|
927
|
-
@d.literal([:x].sql_string_join).should == "x"
|
928
|
-
@d.literal([:x].sql_string_join(' ')).should == "x"
|
909
|
+
@d.literal([:x].sql_string_join).should == "`x`"
|
910
|
+
@d.literal([:x].sql_string_join(' ')).should == "`x`"
|
929
911
|
end
|
930
912
|
end
|
931
913
|
|
@@ -939,7 +921,7 @@ describe "MySQL::Dataset#calc_found_rows" do
|
|
939
921
|
|
940
922
|
specify "should add the SQL_CALC_FOUND_ROWS keyword when selecting" do
|
941
923
|
MYSQL_DB[:items].select(:a).calc_found_rows.limit(1).sql.should == \
|
942
|
-
'SELECT SQL_CALC_FOUND_ROWS a FROM items LIMIT 1'
|
924
|
+
'SELECT SQL_CALC_FOUND_ROWS `a` FROM `items` LIMIT 1'
|
943
925
|
end
|
944
926
|
|
945
927
|
specify "should count matching rows disregarding LIMIT clause" do
|
@@ -950,8 +932,8 @@ describe "MySQL::Dataset#calc_found_rows" do
|
|
950
932
|
MYSQL_DB.dataset.select(:FOUND_ROWS.sql_function.as(:rows)).all.should == [{:rows => 2 }]
|
951
933
|
|
952
934
|
MYSQL_DB.sqls.should == [
|
953
|
-
'SELECT SQL_CALC_FOUND_ROWS * FROM items WHERE (a = 1) LIMIT 1',
|
954
|
-
'SELECT FOUND_ROWS() AS rows',
|
935
|
+
'SELECT SQL_CALC_FOUND_ROWS * FROM `items` WHERE (`a` = 1) LIMIT 1',
|
936
|
+
'SELECT FOUND_ROWS() AS `rows`',
|
955
937
|
]
|
956
938
|
end
|
957
939
|
end
|
@@ -1015,29 +997,29 @@ end
|
|
1015
997
|
if MYSQL_DB.adapter_scheme == :mysql
|
1016
998
|
describe "MySQL bad date/time conversions" do
|
1017
999
|
after do
|
1018
|
-
|
1000
|
+
MYSQL_DB.convert_invalid_date_time = false
|
1019
1001
|
end
|
1020
1002
|
|
1021
1003
|
specify "should raise an exception when a bad date/time is used and convert_invalid_date_time is false" do
|
1022
|
-
|
1004
|
+
MYSQL_DB.convert_invalid_date_time = false
|
1023
1005
|
proc{MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value}.should raise_error(Sequel::InvalidValue)
|
1024
1006
|
proc{MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value}.should raise_error(Sequel::InvalidValue)
|
1025
1007
|
proc{MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value}.should raise_error(Sequel::InvalidValue)
|
1026
1008
|
end
|
1027
1009
|
|
1028
1010
|
specify "should not use a nil value bad date/time is used and convert_invalid_date_time is nil or :nil" do
|
1029
|
-
|
1011
|
+
MYSQL_DB.convert_invalid_date_time = nil
|
1030
1012
|
MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
|
1031
1013
|
MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
|
1032
1014
|
MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
|
1033
|
-
|
1015
|
+
MYSQL_DB.convert_invalid_date_time = :nil
|
1034
1016
|
MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
|
1035
1017
|
MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
|
1036
1018
|
MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
|
1037
1019
|
end
|
1038
1020
|
|
1039
1021
|
specify "should not use a nil value bad date/time is used and convert_invalid_date_time is :string" do
|
1040
|
-
|
1022
|
+
MYSQL_DB.convert_invalid_date_time = :string
|
1041
1023
|
MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == '0000-00-00'
|
1042
1024
|
MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == '0000-00-00 00:00:00'
|
1043
1025
|
MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == '25:00:00'
|