sequel 4.45.0 → 4.46.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|