sequel 5.3.0 → 5.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG +30 -0
- data/bin/sequel +13 -0
- data/doc/cheat_sheet.rdoc +1 -0
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/querying.rdoc +8 -11
- data/doc/release_notes/5.4.0.txt +80 -0
- data/doc/testing.rdoc +2 -0
- data/lib/sequel/adapters/shared/db2.rb +6 -5
- data/lib/sequel/adapters/shared/mssql.rb +5 -8
- data/lib/sequel/adapters/shared/mysql.rb +4 -8
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +5 -3
- data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -6
- data/lib/sequel/adapters/shared/sqlite.rb +2 -0
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +10 -1
- data/lib/sequel/dataset/query.rb +1 -2
- data/lib/sequel/extensions/date_arithmetic.rb +27 -10
- data/lib/sequel/extensions/datetime_parse_to_time.rb +37 -0
- data/lib/sequel/extensions/index_caching.rb +107 -0
- data/lib/sequel/extensions/null_dataset.rb +3 -1
- data/lib/sequel/extensions/pg_timestamptz.rb +26 -0
- data/lib/sequel/model/base.rb +2 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -3
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +1 -1
- data/spec/adapters/spec_helper.rb +3 -0
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/bin_spec.rb +9 -0
- data/spec/core/connection_pool_spec.rb +2 -2
- data/spec/core/dataset_spec.rb +1 -6
- data/spec/extensions/class_table_inheritance_spec.rb +52 -2
- data/spec/extensions/date_arithmetic_spec.rb +15 -1
- data/spec/extensions/datetime_parse_to_time_spec.rb +169 -0
- data/spec/extensions/index_caching_spec.rb +66 -0
- data/spec/extensions/json_serializer_spec.rb +5 -0
- data/spec/extensions/null_dataset_spec.rb +5 -0
- data/spec/extensions/pg_extended_date_support_spec.rb +4 -0
- data/spec/extensions/pg_timestamptz_spec.rb +17 -0
- data/spec/extensions/xml_serializer_spec.rb +7 -0
- data/spec/integration/dataset_test.rb +6 -0
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +19 -17
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/record_spec.rb +28 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 31c759888ccdeebe39b3d3bd9e953c74d8584bade28bdc1bc2d6e38545c8896d
|
4
|
+
data.tar.gz: dbf22a0e145192f4a50ea421a4e93a8b182472c5430d06061d710f218bd61d24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 764c3d3d8856d8be93d5ee7492e331b1a56caeef4a2ad2d8a53a6c781e34650007f44a1ea0d3cb97b03ebf633842da3c67846edcfe0a0a9c7f788e15123403a9
|
7
|
+
data.tar.gz: f0f32cc6e140e46a7cf91f78ace601a0c5bf7c77b87f2fcbfd236fca04090e2bc97e89f579206bb10b9bce84a340215aafe029c9923aec816f33f60aa54da80d
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,33 @@
|
|
1
|
+
=== 5.4.0 (2018-01-04)
|
2
|
+
|
3
|
+
* Enable fractional seconds in timestamps on DB2 (jeremyevans) (#1463)
|
4
|
+
|
5
|
+
* Don't attempt to insert a second time if insert_select runs a query that doesn't return results, which can happen when triggers are used (jeremyevans)
|
6
|
+
|
7
|
+
* Make Dataset#insert_select on PostgreSQL and MSSQL return false instead of nil if the INSERT query is sent to the database but returns no rows (jeremyevans)
|
8
|
+
|
9
|
+
* Add index_caching extension for caching calls to Database#indexes (kenaniah, jeremyevans) (#1461)
|
10
|
+
|
11
|
+
* Allow Database#indexes on SQLite, MSSQL, SQLAnywhere, and DB2 to handle SQL::Identifier values (jeremyevans)
|
12
|
+
|
13
|
+
* Add pg_timestamptz extension for using timestamptz (timestamp with time zone) as the default timestamp type (jeremyevans)
|
14
|
+
|
15
|
+
* Support Sequel.date_{add,sub} :cast option for setting cast type in date_arithmetic extension (jeremyevans)
|
16
|
+
|
17
|
+
* Optimize Database#synchronize implementation on ruby 2.5+ (jeremyevans)
|
18
|
+
|
19
|
+
* Add class_table_inheritance plugin :ignore_subclass_columns option (brianphillips) (#1459)
|
20
|
+
|
21
|
+
* Make Dataset#to_xml in xml_serializer work with eager_graphed datasets (jeremyevans)
|
22
|
+
|
23
|
+
* Make Dataset#to_json in json_serializer work with eager_graphed datasets (jeremyevans)
|
24
|
+
|
25
|
+
* Cache Dataset#nullify dataset in the null_dataset extension (chanks) (#1456)
|
26
|
+
|
27
|
+
* Add datetime_parse_to_time extension, for parsing timestamp strings without offsets using DateTime.parse.to_time (jeremyevans) (#1455)
|
28
|
+
|
29
|
+
* Add WHERE NULL filter for Dataset#where calls with no existing filter, no argument, and where the virtual row block returns nil (jeremyevans)
|
30
|
+
|
1
31
|
=== 5.3.0 (2017-12-01)
|
2
32
|
|
3
33
|
* Add logger to Database instance before making first connection in bin/sequel (jeremyevans)
|
data/bin/sequel
CHANGED
@@ -7,6 +7,7 @@ code = nil
|
|
7
7
|
copy_databases = nil
|
8
8
|
dump_migration = nil
|
9
9
|
dump_schema = nil
|
10
|
+
dump_indexes = nil
|
10
11
|
env = nil
|
11
12
|
migrate_dir = nil
|
12
13
|
migrate_ver = nil
|
@@ -106,6 +107,11 @@ options = OptionParser.new do |opts|
|
|
106
107
|
opts.on_tail("-v", "--version", "Show version") do
|
107
108
|
show_version = true
|
108
109
|
end
|
110
|
+
|
111
|
+
opts.on("-X", "--dump-indexes filename", "dump the index cache for all tables to the file") do |v|
|
112
|
+
dump_indexes = v
|
113
|
+
exclusive_options << :X
|
114
|
+
end
|
109
115
|
end
|
110
116
|
opts = options
|
111
117
|
opts.parse!
|
@@ -170,6 +176,13 @@ begin
|
|
170
176
|
DB.dump_schema_cache(dump_schema)
|
171
177
|
exit
|
172
178
|
end
|
179
|
+
if dump_indexes
|
180
|
+
extra_proc.call
|
181
|
+
DB.extension :index_caching
|
182
|
+
DB.tables.each{|t| DB.indexes(Sequel::SQL::Identifier.new(t))}
|
183
|
+
DB.dump_index_cache(dump_indexes)
|
184
|
+
exit
|
185
|
+
end
|
173
186
|
if copy_databases
|
174
187
|
Sequel.extension :migration
|
175
188
|
DB.extension :schema_dumper
|
data/doc/cheat_sheet.rdoc
CHANGED
data/doc/dataset_filtering.rdoc
CHANGED
@@ -84,7 +84,7 @@ You can also use the =~ operator:
|
|
84
84
|
This works with other hash values, such as arrays and ranges:
|
85
85
|
|
86
86
|
items.where{Sequel.|({category: ['ruby', 'other']}, (price - 100 > 200))}.sql
|
87
|
-
# "SELECT * FROM items WHERE ((category IN ('ruby', 'other')) OR ((price - 100)
|
87
|
+
# "SELECT * FROM items WHERE ((category IN ('ruby', 'other')) OR ((price - 100) > 200))"
|
88
88
|
|
89
89
|
items.where{(price =~ (100..200)) & :active}.sql
|
90
90
|
# "SELECT * FROM items WHERE ((price >= 100 AND price <= 200) AND active)"
|
data/doc/querying.rdoc
CHANGED
@@ -49,7 +49,7 @@ to raise an exception if no record is found, you can use <tt>Sequel::Model.with_
|
|
49
49
|
|
50
50
|
==== Using +first+
|
51
51
|
|
52
|
-
If you
|
52
|
+
If you want the first record in the dataset,
|
53
53
|
<tt>Sequel::Dataset#first</tt> is probably the most obvious method to use:
|
54
54
|
|
55
55
|
artist = Artist.first
|
@@ -82,22 +82,19 @@ Dataset#[] does not (unless it is a model dataset).
|
|
82
82
|
==== Using +last+
|
83
83
|
|
84
84
|
If you want the last record in the dataset,
|
85
|
-
<tt>Sequel::Dataset#last</tt> is an obvious method to use.
|
86
|
-
|
87
|
-
|
88
|
-
reverse order by the primary key field:
|
85
|
+
<tt>Sequel::Dataset#last</tt> is an obvious method to use. +last+ requires the
|
86
|
+
dataset be ordered, unless the dataset is a model dataset in which case +last+
|
87
|
+
will do a reverse order by the primary key field:
|
89
88
|
|
90
89
|
artist = Artist.last
|
91
90
|
# SELECT * FROM artists ORDER BY id DESC LIMIT 1
|
92
91
|
# => #<Artist @values={:name=>"YJM", :id=>1}>
|
93
92
|
|
94
|
-
Note
|
95
|
-
call +first+. This is why +last+ raises a Sequel::Error if there is no
|
96
|
-
order on a plain dataset, because otherwise it would provide the same record
|
97
|
-
as +first+, and most users would find that confusing.
|
93
|
+
Note:
|
98
94
|
|
99
|
-
|
100
|
-
in the dataset unless you give the dataset an unambiguous order.
|
95
|
+
1. +last+ is equivalent to running a +reverse.first+ query, in other words it reverses the order of the dataset and then calls +first+. This is why +last+ raises a Sequel::Error when there is no order on a plain dataset - because it will provide the same record as +first+, and most users will find that confusing.
|
96
|
+
2. +last+ is not necessarily going to give you the last record in the dataset unless you give the dataset an unambiguous order.
|
97
|
+
3. +last+ will ignore +limit+ if chained together in a query because it sets a limit of 1 if no arguments are given.
|
101
98
|
|
102
99
|
==== Retrieving a Single Column Value
|
103
100
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* An index_caching extension has been added, which makes
|
4
|
+
Database#indexes use a cache similar to Database#schema, and also
|
5
|
+
offers methods for saving and loading the cache from a file, similar
|
6
|
+
to the schema_caching extension.
|
7
|
+
|
8
|
+
This can speed up model loaded in certain cases when the
|
9
|
+
auto_validations plugin is used.
|
10
|
+
|
11
|
+
* A datetime_parse_to_time extension has been added, which parses
|
12
|
+
strings without timezone offsets using DateTime.parse intead of
|
13
|
+
Time.parse. This can fix problems when the string being parsed
|
14
|
+
represents a time not valid in the local timezone due to daylight
|
15
|
+
savings time shifts. Time.parse silently shifts such times by 1
|
16
|
+
hour instead of raising an exception, resulting in incorrect
|
17
|
+
behavior in that case.
|
18
|
+
|
19
|
+
It only makes sense to use this extension when the times in the
|
20
|
+
database are stored in UTC but not returned with timezone
|
21
|
+
information, the timezone for the Database instance
|
22
|
+
(or Sequel.database_timezone) is set to :utc (not the default),
|
23
|
+
and Time is used as the datetime_class (the default).
|
24
|
+
|
25
|
+
* A pg_timestamptz extension has been added for switching the default
|
26
|
+
generic timestamp type from timestamp to timestamptz.
|
27
|
+
|
28
|
+
* Sequel.date_{add,sub} in the date_arithmetic extension now supports
|
29
|
+
a :cast option for setting the cast type. This value defaults to
|
30
|
+
Time for backwards compatibility, which uses the default generic
|
31
|
+
timestamp type for the database.
|
32
|
+
|
33
|
+
* The class_table_inheritance plugin now supports an
|
34
|
+
:ignore_subclass_columns option which takes an array of column
|
35
|
+
symbols to ignore in subclasses. This allows you to use
|
36
|
+
the plugin when your table inheritance hierarchy includes
|
37
|
+
non-primary key columns with the same name in different tables.
|
38
|
+
|
39
|
+
= Improvements
|
40
|
+
|
41
|
+
* Dataset#insert_select now returns false instead of nil if it runs
|
42
|
+
an INSERT statement but does not return a value on Microsoft SQL
|
43
|
+
Server or PostgreSQL. This can happen on both databases if triggers
|
44
|
+
are used.
|
45
|
+
|
46
|
+
Model#save now checks for a false value returned by
|
47
|
+
Dataset#insert_select, and does not issue another INSERT statement
|
48
|
+
in that case.
|
49
|
+
|
50
|
+
* Database#indexes now correctly handles SQL::Identifier arguments on
|
51
|
+
SQLite, Microsoft SQL Server, SQLAnywhere, and DB2.
|
52
|
+
|
53
|
+
* Dataset#to_json in the json_serializer plugin and Dataset#to_xml
|
54
|
+
in the xml_serializer plugin now both handle datasets that use
|
55
|
+
eager_graph.
|
56
|
+
|
57
|
+
* Dataset#nullify now caches the dataset it returns, for better
|
58
|
+
performance if it is called more than once on the same dataset.
|
59
|
+
|
60
|
+
* Database#synchronize is now optimized on ruby 2.5+ and is about
|
61
|
+
10% faster by relying on the new lazy proc allocation feature.
|
62
|
+
|
63
|
+
= Backwards Compatibility
|
64
|
+
|
65
|
+
* Fractional second timestamps are now enabled on DB2. If you are
|
66
|
+
connecting to a DB2 database that does not support fractional
|
67
|
+
seconds, you should add the following code (where DB is your
|
68
|
+
Sequel::Database instance):
|
69
|
+
|
70
|
+
DB.extend_datasets do
|
71
|
+
def supports_timestamp_usecs?
|
72
|
+
false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
* Calling a filtering method with no argument and a virtual row
|
77
|
+
block that returns nil on a dataset with no existing filter now
|
78
|
+
adds a WHERE NULL filter, to match the behavior if given a nil
|
79
|
+
argument. Previously, a deprecation warning was issued and a
|
80
|
+
dataset with no filter was returned.
|
data/doc/testing.rdoc
CHANGED
@@ -156,6 +156,7 @@ SEQUEL_COLUMNS_INTROSPECTION :: Use the columns_introspection extension when run
|
|
156
156
|
SEQUEL_CONNECTION_VALIDATOR :: Use the connection validator extension when running the specs
|
157
157
|
SEQUEL_DUPLICATE_COLUMNS_HANDLER :: Use the duplicate columns handler extension with value given when running the specs
|
158
158
|
SEQUEL_ERROR_SQL :: Use the error_sql extension when running the specs
|
159
|
+
SEQUEL_INDEX_CACHING :: Use the index_caching extension when running the specs
|
159
160
|
SEQUEL_FREEZE_DATABASE :: Freeze the database before running the integration specs
|
160
161
|
SEQUEL_IDENTIFIER_MANGLING :: Use the identifier_mangling extension when running the specs
|
161
162
|
SEQUEL_MODEL_PREPARED_STATEMENTS :: Use the prepared_statements plugin when running the specs
|
@@ -163,5 +164,6 @@ SEQUEL_NO_CACHE_ASSOCIATIONS :: Don't cache association metadata when running th
|
|
163
164
|
SEQUEL_NO_CHECK_SQLS :: Don't check for specific SQL syntax when running the specs
|
164
165
|
SEQUEL_CHECK_PENDING :: Try running all specs (note, can cause lockups for some adapters), and raise errors for skipped specs that don't fail
|
165
166
|
SEQUEL_NO_PENDING :: Don't skip any specs, try running all specs (note, can cause lockups for some adapters)
|
167
|
+
SEQUEL_PG_TIMESTAMPTZ :: Use the pg_timestamptz extension when running the postgres specs
|
166
168
|
SEQUEL_SPLIT_SYMBOLS :: Turn on symbol splitting when running the adapter and integration specs
|
167
169
|
SEQUEL_SYNCHRONIZE_SQL :: Use the synchronize_sql extension when running the specs
|
@@ -69,6 +69,7 @@ module Sequel
|
|
69
69
|
# Use SYSCAT.INDEXES to get the indexes for the table
|
70
70
|
def indexes(table, opts = OPTS)
|
71
71
|
m = output_identifier_meth
|
72
|
+
table = table.value if table.is_a?(Sequel::SQL::Identifier)
|
72
73
|
indexes = {}
|
73
74
|
metadata_dataset.
|
74
75
|
from(Sequel[:syscat][:indexes]).
|
@@ -345,11 +346,6 @@ module Sequel
|
|
345
346
|
false
|
346
347
|
end
|
347
348
|
|
348
|
-
# DB2 does not support fractional seconds in timestamps.
|
349
|
-
def supports_timestamp_usecs?
|
350
|
-
false
|
351
|
-
end
|
352
|
-
|
353
349
|
# DB2 supports window functions
|
354
350
|
def supports_window_functions?
|
355
351
|
true
|
@@ -384,6 +380,11 @@ module Sequel
|
|
384
380
|
'0'
|
385
381
|
end
|
386
382
|
|
383
|
+
# DB2 doesn't support fractional seconds in times, only fractional seconds in timestamps.
|
384
|
+
def literal_sqltime(v)
|
385
|
+
v.strftime("'%H:%M:%S'")
|
386
|
+
end
|
387
|
+
|
387
388
|
# Use 1 for true on DB2
|
388
389
|
def literal_true
|
389
390
|
'1'
|
@@ -165,6 +165,7 @@ module Sequel
|
|
165
165
|
m = output_identifier_meth
|
166
166
|
im = input_identifier_meth
|
167
167
|
indexes = {}
|
168
|
+
table = table.value if table.is_a?(Sequel::SQL::Identifier)
|
168
169
|
i = Sequel[:i]
|
169
170
|
ds = metadata_dataset.from(Sequel.lit('[sys].[tables]').as(:t)).
|
170
171
|
join(Sequel.lit('[sys].[indexes]').as(:i), :object_id=>:object_id).
|
@@ -473,12 +474,6 @@ module Sequel
|
|
473
474
|
:datetime
|
474
475
|
end
|
475
476
|
|
476
|
-
# MSSQL has both datetime and timestamp classes, most people are going
|
477
|
-
# to want datetime
|
478
|
-
def type_literal_generic_time(column)
|
479
|
-
column[:only_time] ? :time : :datetime
|
480
|
-
end
|
481
|
-
|
482
477
|
# MSSQL doesn't have a true boolean class, so it uses bit
|
483
478
|
def type_literal_generic_trueclass(column)
|
484
479
|
:bit
|
@@ -580,10 +575,12 @@ module Sequel
|
|
580
575
|
where(Sequel.lit("CONTAINS (?, ?)", cols, terms))
|
581
576
|
end
|
582
577
|
|
583
|
-
#
|
578
|
+
# Insert a record, returning the record inserted, using OUTPUT. Always returns nil without
|
579
|
+
# running an INSERT statement if disable_insert_output is used. If the query runs
|
580
|
+
# but returns no values, returns false.
|
584
581
|
def insert_select(*values)
|
585
582
|
return unless supports_insert_select?
|
586
|
-
with_sql_first(insert_select_sql(*values))
|
583
|
+
with_sql_first(insert_select_sql(*values)) || false
|
587
584
|
end
|
588
585
|
|
589
586
|
# Add OUTPUT clause unless there is already an existing output clause, then return
|
@@ -537,15 +537,11 @@ module Sequel
|
|
537
537
|
|
538
538
|
# MySQL has both datetime and timestamp classes, most people are going
|
539
539
|
# to want datetime.
|
540
|
-
def
|
541
|
-
if
|
542
|
-
|
543
|
-
:'time(6)'
|
544
|
-
else
|
545
|
-
:time
|
546
|
-
end
|
540
|
+
def type_literal_generic_only_time(column)
|
541
|
+
if supports_timestamp_usecs?
|
542
|
+
:'time(6)'
|
547
543
|
else
|
548
|
-
|
544
|
+
:time
|
549
545
|
end
|
550
546
|
end
|
551
547
|
|
@@ -1393,11 +1393,13 @@ module Sequel
|
|
1393
1393
|
insert_conflict
|
1394
1394
|
end
|
1395
1395
|
|
1396
|
-
# Insert a record returning the record inserted. Always returns nil without
|
1397
|
-
#
|
1396
|
+
# Insert a record, returning the record inserted, using RETURNING. Always returns nil without
|
1397
|
+
# running an INSERT statement if disable_insert_returning is used. If the query runs
|
1398
|
+
# but returns no values, returns false.
|
1398
1399
|
def insert_select(*values)
|
1399
1400
|
return unless supports_insert_select?
|
1400
|
-
|
1401
|
+
# Handle case where query does not return a row
|
1402
|
+
server?(:default).with_sql_first(insert_select_sql(*values)) || false
|
1401
1403
|
end
|
1402
1404
|
|
1403
1405
|
# The SQL to use for an insert_select, adds a RETURNING clause to the insert
|
@@ -58,6 +58,7 @@ module Sequel
|
|
58
58
|
def indexes(table, opts = OPTS)
|
59
59
|
m = output_identifier_meth
|
60
60
|
im = input_identifier_meth
|
61
|
+
table = table.value if table.is_a?(Sequel::SQL::Identifier)
|
61
62
|
indexes = {}
|
62
63
|
metadata_dataset.
|
63
64
|
from(Sequel[:dbo][:sysobjects].as(:z)).
|
@@ -158,12 +159,6 @@ module Sequel
|
|
158
159
|
:datetime
|
159
160
|
end
|
160
161
|
|
161
|
-
# Sybase has both datetime and timestamp classes, most people are going
|
162
|
-
# to want datetime
|
163
|
-
def type_literal_generic_time(column)
|
164
|
-
column[:only_time] ? :time : :datetime
|
165
|
-
end
|
166
|
-
|
167
162
|
# Sybase doesn't have a true boolean class, so it uses integer
|
168
163
|
def type_literal_generic_trueclass(column)
|
169
164
|
:smallint
|
@@ -82,6 +82,7 @@ module Sequel
|
|
82
82
|
m = output_identifier_meth
|
83
83
|
im = input_identifier_meth
|
84
84
|
indexes = {}
|
85
|
+
table = table.value if table.is_a?(Sequel::SQL::Identifier)
|
85
86
|
metadata_dataset.with_sql("PRAGMA index_list(?)", im.call(table)).each do |r|
|
86
87
|
if opts[:only_autocreated]
|
87
88
|
# If specifically asked for only autocreated indexes, then return those an only those
|
@@ -188,6 +189,7 @@ module Sequel
|
|
188
189
|
ops.each{|op| alter_table_sql_list(table, [op]).flatten.each{|sql| execute_ddl(sql)}}
|
189
190
|
end
|
190
191
|
end
|
192
|
+
remove_cached_schema(table)
|
191
193
|
ensure
|
192
194
|
run "PRAGMA foreign_keys = 1" if fks
|
193
195
|
end
|
@@ -247,7 +247,7 @@ module Sequel
|
|
247
247
|
@single_threaded
|
248
248
|
end
|
249
249
|
|
250
|
-
if
|
250
|
+
if RUBY_ENGINE == 'ruby' && RUBY_VERSION < '2.5'
|
251
251
|
# Acquires a database connection, yielding it to the passed block. This is
|
252
252
|
# useful if you want to make sure the same connection is used for all
|
253
253
|
# database queries in the block. It is also useful if you want to gain
|
@@ -1010,7 +1010,16 @@ module Sequel
|
|
1010
1010
|
# Sequel uses the timestamp type by default for Time values.
|
1011
1011
|
# If the :only_time option is used, the time type is used.
|
1012
1012
|
def type_literal_generic_time(column)
|
1013
|
-
column[:only_time]
|
1013
|
+
if column[:only_time]
|
1014
|
+
type_literal_generic_only_time(column)
|
1015
|
+
else
|
1016
|
+
type_literal_generic_datetime(column)
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
# Use time by default for Time values if :only_time option is used.
|
1021
|
+
def type_literal_generic_only_time(column)
|
1022
|
+
:time
|
1014
1023
|
end
|
1015
1024
|
|
1016
1025
|
# Sequel uses the boolean type by default for TrueClass and FalseClass.
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -1211,8 +1211,7 @@ module Sequel
|
|
1211
1211
|
cond = SQL::BooleanExpression.new(combine, @opts[clause], cond) if @opts[clause]
|
1212
1212
|
|
1213
1213
|
if cond.nil?
|
1214
|
-
|
1215
|
-
#cond = Sequel::NULL
|
1214
|
+
cond = Sequel::NULL
|
1216
1215
|
end
|
1217
1216
|
|
1218
1217
|
clone(clause => cond)
|
@@ -21,6 +21,11 @@
|
|
21
21
|
# add = Sequel.date_add(:date_column, 1.years + 2.months + 3.days)
|
22
22
|
# sub = Sequel.date_sub(:date_column, 1.hours + 2.minutes + 3.seconds)
|
23
23
|
#
|
24
|
+
# By default, values are casted to the generic timestamp type for the
|
25
|
+
# database. You can override the cast type using the :cast option:
|
26
|
+
#
|
27
|
+
# add = Sequel.date_add(:date_column, {years: 1, months: 2, days: 3}, :cast=>:timestamptz)
|
28
|
+
#
|
24
29
|
# These expressions can be used in your datasets, or anywhere else that
|
25
30
|
# Sequel expressions are allowed:
|
26
31
|
#
|
@@ -33,13 +38,17 @@ module Sequel
|
|
33
38
|
module SQL
|
34
39
|
module Builders
|
35
40
|
# Return a DateAdd expression, adding an interval to the date/timestamp expr.
|
36
|
-
|
37
|
-
|
41
|
+
# Options:
|
42
|
+
# :cast :: Cast to the specified type instead of the default if casting
|
43
|
+
def date_add(expr, interval, opts=OPTS)
|
44
|
+
DateAdd.new(expr, interval, opts)
|
38
45
|
end
|
39
46
|
|
40
47
|
# Return a DateAdd expression, adding the negative of the interval to
|
41
48
|
# the date/timestamp expr.
|
42
|
-
|
49
|
+
# Options:
|
50
|
+
# :cast :: Cast to the specified type instead of the default if casting
|
51
|
+
def date_sub(expr, interval, opts=OPTS)
|
43
52
|
interval = if interval.is_a?(Hash)
|
44
53
|
h = {}
|
45
54
|
interval.each{|k,v| h[k] = -v unless v.nil?}
|
@@ -47,7 +56,7 @@ module Sequel
|
|
47
56
|
else
|
48
57
|
-interval
|
49
58
|
end
|
50
|
-
DateAdd.new(expr, interval)
|
59
|
+
DateAdd.new(expr, interval, opts)
|
51
60
|
end
|
52
61
|
end
|
53
62
|
|
@@ -72,8 +81,11 @@ module Sequel
|
|
72
81
|
if defined?(super)
|
73
82
|
return super
|
74
83
|
end
|
84
|
+
|
75
85
|
h = da.interval
|
76
86
|
expr = da.expr
|
87
|
+
cast_type = da.cast_type || Time
|
88
|
+
|
77
89
|
cast = case db_type = db.database_type
|
78
90
|
when :postgres
|
79
91
|
interval = String.new
|
@@ -81,9 +93,9 @@ module Sequel
|
|
81
93
|
interval << "#{value} #{sql_unit} "
|
82
94
|
end
|
83
95
|
if interval.empty?
|
84
|
-
return literal_append(sql, Sequel.cast(expr,
|
96
|
+
return literal_append(sql, Sequel.cast(expr, cast_type))
|
85
97
|
else
|
86
|
-
return complex_expression_sql_append(sql, :+, [Sequel.cast(expr,
|
98
|
+
return complex_expression_sql_append(sql, :+, [Sequel.cast(expr, cast_type), Sequel.cast(interval, :interval)])
|
87
99
|
end
|
88
100
|
when :sqlite
|
89
101
|
args = [expr]
|
@@ -94,7 +106,7 @@ module Sequel
|
|
94
106
|
when :mysql, :hsqldb
|
95
107
|
if db_type == :hsqldb
|
96
108
|
# HSQLDB requires 2.2.9+ for the DATE_ADD function
|
97
|
-
expr = Sequel.cast(expr,
|
109
|
+
expr = Sequel.cast(expr, cast_type)
|
98
110
|
end
|
99
111
|
each_valid_interval_unit(h, MYSQL_DURATION_UNITS) do |value, sql_unit|
|
100
112
|
expr = Sequel.function(:DATE_ADD, expr, Sequel.lit(["INTERVAL ", " "], value, sql_unit))
|
@@ -124,7 +136,7 @@ module Sequel
|
|
124
136
|
expr = Sequel.+(expr, Sequel.lit(["INTERVAL ", " "], value.to_s, sql_unit))
|
125
137
|
end
|
126
138
|
when :db2
|
127
|
-
expr = Sequel.cast(expr,
|
139
|
+
expr = Sequel.cast(expr, cast_type)
|
128
140
|
each_valid_interval_unit(h, DB2_DURATION_UNITS) do |value, sql_unit|
|
129
141
|
expr = Sequel.+(expr, Sequel.lit(["", " "], value, sql_unit))
|
130
142
|
end
|
@@ -134,7 +146,7 @@ module Sequel
|
|
134
146
|
end
|
135
147
|
|
136
148
|
if cast
|
137
|
-
expr = Sequel.cast(expr,
|
149
|
+
expr = Sequel.cast(expr, cast_type)
|
138
150
|
end
|
139
151
|
|
140
152
|
literal_append(sql, expr)
|
@@ -165,10 +177,14 @@ module Sequel
|
|
165
177
|
# symbol keys.
|
166
178
|
attr_reader :interval
|
167
179
|
|
180
|
+
# The type to cast the expression to. nil if not overridden, in which cast
|
181
|
+
# the generic timestamp type for the database will be used.
|
182
|
+
attr_reader :cast_type
|
183
|
+
|
168
184
|
# Supports two types of intervals:
|
169
185
|
# Hash :: Used directly, but values cannot be plain strings.
|
170
186
|
# ActiveSupport::Duration :: Converted to a hash using the interval's parts.
|
171
|
-
def initialize(expr, interval)
|
187
|
+
def initialize(expr, interval, opts=OPTS)
|
172
188
|
@expr = expr
|
173
189
|
@interval = if interval.is_a?(Hash)
|
174
190
|
interval.each_value do |v|
|
@@ -186,6 +202,7 @@ module Sequel
|
|
186
202
|
end
|
187
203
|
|
188
204
|
@interval.freeze
|
205
|
+
@cast_type = opts[:cast] if opts[:cast]
|
189
206
|
freeze
|
190
207
|
end
|
191
208
|
|