sequel 5.3.0 → 5.4.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 +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
|
|