sequel 4.31.0 → 4.32.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 +24 -0
- data/Rakefile +17 -15
- data/doc/association_basics.rdoc +7 -3
- data/doc/opening_databases.rdoc +7 -0
- data/doc/release_notes/4.32.0.txt +132 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +70 -26
- data/doc/testing.rdoc +1 -0
- data/lib/sequel/adapters/jdbc.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +3 -4
- data/lib/sequel/adapters/shared/mysql.rb +14 -1
- data/lib/sequel/adapters/shared/sqlite.rb +2 -2
- data/lib/sequel/extensions/_pretty_table.rb +2 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +2 -0
- data/lib/sequel/extensions/columns_introspection.rb +2 -0
- data/lib/sequel/extensions/connection_validator.rb +2 -0
- data/lib/sequel/extensions/constraint_validations.rb +2 -0
- data/lib/sequel/extensions/core_extensions.rb +1 -5
- data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -0
- data/lib/sequel/extensions/dataset_source_alias.rb +2 -0
- data/lib/sequel/extensions/date_arithmetic.rb +2 -0
- data/lib/sequel/extensions/empty_array_consider_nulls.rb +3 -1
- data/lib/sequel/extensions/error_sql.rb +2 -0
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/filter_having.rb +2 -0
- data/lib/sequel/extensions/from_block.rb +2 -0
- data/lib/sequel/extensions/graph_each.rb +2 -0
- data/lib/sequel/extensions/hash_aliases.rb +2 -0
- data/lib/sequel/extensions/inflector.rb +2 -0
- data/lib/sequel/extensions/looser_typecasting.rb +3 -1
- data/lib/sequel/extensions/meta_def.rb +2 -0
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +2 -0
- data/lib/sequel/extensions/no_auto_literal_strings.rb +84 -0
- data/lib/sequel/extensions/null_dataset.rb +2 -0
- data/lib/sequel/extensions/pagination.rb +2 -0
- data/lib/sequel/extensions/pg_array.rb +2 -4
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -4
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_inet.rb +2 -4
- data/lib/sequel/extensions/pg_inet_ops.rb +2 -0
- data/lib/sequel/extensions/pg_interval.rb +2 -4
- data/lib/sequel/extensions/pg_json.rb +4 -4
- data/lib/sequel/extensions/pg_json_ops.rb +3 -0
- data/lib/sequel/extensions/pg_loose_count.rb +2 -0
- data/lib/sequel/extensions/pg_range.rb +2 -4
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -4
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/pg_static_cache_updater.rb +2 -0
- data/lib/sequel/extensions/pretty_table.rb +2 -0
- data/lib/sequel/extensions/query.rb +3 -0
- data/lib/sequel/extensions/query_literals.rb +7 -5
- data/lib/sequel/extensions/round_timestamps.rb +4 -3
- data/lib/sequel/extensions/schema_caching.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +2 -0
- data/lib/sequel/extensions/select_remove.rb +2 -0
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +2 -0
- data/lib/sequel/extensions/server_block.rb +3 -0
- data/lib/sequel/extensions/set_overrides.rb +2 -0
- data/lib/sequel/extensions/split_array_nil.rb +2 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +2 -0
- data/lib/sequel/extensions/to_dot.rb +2 -0
- data/lib/sequel/model/associations.rb +95 -55
- data/lib/sequel/plugins/association_pks.rb +58 -33
- data/lib/sequel/plugins/eager_each.rb +22 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +44 -3
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +34 -6
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/bin_spec.rb +2 -2
- data/spec/core/dataset_spec.rb +7 -0
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +24 -0
- data/spec/extensions/eager_each_spec.rb +25 -1
- data/spec/extensions/no_auto_literal_strings_spec.rb +65 -0
- data/spec/extensions/pg_range_spec.rb +1 -0
- data/spec/extensions/spec_helper.rb +5 -5
- data/spec/extensions/tactical_eager_loading_spec.rb +71 -17
- data/spec/integration/associations_test.rb +77 -62
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/plugin_test.rb +22 -0
- data/spec/integration/prepared_statement_test.rb +8 -8
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/association_reflection_spec.rb +30 -0
- data/spec/model/associations_spec.rb +177 -16
- metadata +6 -2
data/lib/sequel/adapters/jdbc.rb
CHANGED
@@ -632,7 +632,8 @@ module Sequel
|
|
632
632
|
:allow_null=>(h[:nullable] != 0),
|
633
633
|
:primary_key=>pks.include?(h[:column_name]),
|
634
634
|
:column_size=>h[:column_size],
|
635
|
-
:scale=>h[:decimal_digits]
|
635
|
+
:scale=>h[:decimal_digits],
|
636
|
+
:remarks=>h[:remarks]
|
636
637
|
}
|
637
638
|
if s[:primary_key]
|
638
639
|
s[:auto_increment] = h[:is_autoincrement] == "YES"
|
@@ -306,10 +306,9 @@ module Sequel
|
|
306
306
|
|
307
307
|
# Disconnect given connection
|
308
308
|
def disconnect_connection(conn)
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
end
|
309
|
+
conn.finish
|
310
|
+
rescue PGError, IOError
|
311
|
+
nil
|
313
312
|
end
|
314
313
|
|
315
314
|
if SEQUEL_POSTGRES_USES_PG && Object.const_defined?(:PG) && ::PG.const_defined?(:Constants) && ::PG::Constants.const_defined?(:PG_DIAG_SCHEMA_NAME)
|
@@ -682,6 +682,18 @@ module Sequel
|
|
682
682
|
def calc_found_rows
|
683
683
|
clone(:calc_found_rows => true)
|
684
684
|
end
|
685
|
+
|
686
|
+
# Sets up the select methods to delete from if deleting from a
|
687
|
+
# joined dataset:
|
688
|
+
#
|
689
|
+
# DB[:a].join(:b, :a_id=>:id).delete
|
690
|
+
# # DELETE a FROM a INNER JOIN b ON (b.a_id = a.id)
|
691
|
+
#
|
692
|
+
# DB[:a].join(:b, :a_id=>:id).delete_from(:a, :b).delete
|
693
|
+
# # DELETE a, b FROM a INNER JOIN b ON (b.a_id = a.id)
|
694
|
+
def delete_from(*tables)
|
695
|
+
clone(:delete_from=>tables)
|
696
|
+
end
|
685
697
|
|
686
698
|
# Return the results of an EXPLAIN query as a string. Options:
|
687
699
|
# :extended :: Use EXPLAIN EXPTENDED instead of EXPLAIN if true.
|
@@ -847,7 +859,8 @@ module Sequel
|
|
847
859
|
def delete_from_sql(sql)
|
848
860
|
if joined_dataset?
|
849
861
|
sql << SPACE
|
850
|
-
|
862
|
+
tables = @opts[:delete_from] || @opts[:from][0..0]
|
863
|
+
source_list_append(sql, tables)
|
851
864
|
sql << FROM
|
852
865
|
source_list_append(sql, @opts[:from])
|
853
866
|
select_join_sql(sql)
|
@@ -13,9 +13,9 @@ module Sequel
|
|
13
13
|
AUTO_VACUUM = [:none, :full, :incremental].freeze
|
14
14
|
PRIMARY_KEY_INDEX_RE = /\Asqlite_autoindex_/.freeze
|
15
15
|
SYNCHRONOUS = [:off, :normal, :full].freeze
|
16
|
-
TABLES_FILTER =
|
16
|
+
TABLES_FILTER = Sequel.~(:name=>'sqlite_sequence'.freeze) & {:type => 'table'.freeze}
|
17
17
|
TEMP_STORE = [:default, :file, :memory].freeze
|
18
|
-
VIEWS_FILTER =
|
18
|
+
VIEWS_FILTER = {:type => 'view'.freeze}.freeze
|
19
19
|
TRANSACTION_MODE = {
|
20
20
|
:deferred => "BEGIN DEFERRED TRANSACTION".freeze,
|
21
21
|
:immediate => "BEGIN IMMEDIATE TRANSACTION".freeze,
|
@@ -44,6 +44,8 @@
|
|
44
44
|
# threaded pools work fine even in single threaded code, so if
|
45
45
|
# you are currently using a single threaded pool and want to
|
46
46
|
# use this extension, switch to using a threaded pool.
|
47
|
+
#
|
48
|
+
# Related module: Sequel::ConnectionValidator
|
47
49
|
|
48
50
|
#
|
49
51
|
module Sequel
|
@@ -123,6 +123,8 @@
|
|
123
123
|
# <tt>drop_constraint_validations_for(:table=>'table')</tt>, and then
|
124
124
|
# readd all constraints you want to use inside the alter table block,
|
125
125
|
# making no other changes inside the alter_table block.
|
126
|
+
#
|
127
|
+
# Related module: Sequel::ConstraintValidations
|
126
128
|
|
127
129
|
#
|
128
130
|
module Sequel
|
@@ -3,11 +3,7 @@
|
|
3
3
|
# These are extensions to core classes that Sequel enables by default.
|
4
4
|
# They make using Sequel's DSL easier by adding methods to Array,
|
5
5
|
# Hash, String, and Symbol to add methods that return Sequel
|
6
|
-
# expression objects.
|
7
|
-
#
|
8
|
-
# This extension is currently loaded by default, but that will no
|
9
|
-
# longer be true in Sequel 4. Starting in Sequel 4, you will
|
10
|
-
# need to load it manually via:
|
6
|
+
# expression objects. To load the extension:
|
11
7
|
#
|
12
8
|
# Sequel.extension :core_extensions
|
13
9
|
|
@@ -21,11 +21,13 @@
|
|
21
21
|
# is probably the desired behavior if you are using this extension:
|
22
22
|
#
|
23
23
|
# DB.extension(:empty_array_consider_nulls)
|
24
|
+
#
|
25
|
+
# Related module: Sequel::EmptyArrayConsiderNulls
|
24
26
|
|
25
27
|
#
|
26
28
|
module Sequel
|
27
29
|
module EmptyArrayConsiderNulls
|
28
|
-
# Use
|
30
|
+
# Use an expression that returns NULL if the column value is NULL.
|
29
31
|
def empty_array_value(op, cols)
|
30
32
|
c = Array(cols)
|
31
33
|
SQL::BooleanExpression.from_value_pairs(c.zip(c), :AND, op == :IN)
|
@@ -11,6 +11,8 @@
|
|
11
11
|
# To load the extension into the database:
|
12
12
|
#
|
13
13
|
# DB.extension :looser_typecasting
|
14
|
+
#
|
15
|
+
# Related module: Sequel::LooserTypecasting
|
14
16
|
|
15
17
|
#
|
16
18
|
module Sequel
|
@@ -25,7 +27,7 @@ module Sequel
|
|
25
27
|
value.to_i
|
26
28
|
end
|
27
29
|
|
28
|
-
# Typecast the value to an
|
30
|
+
# Typecast the value to an String using to_s instead of Kernel.String
|
29
31
|
def typecast_value_string(value)
|
30
32
|
value.to_s
|
31
33
|
end
|
@@ -7,6 +7,10 @@
|
|
7
7
|
# To load the extension:
|
8
8
|
#
|
9
9
|
# Sequel.extension :migration
|
10
|
+
#
|
11
|
+
# Related modules: Sequel::Migration, Sequel::SimpleMigration,
|
12
|
+
# Sequel::MigrationDSL, Sequel::MigrationReverser, Sequel::MigrationAlterTableReverser,
|
13
|
+
# Sequel::Migrator, Sequel::IntegerMigrator, Sequel::TimestampMigrator
|
10
14
|
|
11
15
|
#
|
12
16
|
module Sequel
|
@@ -38,6 +38,8 @@
|
|
38
38
|
# timezone when fetching rows is dependent on the database adapter,
|
39
39
|
# and only works on adapters where Sequel itself does the conversion.
|
40
40
|
# It should work on mysql, postgres, sqlite, ibmdb, and jdbc.
|
41
|
+
#
|
42
|
+
# Related module: Sequel::NamedTimezones
|
41
43
|
|
42
44
|
require 'tzinfo'
|
43
45
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The no_auto_literal_strings extension removes Sequel's automatic conversion
|
4
|
+
# of strings to literal strings in the dataset filter methods. By default,
|
5
|
+
# Sequel considers a string passed to a filter method as a literal string:
|
6
|
+
#
|
7
|
+
# DB[:table].where("name > 'A'")
|
8
|
+
#
|
9
|
+
# This is fine, except when the string is derived from user input:
|
10
|
+
#
|
11
|
+
# DB[:table].where("name > '#{params[:user]}'") # SQL Injection!
|
12
|
+
#
|
13
|
+
# Sequel does support using placeholders for such strings:
|
14
|
+
#
|
15
|
+
# DB[:table].where("name > ?", params[:user].to_s) # Safe
|
16
|
+
#
|
17
|
+
# However, if you forget to user placeholders, and pass a string to a filter
|
18
|
+
# method that is derived from user input, you open yourself up to SQL injection.
|
19
|
+
# With this extension, using a plain string in a filter method will result
|
20
|
+
# in an exception being raised. You either need to explicitly use a literal
|
21
|
+
# string:
|
22
|
+
#
|
23
|
+
# DB[:table].where(Sequel.lit("name > ?", params[:user].to_s))
|
24
|
+
#
|
25
|
+
# or you need to construct the same SQL using a non-string based approach:
|
26
|
+
#
|
27
|
+
# DB[:table].where{|o| o.name > params[:user].to_s}
|
28
|
+
#
|
29
|
+
# Note that as listed in Sequel's security guide, a large number of dataset
|
30
|
+
# methods call down to a filtering method, and this protects all of those
|
31
|
+
# cases.
|
32
|
+
#
|
33
|
+
# This extension also protects the use of a plain string passed to Dataset#update:
|
34
|
+
#
|
35
|
+
# DB[:table].update("column = column + 1")
|
36
|
+
#
|
37
|
+
# Again, you either need to explicitly use a literal string:
|
38
|
+
#
|
39
|
+
# DB[:table].update(Sequel.lit("column = column + 1"))
|
40
|
+
#
|
41
|
+
# or construct the same SQL using a non-string based approach:
|
42
|
+
#
|
43
|
+
# DB[:table].update(:column => Sequel.expr(:column) + 1)
|
44
|
+
#
|
45
|
+
# Related module: Sequel::Dataset::NoAutoLiteralStrings
|
46
|
+
|
47
|
+
#
|
48
|
+
module Sequel
|
49
|
+
class Dataset
|
50
|
+
module NoAutoLiteralStrings
|
51
|
+
# Raise an error if passing a plain string or an array whose first
|
52
|
+
# entry is a plain string.
|
53
|
+
def filter_expr(expr = nil)
|
54
|
+
case expr
|
55
|
+
when LiteralString
|
56
|
+
super
|
57
|
+
when String
|
58
|
+
raise Error, "plain string passed to a dataset filtering method"
|
59
|
+
when Array
|
60
|
+
if expr.first.is_a?(String) && !expr.first.is_a?(LiteralString)
|
61
|
+
raise Error, "plain string passed to a dataset filtering method"
|
62
|
+
end
|
63
|
+
super
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Raise an error if passing a plain string.
|
70
|
+
def update_sql(values=OPTS)
|
71
|
+
case values
|
72
|
+
when LiteralString
|
73
|
+
super
|
74
|
+
when String
|
75
|
+
raise Error, "plain string passed to a dataset filtering method"
|
76
|
+
else
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
register_extension(:no_auto_literal_strings, NoAutoLiteralStrings)
|
83
|
+
end
|
84
|
+
end
|
@@ -41,10 +41,6 @@
|
|
41
41
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
42
42
|
# for details on using postgres array columns in CREATE/ALTER TABLE statements.
|
43
43
|
#
|
44
|
-
# If you are not using the native postgres or jdbc/postgresql adapter and are using array
|
45
|
-
# types as model column values you probably should use the the pg_typecast_on_load plugin
|
46
|
-
# if the column values are returned as a string.
|
47
|
-
#
|
48
44
|
# This extension by default includes handlers for array types for
|
49
45
|
# all scalar types that the native postgres adapter handles. It
|
50
46
|
# also makes it easy to add support for other array types. In
|
@@ -84,6 +80,8 @@
|
|
84
80
|
# operators, look into the pg_array_ops extension.
|
85
81
|
#
|
86
82
|
# This extension requires the strscan and delegate libraries.
|
83
|
+
#
|
84
|
+
# Related module: Sequel::Postgres::PGArray
|
87
85
|
|
88
86
|
require 'delegate'
|
89
87
|
require 'strscan'
|