sequel 4.45.0 → 4.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +108 -0
- data/doc/release_notes/4.46.0.txt +404 -0
- data/doc/security.rdoc +9 -0
- data/doc/sql.rdoc +2 -2
- data/doc/testing.rdoc +1 -1
- data/doc/validations.rdoc +1 -2
- data/lib/sequel/adapters/ado.rb +8 -3
- data/lib/sequel/adapters/ado/access.rb +8 -4
- data/lib/sequel/adapters/ado/mssql.rb +3 -1
- data/lib/sequel/adapters/amalgalite.rb +5 -0
- data/lib/sequel/adapters/cubrid.rb +16 -7
- data/lib/sequel/adapters/do.rb +7 -1
- data/lib/sequel/adapters/do/mysql.rb +8 -4
- data/lib/sequel/adapters/ibmdb.rb +10 -5
- data/lib/sequel/adapters/jdbc.rb +8 -2
- data/lib/sequel/adapters/jdbc/as400.rb +10 -3
- data/lib/sequel/adapters/jdbc/db2.rb +27 -16
- data/lib/sequel/adapters/jdbc/derby.rb +47 -20
- data/lib/sequel/adapters/jdbc/h2.rb +13 -7
- data/lib/sequel/adapters/jdbc/hsqldb.rb +18 -9
- data/lib/sequel/adapters/jdbc/mssql.rb +5 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +3 -2
- data/lib/sequel/adapters/jdbc/oracle.rb +3 -2
- data/lib/sequel/adapters/jdbc/postgresql.rb +4 -3
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +2 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +10 -3
- data/lib/sequel/adapters/jdbc/sqlserver.rb +23 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +16 -10
- data/lib/sequel/adapters/mock.rb +5 -0
- data/lib/sequel/adapters/mysql.rb +8 -1
- data/lib/sequel/adapters/mysql2.rb +6 -1
- data/lib/sequel/adapters/odbc.rb +20 -8
- data/lib/sequel/adapters/odbc/mssql.rb +6 -3
- data/lib/sequel/adapters/oracle.rb +12 -6
- data/lib/sequel/adapters/postgres.rb +20 -8
- data/lib/sequel/adapters/shared/access.rb +76 -47
- data/lib/sequel/adapters/shared/cubrid.rb +16 -11
- data/lib/sequel/adapters/shared/db2.rb +46 -19
- data/lib/sequel/adapters/shared/firebird.rb +20 -8
- data/lib/sequel/adapters/shared/informix.rb +6 -3
- data/lib/sequel/adapters/shared/mssql.rb +132 -72
- data/lib/sequel/adapters/shared/mysql.rb +112 -65
- data/lib/sequel/adapters/shared/oracle.rb +36 -21
- data/lib/sequel/adapters/shared/postgres.rb +91 -56
- data/lib/sequel/adapters/shared/sqlanywhere.rb +65 -37
- data/lib/sequel/adapters/shared/sqlite.rb +67 -32
- data/lib/sequel/adapters/sqlanywhere.rb +9 -1
- data/lib/sequel/adapters/sqlite.rb +8 -1
- data/lib/sequel/adapters/swift.rb +5 -0
- data/lib/sequel/adapters/swift/mysql.rb +4 -2
- data/lib/sequel/adapters/swift/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +10 -3
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -0
- data/lib/sequel/adapters/utils/pg_types.rb +14 -6
- data/lib/sequel/adapters/utils/replace.rb +4 -2
- data/lib/sequel/connection_pool/single.rb +2 -2
- data/lib/sequel/core.rb +24 -11
- data/lib/sequel/database/connecting.rb +9 -3
- data/lib/sequel/database/dataset_defaults.rb +7 -1
- data/lib/sequel/database/logging.rb +1 -0
- data/lib/sequel/database/misc.rb +5 -2
- data/lib/sequel/database/query.rb +7 -5
- data/lib/sequel/database/schema_generator.rb +1 -0
- data/lib/sequel/database/schema_methods.rb +50 -27
- data/lib/sequel/database/transactions.rb +19 -9
- data/lib/sequel/dataset/actions.rb +15 -6
- data/lib/sequel/dataset/graph.rb +15 -5
- data/lib/sequel/dataset/misc.rb +12 -4
- data/lib/sequel/dataset/mutation.rb +17 -8
- data/lib/sequel/dataset/prepared_statements.rb +3 -2
- data/lib/sequel/dataset/query.rb +84 -38
- data/lib/sequel/dataset/sql.rb +302 -191
- data/lib/sequel/deprecated.rb +26 -17
- data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +2 -2
- data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
- data/lib/sequel/extensions/from_block.rb +1 -0
- data/lib/sequel/extensions/graph_each.rb +1 -1
- data/lib/sequel/extensions/identifier_mangling.rb +2 -2
- data/lib/sequel/extensions/migration.rb +28 -4
- data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +4 -4
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +5 -3
- data/lib/sequel/extensions/set_overrides.rb +2 -0
- data/lib/sequel/extensions/split_array_nil.rb +2 -2
- data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
- data/lib/sequel/model.rb +11 -7
- data/lib/sequel/model/associations.rb +5 -7
- data/lib/sequel/model/base.rb +47 -45
- data/lib/sequel/model/dataset_module.rb +9 -14
- data/lib/sequel/model/plugins.rb +3 -0
- data/lib/sequel/no_core_ext.rb +1 -0
- data/lib/sequel/plugins/blacklist_security.rb +1 -1
- data/lib/sequel/plugins/boolean_subsets.rb +7 -5
- data/lib/sequel/plugins/class_table_inheritance.rb +47 -10
- data/lib/sequel/plugins/dataset_associations.rb +1 -1
- data/lib/sequel/plugins/def_dataset_method.rb +90 -0
- data/lib/sequel/plugins/finder.rb +240 -0
- data/lib/sequel/plugins/inverted_subsets.rb +19 -12
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +1 -1
- data/lib/sequel/plugins/schema.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +7 -1
- data/lib/sequel/plugins/subset_conditions.rb +11 -3
- data/lib/sequel/plugins/whitelist_security.rb +118 -0
- data/lib/sequel/sql.rb +80 -36
- data/lib/sequel/timezones.rb +2 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +20 -0
- data/spec/adapters/mysql_spec.rb +1 -1
- data/spec/adapters/oracle_spec.rb +12 -8
- data/spec/adapters/postgres_spec.rb +1 -1
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +36 -34
- data/spec/core/connection_pool_spec.rb +2 -1
- data/spec/core/database_spec.rb +87 -9
- data/spec/core/dataset_spec.rb +501 -129
- data/spec/core/deprecated_spec.rb +1 -1
- data/spec/core/expression_filters_spec.rb +146 -60
- data/spec/core/mock_adapter_spec.rb +1 -1
- data/spec/core/object_graph_spec.rb +61 -9
- data/spec/core/placeholder_literalizer_spec.rb +20 -2
- data/spec/core/schema_generator_spec.rb +6 -6
- data/spec/core/schema_spec.rb +54 -5
- data/spec/core_extensions_spec.rb +122 -18
- data/spec/deprecation_helper.rb +27 -2
- data/spec/extensions/_deprecated_identifier_mangling_spec.rb +6 -6
- data/spec/extensions/association_proxies_spec.rb +2 -2
- data/spec/extensions/auto_literal_strings_spec.rb +212 -0
- data/spec/extensions/blacklist_security_spec.rb +1 -0
- data/spec/extensions/class_table_inheritance_spec.rb +1037 -39
- data/spec/extensions/column_select_spec.rb +20 -8
- data/spec/extensions/columns_introspection_spec.rb +3 -3
- data/spec/extensions/core_refinements_spec.rb +29 -12
- data/spec/extensions/dataset_associations_spec.rb +12 -12
- data/spec/extensions/def_dataset_method_spec.rb +100 -0
- data/spec/extensions/error_sql_spec.rb +1 -1
- data/spec/extensions/finder_spec.rb +260 -0
- data/spec/extensions/graph_each_spec.rb +2 -2
- data/spec/extensions/identifier_mangling_spec.rb +14 -8
- data/spec/extensions/inverted_subsets_spec.rb +4 -4
- data/spec/extensions/lazy_attributes_spec.rb +7 -0
- data/spec/extensions/many_through_many_spec.rb +38 -14
- data/spec/extensions/nested_attributes_spec.rb +18 -6
- data/spec/extensions/no_auto_literal_strings_spec.rb +1 -1
- data/spec/extensions/pg_enum_spec.rb +16 -1
- data/spec/extensions/pg_interval_spec.rb +11 -2
- data/spec/extensions/pg_loose_count_spec.rb +5 -0
- data/spec/extensions/pg_row_spec.rb +25 -0
- data/spec/extensions/prepared_statements_spec.rb +10 -1
- data/spec/extensions/query_spec.rb +2 -2
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/set_overrides_spec.rb +7 -3
- data/spec/extensions/sql_expr_spec.rb +0 -1
- data/spec/extensions/subset_conditions_spec.rb +6 -6
- data/spec/extensions/table_select_spec.rb +24 -12
- data/spec/extensions/to_dot_spec.rb +4 -4
- data/spec/extensions/whitelist_security_spec.rb +131 -0
- data/spec/integration/dataset_test.rb +9 -5
- data/spec/integration/model_test.rb +2 -0
- data/spec/integration/plugin_test.rb +2 -2
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/model/associations_spec.rb +39 -11
- data/spec/model/base_spec.rb +44 -24
- data/spec/model/class_dataset_methods_spec.rb +18 -16
- data/spec/model/dataset_methods_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +84 -24
- data/spec/model/model_spec.rb +97 -63
- data/spec/model/record_spec.rb +21 -13
- metadata +13 -2
|
@@ -27,22 +27,29 @@ module Sequel
|
|
|
27
27
|
# # SELECT * FROM albums WHERE (published IS NOT TRUE)
|
|
28
28
|
#
|
|
29
29
|
module InvertedSubsets
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
def self.apply(mod, &block)
|
|
31
|
+
mod.instance_exec do
|
|
32
|
+
@dataset_module_class = Class.new(@dataset_module_class) do
|
|
33
|
+
include DatasetModuleMethods
|
|
34
|
+
if block
|
|
35
|
+
define_method(:inverted_subset_name, &block)
|
|
36
|
+
private :inverted_subset_name
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
37
40
|
end
|
|
38
41
|
|
|
39
|
-
module
|
|
40
|
-
Plugins.inherited_instance_variables(self, :@inverted_subsets_name_block => nil)
|
|
41
|
-
|
|
42
|
+
module DatasetModuleMethods
|
|
42
43
|
# Define a not_ prefixed subset which inverts the subset condition.
|
|
43
|
-
def
|
|
44
|
+
def where(name, *args, &block)
|
|
44
45
|
super
|
|
45
|
-
|
|
46
|
+
exclude(inverted_subset_name(name), *args, &block)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def inverted_subset_name(name)
|
|
52
|
+
"not_#{name}"
|
|
46
53
|
end
|
|
47
54
|
end
|
|
48
55
|
end
|
|
@@ -283,7 +283,7 @@ module Sequel
|
|
|
283
283
|
iq = nil
|
|
284
284
|
end
|
|
285
285
|
fe = opts.final_edge
|
|
286
|
-
ds.graph(opts.associated_class, use_only_conditions ? only_conditions : (Array(opts.right_primary_key).zip(Array(fe[:left])) + conditions), :select=>select, :table_alias=>eo[:table_alias], :qualify=>:deep, :join_type=>eo[:join_type]||join_type, :join_only=>eo[:join_only], &graph_block)
|
|
286
|
+
ds.graph(opts.associated_class.dataset, use_only_conditions ? only_conditions : (Array(opts.right_primary_key).zip(Array(fe[:left])) + conditions), :select=>select, :table_alias=>eo[:table_alias], :qualify=>:deep, :join_type=>eo[:join_type]||join_type, :join_only=>eo[:join_only], &graph_block)
|
|
287
287
|
end
|
|
288
288
|
end
|
|
289
289
|
end
|
|
@@ -245,7 +245,7 @@ module Sequel
|
|
|
245
245
|
def nested_attributes_set_attributes(meta, obj, attributes)
|
|
246
246
|
if fields = meta[:fields]
|
|
247
247
|
fields = fields.call(obj) if fields.respond_to?(:call)
|
|
248
|
-
obj.
|
|
248
|
+
obj.set_fields(attributes, fields, :missing=>:skip)
|
|
249
249
|
else
|
|
250
250
|
obj.set(attributes)
|
|
251
251
|
end
|
|
@@ -59,7 +59,7 @@ module Sequel
|
|
|
59
59
|
@schema || (superclass.schema unless superclass == Model)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
# Defines a table schema (see Schema::
|
|
62
|
+
# Defines a table schema (see Schema::CreateTableGenerator for more information).
|
|
63
63
|
#
|
|
64
64
|
# This is only needed if you want to use the create_table/create_table! methods.
|
|
65
65
|
# Will also set the dataset if you provide a name, as well as setting
|
|
@@ -171,7 +171,7 @@ module Sequel
|
|
|
171
171
|
key = Array(sti_key_map[subclass]).dup
|
|
172
172
|
sti_subclass_added(key)
|
|
173
173
|
rp = dataset.row_proc
|
|
174
|
-
subclass.set_dataset(
|
|
174
|
+
subclass.set_dataset(sti_subclass_dataset(key), :inherited=>true)
|
|
175
175
|
subclass.instance_eval do
|
|
176
176
|
@dataset = @dataset.with_row_proc(rp)
|
|
177
177
|
@sti_key_array = key
|
|
@@ -230,6 +230,12 @@ module Sequel
|
|
|
230
230
|
raise(Error, "Invalid class type used: #{v.inspect}")
|
|
231
231
|
end
|
|
232
232
|
end
|
|
233
|
+
|
|
234
|
+
# Use the given dataset for the subclass, with key being the allowed
|
|
235
|
+
# values for the sti_kind field.
|
|
236
|
+
def sti_subclass_dataset(key)
|
|
237
|
+
sti_dataset.where(SQL::QualifiedIdentifier.new(sti_dataset.first_source_alias, sti_key)=>Sequel.delay{Sequel.synchronize{key}})
|
|
238
|
+
end
|
|
233
239
|
end
|
|
234
240
|
|
|
235
241
|
module InstanceMethods
|
|
@@ -24,13 +24,21 @@ module Sequel
|
|
|
24
24
|
# Album.where(Sequel.|(Album.published_conditions, :ready=>true)).sql
|
|
25
25
|
# # SELECT * FROM albums WHERE ((published IS TRUE) OR (ready IS TRUE))
|
|
26
26
|
module SubsetConditions
|
|
27
|
-
|
|
27
|
+
def self.apply(mod, &block)
|
|
28
|
+
mod.instance_exec do
|
|
29
|
+
@dataset_module_class = Class.new(@dataset_module_class) do
|
|
30
|
+
include DatasetModuleMethods
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module DatasetModuleMethods
|
|
28
36
|
# Also create a method that returns the conditions the filter uses.
|
|
29
|
-
def
|
|
37
|
+
def where(name, *args, &block)
|
|
30
38
|
super
|
|
31
39
|
cond = args
|
|
32
40
|
cond = cond.first if cond.size == 1
|
|
33
|
-
|
|
41
|
+
define_method(:"#{name}_conditions"){filter_expr(cond, &block)}
|
|
34
42
|
end
|
|
35
43
|
end
|
|
36
44
|
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module Plugins
|
|
5
|
+
# The whitelist_security plugin contains whitelist-based support for
|
|
6
|
+
# mass assignment, explicitly specifying which columns to allow mass assignment for,
|
|
7
|
+
# disallowing mass assignment for columns not listed. This exists mostly for backwards
|
|
8
|
+
# compatibility, it's best to use Sequel::Model#set_fields and Sequel::Model#update_fields
|
|
9
|
+
# to decide which fields to allow on a per-call basis.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
#
|
|
13
|
+
# # Make all model subclasses support allowed_columns
|
|
14
|
+
# Sequel::Model.plugin :whitelist_security
|
|
15
|
+
#
|
|
16
|
+
# # Make the Album class support allowed_columns
|
|
17
|
+
# Album.plugin :whitelist_security
|
|
18
|
+
module WhitelistSecurity
|
|
19
|
+
module ClassMethods
|
|
20
|
+
# Which columns should be the only columns allowed in a call to a mass assignment method (e.g. set)
|
|
21
|
+
# (default: not set, so all columns not otherwise restricted are allowed).
|
|
22
|
+
attr_reader :allowed_columns
|
|
23
|
+
|
|
24
|
+
Plugins.inherited_instance_variables(self, :@allowed_columns=>:dup)
|
|
25
|
+
|
|
26
|
+
# Freeze allowed columns when freezing model class.
|
|
27
|
+
def freeze
|
|
28
|
+
@allowed_columns.freeze
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Set the columns to allow when using mass assignment (e.g. +set+). Using this means that
|
|
33
|
+
# any columns not listed here will not be modified. If you have any virtual
|
|
34
|
+
# setter methods (methods that end in =) that you want to be used during
|
|
35
|
+
# mass assignment, they need to be listed here as well (without the =).
|
|
36
|
+
#
|
|
37
|
+
# It may be better to use a method such as +set_only+ or +set_fields+ that lets you specify
|
|
38
|
+
# the allowed fields per call.
|
|
39
|
+
#
|
|
40
|
+
# Artist.set_allowed_columns(:name, :hometown)
|
|
41
|
+
# Artist.set(:name=>'Bob', :hometown=>'Sactown') # No Error
|
|
42
|
+
# Artist.set(:name=>'Bob', :records_sold=>30000) # Error
|
|
43
|
+
def set_allowed_columns(*cols)
|
|
44
|
+
clear_setter_methods_cache
|
|
45
|
+
@allowed_columns = cols
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# If allowed_columns is set, only allow those columns.
|
|
51
|
+
def get_setter_methods
|
|
52
|
+
if allowed_columns
|
|
53
|
+
allowed_columns.map{|x| "#{x}="}
|
|
54
|
+
else
|
|
55
|
+
super
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module InstanceMethods
|
|
61
|
+
# Set all values using the entries in the hash, ignoring any setting of
|
|
62
|
+
# allowed_columns in the model.
|
|
63
|
+
#
|
|
64
|
+
# Artist.set_allowed_columns(:num_albums)
|
|
65
|
+
# artist.set_all(:name=>'Jim')
|
|
66
|
+
# artist.name # => 'Jim'
|
|
67
|
+
def set_all(hash)
|
|
68
|
+
set_restricted(hash, :all)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Set the values using the entries in the hash, only if the key
|
|
72
|
+
# is included in only. It may be a better idea to use +set_fields+
|
|
73
|
+
# instead of this method.
|
|
74
|
+
#
|
|
75
|
+
# artist.set_only({:name=>'Jim'}, :name)
|
|
76
|
+
# artist.name # => 'Jim'
|
|
77
|
+
#
|
|
78
|
+
# artist.set_only({:hometown=>'LA'}, :name) # Raise Error
|
|
79
|
+
def set_only(hash, *only)
|
|
80
|
+
set_restricted(hash, only.flatten)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Update all values using the entries in the hash, ignoring any setting of
|
|
84
|
+
# +allowed_columns+ in the model.
|
|
85
|
+
#
|
|
86
|
+
# Artist.set_allowed_columns(:num_albums)
|
|
87
|
+
# artist.update_all(:name=>'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
88
|
+
def update_all(hash)
|
|
89
|
+
update_restricted(hash, :all)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Update the values using the entries in the hash, only if the key
|
|
93
|
+
# is included in only. It may be a better idea to use +update_fields+
|
|
94
|
+
# instead of this method.
|
|
95
|
+
#
|
|
96
|
+
# artist.update_only({:name=>'Jim'}, :name)
|
|
97
|
+
# # UPDATE artists SET name = 'Jim' WHERE (id = 1)
|
|
98
|
+
#
|
|
99
|
+
# artist.update_only({:hometown=>'LA'}, :name) # Raise Error
|
|
100
|
+
def update_only(hash, *only)
|
|
101
|
+
update_restricted(hash, only.flatten)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
# If allowed_columns is set and set/update is called, only allow those columns.
|
|
107
|
+
def setter_methods(type)
|
|
108
|
+
if type == :default && model.allowed_columns
|
|
109
|
+
model.setter_methods
|
|
110
|
+
else
|
|
111
|
+
super
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
data/lib/sequel/sql.rb
CHANGED
|
@@ -35,6 +35,7 @@ module Sequel
|
|
|
35
35
|
|
|
36
36
|
# No-op method on ruby 1.9, which has a real +BasicObject+ class.
|
|
37
37
|
def self.remove_methods!
|
|
38
|
+
Sequel::Deprecation.deprecate("Sequel::BasicObject#remove_methods!", "It has no effect, so stop calling it")
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
end
|
|
@@ -58,7 +59,8 @@ module Sequel
|
|
|
58
59
|
# Create a new SQLTime instance given an hour, minute, and second.
|
|
59
60
|
def create(hour, minute, second, usec = 0)
|
|
60
61
|
t = date
|
|
61
|
-
|
|
62
|
+
meth = Sequel.application_timezone == :utc ? :utc : :local
|
|
63
|
+
send(meth, t.year, t.month, t.day, hour, minute, second, usec)
|
|
62
64
|
end
|
|
63
65
|
end
|
|
64
66
|
|
|
@@ -142,19 +144,20 @@ module Sequel
|
|
|
142
144
|
([self.class] + self.class.comparison_attrs.map{|x| send(x)}).hash
|
|
143
145
|
end
|
|
144
146
|
|
|
145
|
-
# Show the class name and instance variables for the object
|
|
146
|
-
# for correct operation on ruby 1.9.2.
|
|
147
|
+
# Show the class name and instance variables for the object.
|
|
147
148
|
def inspect
|
|
148
149
|
"#<#{self.class} #{instance_variables.map{|iv| "#{iv}=>#{instance_variable_get(iv).inspect}"}.join(', ')}>"
|
|
149
150
|
end
|
|
150
151
|
|
|
151
152
|
# Returns +self+, because <tt>SQL::Expression</tt> already acts like +LiteralString+.
|
|
152
153
|
def lit
|
|
154
|
+
Sequel::Deprecation.deprecate("Sequel::SQL::Expression#lit", "This method returns self, so just use the receiver")
|
|
153
155
|
self
|
|
154
156
|
end
|
|
155
157
|
|
|
156
158
|
# Alias of +to_s+
|
|
157
159
|
def sql_literal(ds)
|
|
160
|
+
Sequel::Deprecation.deprecate("Sequel::SQL::Expression#sql_literal", "Call Sequel::Dataset#literal with the expression instead")
|
|
158
161
|
s = String.new
|
|
159
162
|
to_s_append(ds, s)
|
|
160
163
|
s
|
|
@@ -379,7 +382,7 @@ module Sequel
|
|
|
379
382
|
#
|
|
380
383
|
# Sequel.case([[{:a=>[2,3]}, 1]], 0) # SQL: CASE WHEN a IN (2, 3) THEN 1 ELSE 0 END
|
|
381
384
|
# Sequel.case({:a=>1}, 0, :b) # SQL: CASE b WHEN a THEN 1 ELSE 0 END
|
|
382
|
-
def case(*args)
|
|
385
|
+
def case(*args)
|
|
383
386
|
SQL::CaseExpression.new(*args)
|
|
384
387
|
end
|
|
385
388
|
|
|
@@ -612,7 +615,7 @@ module Sequel
|
|
|
612
615
|
#
|
|
613
616
|
# DB[:items].select{|o| o.count(Sequel.lit('DISTINCT ?', :a))}.sql #=>
|
|
614
617
|
# "SELECT count(DISTINCT a) FROM items"
|
|
615
|
-
def lit(s, *args)
|
|
618
|
+
def lit(s, *args)
|
|
616
619
|
if args.empty?
|
|
617
620
|
if s.is_a?(LiteralString)
|
|
618
621
|
s
|
|
@@ -1108,7 +1111,7 @@ module Sequel
|
|
|
1108
1111
|
def self.from_value_pairs(pairs, op=:AND, negate=false)
|
|
1109
1112
|
pairs = pairs.map{|l,r| from_value_pair(l, r)}
|
|
1110
1113
|
pairs.map!{|ce| invert(ce)} if negate
|
|
1111
|
-
pairs.length == 1 ? pairs
|
|
1114
|
+
pairs.length == 1 ? pairs[0] : new(op, *pairs)
|
|
1112
1115
|
end
|
|
1113
1116
|
|
|
1114
1117
|
# Return a BooleanExpression based on the right side of the pair.
|
|
@@ -1422,6 +1425,7 @@ module Sequel
|
|
|
1422
1425
|
end
|
|
1423
1426
|
|
|
1424
1427
|
# Return a new function with an OVER clause (making it a window function).
|
|
1428
|
+
# See {SQL::Window} for the list of options +over+ can receive.
|
|
1425
1429
|
#
|
|
1426
1430
|
# Sequel.function(:row_number).over(:partition=>:col) # row_number() OVER (PARTITION BY col)
|
|
1427
1431
|
def over(window=OPTS)
|
|
@@ -1614,8 +1618,14 @@ module Sequel
|
|
|
1614
1618
|
# Create an object with the given string, placeholder arguments, and parens flag.
|
|
1615
1619
|
def initialize(str, args, parens=false)
|
|
1616
1620
|
@str = str
|
|
1617
|
-
@args = args.is_a?(Array) && args.length == 1 && (v = args
|
|
1621
|
+
@args = args.is_a?(Array) && args.length == 1 && (v = args[0]).is_a?(Hash) ? v : args
|
|
1618
1622
|
@parens = parens
|
|
1623
|
+
freeze
|
|
1624
|
+
end
|
|
1625
|
+
|
|
1626
|
+
# Return a copy of the that will be surrounded by parantheses.
|
|
1627
|
+
def with_parens
|
|
1628
|
+
@parens ? self : self.class.new(@str, @args, true)
|
|
1619
1629
|
end
|
|
1620
1630
|
|
|
1621
1631
|
to_s_method :placeholder_literal_string_sql
|
|
@@ -1758,7 +1768,7 @@ module Sequel
|
|
|
1758
1768
|
r, rre, rci = like_element(ce)
|
|
1759
1769
|
BooleanExpression.new(LIKE_MAP[[lre||rre, lci||rci]], l, r)
|
|
1760
1770
|
end
|
|
1761
|
-
ces.length == 1 ? ces
|
|
1771
|
+
ces.length == 1 ? ces[0] : BooleanExpression.new(:OR, *ces)
|
|
1762
1772
|
end
|
|
1763
1773
|
|
|
1764
1774
|
# Returns a three element array, made up of:
|
|
@@ -1925,47 +1935,81 @@ module Sequel
|
|
|
1925
1935
|
|
|
1926
1936
|
# Return a literal string created with the given string.
|
|
1927
1937
|
def `(s)
|
|
1938
|
+
Sequel::Deprecation.deprecate("Using Sequel#VirtualRow#` to create a literal SQL fragment", "Use Sequel.lit instead")
|
|
1928
1939
|
Sequel::LiteralString.new(s)
|
|
1929
1940
|
end
|
|
1930
1941
|
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
if
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
when :*
|
|
1941
|
-
Function.new(m, *args).*
|
|
1942
|
-
when :distinct
|
|
1943
|
-
Function.new(m, *args).distinct
|
|
1944
|
-
when :over
|
|
1945
|
-
opts = args.shift || OPTS
|
|
1946
|
-
f = Function.new(m, *::Kernel.Array(opts[:args]))
|
|
1947
|
-
f = f.* if opts[:*]
|
|
1948
|
-
f.over(opts)
|
|
1942
|
+
include(Module.new do
|
|
1943
|
+
# Return an +Identifier+, +QualifiedIdentifier+, or +Function+, depending
|
|
1944
|
+
# on arguments and whether a block is provided. Does not currently call the block.
|
|
1945
|
+
# See the class level documentation.
|
|
1946
|
+
def method_missing(m, *args, &block)
|
|
1947
|
+
if block
|
|
1948
|
+
if args.empty?
|
|
1949
|
+
Sequel::Deprecation.deprecate("Passing a block to a virtual row method to create a Sequel::SQL::Function", "Replace the block with a call to .function to create a function, or use the virtual_row_method_block extension")
|
|
1950
|
+
Function.new(m)
|
|
1949
1951
|
else
|
|
1950
|
-
|
|
1952
|
+
case args.shift
|
|
1953
|
+
when :*
|
|
1954
|
+
Sequel::Deprecation.deprecate("Passing a block to a virtual row method with a :* argument to create a Sequel::SQL::Function", "Remove the :* argument and block and a call to .function.* to create a function(*) call, or use the virtual_row_method_block extension")
|
|
1955
|
+
Function.new(m, *args).*
|
|
1956
|
+
when :distinct
|
|
1957
|
+
Sequel::Deprecation.deprecate("Passing a block to a virtual row method with a :distinct argument to create a Sequel::SQL::Function", "Remove the :distinct argument and block with a call to .function.distinct to create a function(DISTINCT ...) call, or use the virtual_row_method_block extension")
|
|
1958
|
+
Function.new(m, *args).distinct
|
|
1959
|
+
when :over
|
|
1960
|
+
opts = args.shift || OPTS
|
|
1961
|
+
f = Function.new(m, *::Kernel.Array(opts[:args]))
|
|
1962
|
+
if opts[:*]
|
|
1963
|
+
Sequel::Deprecation.deprecate("Passing a block to a virtual row method with a :over argument and :* option to create a Sequel::SQL::WindowFunction", "Remove the :over argument, :* option and block with a call to .function.*.over with the options to create a function(*) OVER (...) call, or use the virtual_row_method_block extension")
|
|
1964
|
+
f = f.*
|
|
1965
|
+
else
|
|
1966
|
+
Sequel::Deprecation.deprecate("Passing a block to a virtual row method with a :over argument to create a Sequel::SQL::WindowFunction", "Remove the :over argument and block with a call to .function.over with the options to create a function(...) OVER (...) call, or use the virtual_row_method_block extension")
|
|
1967
|
+
end
|
|
1968
|
+
f.over(opts)
|
|
1969
|
+
else
|
|
1970
|
+
Kernel.raise(Error, 'unsupported VirtualRow method argument used with block')
|
|
1971
|
+
end
|
|
1972
|
+
end
|
|
1973
|
+
elsif args.empty?
|
|
1974
|
+
if split = Sequel.split_symbols?
|
|
1975
|
+
table, column = m.to_s.split(DOUBLE_UNDERSCORE, 2)
|
|
1976
|
+
if column && split == :deprecated
|
|
1977
|
+
Sequel::Deprecation.deprecate("Splitting virtual row method names", "Either set Sequel.split_symbols = true, or change #{m.inspect} to #{table}[:#{column}]")
|
|
1978
|
+
end
|
|
1979
|
+
column ? QualifiedIdentifier.new(table, column) : Identifier.new(m)
|
|
1980
|
+
else
|
|
1981
|
+
Identifier.new(m)
|
|
1951
1982
|
end
|
|
1952
|
-
end
|
|
1953
|
-
elsif args.empty?
|
|
1954
|
-
if Sequel.split_symbols?
|
|
1955
|
-
table, column = m.to_s.split(DOUBLE_UNDERSCORE, 2)
|
|
1956
|
-
column ? QualifiedIdentifier.new(table, column) : Identifier.new(m)
|
|
1957
1983
|
else
|
|
1958
|
-
|
|
1984
|
+
Function.new(m, *args)
|
|
1959
1985
|
end
|
|
1960
|
-
else
|
|
1961
|
-
Function.new(m, *args)
|
|
1962
1986
|
end
|
|
1963
|
-
end
|
|
1987
|
+
end)
|
|
1964
1988
|
|
|
1965
1989
|
Sequel::VIRTUAL_ROW = new
|
|
1966
1990
|
end
|
|
1967
1991
|
|
|
1968
1992
|
# A +Window+ is part of a window function specifying the window over which a window function operates.
|
|
1993
|
+
#
|
|
1994
|
+
# Sequel::SQL::Window.new(partition: :col1)
|
|
1995
|
+
# # (PARTITION BY col1)
|
|
1996
|
+
# Sequel::SQL::Window.new(partition: [:col2, :col3])
|
|
1997
|
+
# # (PARTITION BY col2, col3)
|
|
1998
|
+
#
|
|
1999
|
+
# Sequel::SQL::Window.new(order: :col4)
|
|
2000
|
+
# # (ORDER BY col4)
|
|
2001
|
+
# Sequel::SQL::Window.new(order: [:col5, Sequel.desc(:col6)])
|
|
2002
|
+
# # (ORDER BY col5, col6 DESC)
|
|
2003
|
+
#
|
|
2004
|
+
# Sequel::SQL::Window.new(partition: :col7, frame: :all)
|
|
2005
|
+
# # (PARTITION BY col7 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
|
|
2006
|
+
# Sequel::SQL::Window.new(partition: :col7, frame: :rows)
|
|
2007
|
+
# # (PARTITION BY col7 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
|
|
2008
|
+
# Sequel::SQL::Window.new(partition: :col7, frame: "RANGE CURRENT ROW")
|
|
2009
|
+
# # (PARTITION BY col7 RANGE CURRENT ROW)
|
|
2010
|
+
#
|
|
2011
|
+
# Sequel::SQL::Window.new(window: :named_window) # you can create a named window with Dataset#window
|
|
2012
|
+
# # (named_window)
|
|
1969
2013
|
class Window < Expression
|
|
1970
2014
|
# The options for this window. Options currently supported:
|
|
1971
2015
|
# :frame :: if specified, should be :all, :rows, or a String that is used literally. :all always operates over all rows in the
|
data/lib/sequel/timezones.rb
CHANGED
|
@@ -171,6 +171,7 @@ module Sequel
|
|
|
171
171
|
v.to_datetime
|
|
172
172
|
else
|
|
173
173
|
# :nocov:
|
|
174
|
+
# SEQUEL5: Remove
|
|
174
175
|
# Ruby 1.8 code, %N not available and %z broken on Windows
|
|
175
176
|
offset_hours, offset_minutes = (v.utc_offset/60).divmod(60)
|
|
176
177
|
string_to_datetime(v.strftime("%Y-%m-%dT%H:%M:%S") << sprintf(".%06i%+03i%02i", v.usec, offset_hours, offset_minutes))
|
|
@@ -186,6 +187,7 @@ module Sequel
|
|
|
186
187
|
v.to_time
|
|
187
188
|
else
|
|
188
189
|
# :nocov:
|
|
190
|
+
# SEQUEL5: Remove
|
|
189
191
|
string_to_datetime(v.strftime("%FT%T.%N%z"))
|
|
190
192
|
# :nocov:
|
|
191
193
|
end
|