sequel 5.67.0 → 5.69.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff5af191af88ca381359503cfd9601ec8f18a9d782b68a3de4a8c9dac080eddc
4
- data.tar.gz: 786d20f7eac9325748c259130951643856e34051e64b02aa17493f6d0283eb52
3
+ metadata.gz: dc06712b20f476b85d0a08a4d94d96a2c74e0a632053baeecefbecd4cd60d476
4
+ data.tar.gz: dd5fdc130ad5a4fb19579c45e426d2a2da6431b14af18dd87fd8785b45fb0684
5
5
  SHA512:
6
- metadata.gz: db251488ea0739af5ecf6db332a1cff729cffbf31dfabfc7235f3c27f807366bc9feddf147797e4dd5980348fda6a640cc5ceef7e6255cddcd317acb7172be90
7
- data.tar.gz: 45b0e24847ccb365f1d7d06d35c85f05718802375877ab3d0315deb952f72171e26b5676861c25cf1e840f831d216f99eaddcbb717fc752d75077f19ae13980c
6
+ metadata.gz: e0c1138064b489cbcdc7740f047095279e1f6e9a71e2ef1502359fbc440e8a2caed3009745d0aadbd51c7d2c13dbc6b971150f370bbe10a0f2e566e0cf219722
7
+ data.tar.gz: 364735d4186439b97d2d7e5a83c3ddd13fdcf5af433b97d1892898b3f04115191a4dc77fd5d711a7ad715e8a707c5389aac6bfb539840464cff53e6d3f04ff6f
data/CHANGELOG CHANGED
@@ -1,3 +1,25 @@
1
+ === 5.69.0 (2023-06-01)
2
+
3
+ * Avoid unsupported flag warning when using the mysql adapter with ruby-mysql 3+ (jeremyevans)
4
+
5
+ * Make mysql adapter work with ruby-mysql 4+ (jeremyevans)
6
+
7
+ * Add Model::DatasetModule#model accessor (davekaro) (#2040)
8
+
9
+ * Add trilogy adapter (jeremyevans)
10
+
11
+ === 5.68.0 (2023-05-01)
12
+
13
+ * Add validation_helpers_generic_type_messages plugin for more useful type validation failure messages (jeremyevans) (#2028)
14
+
15
+ * Make constraint_validations plugin not validate missing columns that have a default value (jeremyevans) (#2023)
16
+
17
+ * Skip normal type name parsing for enum/array/composite/range/multirange types on PostgreSQL (jeremyevans) (#2019)
18
+
19
+ * Fix corner case where pg_extended_date_support did not work correctly when using the jdbc/postgresql adapter (jeremyevans)
20
+
21
+ * Include :min_value and :max_value schema entries for date/timestamp/timestamptz columns on PostgreSQL 9.6+ (jeremyevans)
22
+
1
23
  === 5.67.0 (2023-04-01)
2
24
 
3
25
  * Fix dumping of string column sizes in the schema dumper on MSSQL (jeremyevans) (#2013)
data/README.rdoc CHANGED
@@ -13,7 +13,7 @@ toolkit for Ruby.
13
13
  database sharding.
14
14
  * Sequel currently has adapters for ADO, Amalgalite,
15
15
  IBM_DB, JDBC, MySQL, Mysql2, ODBC, Oracle,
16
- PostgreSQL, SQLAnywhere, SQLite3, and TinyTDS.
16
+ PostgreSQL, SQLAnywhere, SQLite3, TinyTDS, and Trilogy.
17
17
 
18
18
  == Resources
19
19
 
@@ -670,8 +670,10 @@ polymorphic associations in Sequel about as easy as it is in ActiveRecord. Howe
670
670
  here's how they can be done using Sequel's custom associations (the sequel_polymorphic
671
671
  external plugin is just a generic version of this code):
672
672
 
673
+ Sequel.extension :inflector # for attachable_type.constantize
674
+
673
675
  class Asset < Sequel::Model
674
- many_to_one :attachable, reciprocal: :assets,
676
+ many_to_one :attachable, reciprocal: :assets, reciprocal_type: :one_to_many,
675
677
  setter: (lambda do |attachable|
676
678
  self[:attachable_id] = (attachable.pk if attachable)
677
679
  self[:attachable_type] = (attachable.class.name if attachable)
@@ -279,7 +279,7 @@ if either the :sslca or :sslkey option is given.
279
279
 
280
280
  === mysql2
281
281
 
282
- This is a newer MySQL adapter that does typecasting in C, so it is often faster than the
282
+ This is a MySQL adapter that does typecasting in C, so it is often faster than the
283
283
  mysql adapter. The options given are passed to Mysql2::Client.new, see the mysql2 documentation
284
284
  for details on what options are supported. The :timeout, :auto_is_null, :sql_mode, and :disable_split_materialized
285
285
  options supported by the mysql adapter are also supported for mysql2 adapter (and any other adapters connecting to
@@ -423,3 +423,10 @@ Other Sequel specific options:
423
423
  This should be specified as an integer. If you plan on setting large
424
424
  text or blob values via tinytds, you should use this option or modify
425
425
  your freetds.conf file.
426
+
427
+ === trilogy
428
+
429
+ This is a MySQL adapter that does typecasting in C, and does not require any mysql client libraries installed.
430
+ The options given are passed to Trilogy.new, see the trilogy documentation for details on what options are
431
+ supported. The :timeout, :auto_is_null, :sql_mode, and :disable_split_materialized
432
+ options supported by the mysql adapter are also supported for trilogy adapter.
@@ -0,0 +1,61 @@
1
+ = New Features
2
+
3
+ * On PostgreSQL 9.6+, date, timestamp, and timestamptz columns now
4
+ have min_value and max_value column schema entries, allowing the
5
+ auto_validations plugin to automatically enforce minimum and
6
+ maximum values for these column types, raising a validation error
7
+ before saving, instead of database error when the query is sent
8
+ to the database.
9
+
10
+ * A validation_helpers_generic_type_messages plugin has been added,
11
+ which improves the default type validation error messages in
12
+ validation_helpers. This change was not made directly to
13
+ validation_helpers for backwards compatibility reasons, but will
14
+ probably become the default behavior in Sequel 6. Some examples
15
+ of the improvements:
16
+
17
+ # :blob type
18
+ # validation_helpers default: "value is not a valid sequel::sql::blob"
19
+ # with this plugin: "value is not a blob"
20
+
21
+ # :boolean type
22
+ # validation_helpers default: "value is not a valid trueclass or falseclass"
23
+ # with this plugin: "value is not true or false"
24
+
25
+ # :datetime type
26
+ # validation_helpers default: "value is not a valid time or datetime"
27
+ # with this plugin: "value is not a valid timestamp"
28
+
29
+ # custom/database-specific types
30
+ # validation_helpers default: "value is not a valid sequel::class_name"
31
+ # with this plugin: "value is not the expected type"
32
+
33
+ = Improvements
34
+
35
+ * The constraint_validations plugin no longer raises validation
36
+ errors for missing columns that have a default value. If a column
37
+ is missing but has a default value, we can assume the default
38
+ value is valid. Additionally, the constraint validations are now
39
+ based on the underlying column value and not any deserialized
40
+ value, so that the validation matches the constraint.
41
+
42
+ * On PostgreSQL, normal type name parsing is skipped for enum,
43
+ array, composite, range, and multirange types, ensuring that
44
+ such types will not be treated incorrectly based on their
45
+ type name.
46
+
47
+ * The pg_extended_date_support extension now works correctly with
48
+ the jdbc/postgresql adapter if there is already an entry in the
49
+ oid_convertor_map for the timestamp and timestamptz types.
50
+
51
+ = Backwards Compatibility
52
+
53
+ * Database#schema_column_type is no longer called for all columns
54
+ on PostgreSQL when parsing schema. Enum, array, composite, range,
55
+ and multirange types each have their own separate type parsing
56
+ method. So if you were overriding Database#schema_column_type to
57
+ implement custom column schema parsing, you may need to adjust
58
+ your code.
59
+
60
+ * The Sequel::Postgres::ExtendedDateSupport::DATE_YEAR_1 constant
61
+ has been removed.
@@ -0,0 +1,26 @@
1
+ = New Features
2
+
3
+ * An adapter has been added for the trilogy MySQL driver. One large
4
+ advantage over mysql2 is that trilogy does not require any MySQL
5
+ client libraries installed on the machine. The trilogy adapter
6
+ has basically the same issues/skipped specs as the mysql2 adapter,
7
+ but it also does not support an application_timezone different
8
+ than the database_timezone.
9
+
10
+ * Model dataset modules now have a model accessor, allowing for
11
+ code such as:
12
+
13
+ class Foo < Sequel::Model
14
+ dataset_module do
15
+ where :kept, Sequel[model.table_name][:discarded_at] => nil
16
+ end
17
+ end
18
+
19
+ = Improvements
20
+
21
+ * The mysql adapter now works with ruby-mysql 4 (the pure-ruby
22
+ MySQL driver). Note that multi-results support does not work
23
+ with ruby-mysql 4 (it doesn't work with mysql2, trilogy, or
24
+ other Sequel adapters in general).
25
+
26
+ * Warnings for unsupported flags are now avoided on ruby-mysql 3.
data/doc/sharding.rdoc CHANGED
@@ -39,7 +39,9 @@ is the simplest configuration:
39
39
  servers: {read_only: {host: 'replica_server'}})
40
40
 
41
41
  This will use the replica_server for SELECT queries and primary_server for
42
- other queries.
42
+ other queries. The :read_only key in the :servers hash is special in that
43
+ it sets the default database for Dataset methods that use SELECT queries
44
+ (which are generally read queries that do not modify the database).
43
45
 
44
46
  If you want to ensure your queries are going to a specific database, you
45
47
  can force this for a given query by using the .server method and passing
@@ -29,6 +29,21 @@ module Sequel
29
29
  end
30
30
  MYSQL_TYPES.freeze
31
31
 
32
+ RUBY_MYSQL_3 = !Mysql.respond_to?(:init)
33
+ RUBY_MYSQL_4 = RUBY_MYSQL_3 && ::Mysql::VERSION.to_i >= 4
34
+
35
+ if RUBY_MYSQL_3
36
+ class Adapter < ::Mysql
37
+ alias real_connect connect
38
+ alias use_result store_result
39
+ if RUBY_MYSQL_4
40
+ def initialize(**opts)
41
+ super(**opts.merge(:cast=>false))
42
+ end
43
+ end
44
+ end
45
+ end
46
+
32
47
  class Database < Sequel::Database
33
48
  include Sequel::MySQL::DatabaseMethods
34
49
  include Sequel::MySQL::MysqlMysql2::DatabaseMethods
@@ -72,7 +87,7 @@ module Sequel
72
87
  def connect(server)
73
88
  opts = server_opts(server)
74
89
 
75
- if Mysql.respond_to?(:init)
90
+ if !RUBY_MYSQL_3
76
91
  conn = Mysql.init
77
92
  conn.options(Mysql::READ_DEFAULT_GROUP, opts[:config_default_group] || "client")
78
93
  conn.options(Mysql::OPT_LOCAL_INFILE, opts[:config_local_infile]) if opts.has_key?(:config_local_infile)
@@ -88,8 +103,8 @@ module Sequel
88
103
  conn.options(Mysql::OPT_CONNECT_TIMEOUT, connect_timeout)
89
104
  end
90
105
  else
91
- # ruby-mysql 3 API
92
- conn = Mysql.new
106
+ # ruby-mysql 3+ API
107
+ conn = Adapter.new
93
108
  # no support for default group
94
109
  conn.local_infile = opts[:config_local_infile] if opts.has_key?(:config_local_infile)
95
110
  if encoding = opts[:encoding] || opts[:charset]
@@ -101,10 +116,7 @@ module Sequel
101
116
  if connect_timeout = opts[:connect_timeout]
102
117
  conn.connect_timeout = connect_timeout
103
118
  end
104
- conn.singleton_class.class_eval do
105
- alias real_connect connect
106
- alias use_result store_result
107
- end
119
+ opts[:compress] = false
108
120
  end
109
121
 
110
122
  conn.ssl_set(opts[:sslkey], opts[:sslcert], opts[:sslca], opts[:sslcapath], opts[:sslcipher]) if opts[:sslca] || opts[:sslkey]
@@ -1007,11 +1007,15 @@ module Sequel
1007
1007
  SQL::Function.new(:format_type, pg_type[:oid], pg_attribute[:atttypmod]).as(:db_type),
1008
1008
  SQL::Function.new(:pg_get_expr, pg_attrdef[:adbin], pg_class[:oid]).as(:default),
1009
1009
  SQL::BooleanExpression.new(:NOT, pg_attribute[:attnotnull]).as(:allow_null),
1010
- SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(pg_attribute[:attnum] => SQL::Function.new(:ANY, pg_index[:indkey])), false).as(:primary_key)]}.
1010
+ SQL::Function.new(:COALESCE, SQL::BooleanExpression.from_value_pairs(pg_attribute[:attnum] => SQL::Function.new(:ANY, pg_index[:indkey])), false).as(:primary_key),
1011
+ Sequel[:pg_type][:typtype],
1012
+ (~Sequel[Sequel[:elementtype][:oid]=>nil]).as(:is_array),
1013
+ ]}.
1011
1014
  from(:pg_class).
1012
1015
  join(:pg_attribute, :attrelid=>:oid).
1013
1016
  join(:pg_type, :oid=>:atttypid).
1014
1017
  left_outer_join(Sequel[:pg_type].as(:basetype), :oid=>:typbasetype).
1018
+ left_outer_join(Sequel[:pg_type].as(:elementtype), :typarray=>Sequel[:pg_type][:oid]).
1015
1019
  left_outer_join(:pg_attrdef, :adrelid=>Sequel[:pg_class][:oid], :adnum=>Sequel[:pg_attribute][:attnum]).
1016
1020
  left_outer_join(:pg_index, :indrelid=>Sequel[:pg_class][:oid], :indisprimary=>true).
1017
1021
  where{{pg_attribute[:attisdropped]=>false}}.
@@ -1538,11 +1542,12 @@ module Sequel
1538
1542
  end
1539
1543
 
1540
1544
  # SQL DDL statement for renaming a table. PostgreSQL doesn't allow you to change a table's schema in
1541
- # a rename table operation, so speciying a new schema in new_name will not have an effect.
1545
+ # a rename table operation, so specifying a new schema in new_name will not have an effect.
1542
1546
  def rename_table_sql(name, new_name)
1543
1547
  "ALTER TABLE #{quote_schema_table(name)} RENAME TO #{quote_identifier(schema_and_table(new_name).last)}"
1544
1548
  end
1545
1549
 
1550
+ # Handle interval and citext types.
1546
1551
  def schema_column_type(db_type)
1547
1552
  case db_type
1548
1553
  when /\Ainterval\z/io
@@ -1554,6 +1559,43 @@ module Sequel
1554
1559
  end
1555
1560
  end
1556
1561
 
1562
+ # The schema :type entry to use for array types.
1563
+ def schema_array_type(db_type)
1564
+ :array
1565
+ end
1566
+
1567
+ # The schema :type entry to use for row/composite types.
1568
+ def schema_composite_type(db_type)
1569
+ :composite
1570
+ end
1571
+
1572
+ # The schema :type entry to use for enum types.
1573
+ def schema_enum_type(db_type)
1574
+ :enum
1575
+ end
1576
+
1577
+ # The schema :type entry to use for range types.
1578
+ def schema_range_type(db_type)
1579
+ :range
1580
+ end
1581
+
1582
+ # The schema :type entry to use for multirange types.
1583
+ def schema_multirange_type(db_type)
1584
+ :multirange
1585
+ end
1586
+
1587
+ MIN_DATE = Date.new(-4713, 11, 24)
1588
+ MAX_DATE = Date.new(5874897, 12, 31)
1589
+ MIN_TIMESTAMP = Time.utc(-4713, 11, 24).freeze
1590
+ MAX_TIMESTAMP = (Time.utc(294277) - Rational(1, 1000000)).freeze
1591
+ TYPTYPE_METHOD_MAP = {
1592
+ 'c' => :schema_composite_type,
1593
+ 'e' => :schema_enum_type,
1594
+ 'r' => :schema_range_type,
1595
+ 'm' => :schema_multirange_type,
1596
+ }
1597
+ TYPTYPE_METHOD_MAP.default = :schema_column_type
1598
+ TYPTYPE_METHOD_MAP.freeze
1557
1599
  # The dataset used for parsing table schemas, using the pg_* system catalogs.
1558
1600
  def schema_parse_table(table_name, opts)
1559
1601
  m = output_identifier_meth(opts[:dataset])
@@ -1569,11 +1611,33 @@ module Sequel
1569
1611
  row.delete(:base_oid)
1570
1612
  row.delete(:db_base_type)
1571
1613
  end
1572
- row[:type] = schema_column_type(row[:db_type])
1614
+
1615
+ db_type = row[:db_type]
1616
+ row[:type] = if row.delete(:is_array)
1617
+ schema_array_type(db_type)
1618
+ else
1619
+ send(TYPTYPE_METHOD_MAP[row.delete(:typtype)], db_type)
1620
+ end
1573
1621
  identity = row.delete(:attidentity)
1574
1622
  if row[:primary_key]
1575
1623
  row[:auto_increment] = !!(row[:default] =~ /\A(?:nextval)/i) || identity == 'a' || identity == 'd'
1576
1624
  end
1625
+
1626
+ # :nocov:
1627
+ if server_version >= 90600
1628
+ # :nocov:
1629
+ case row[:oid]
1630
+ when 1082
1631
+ row[:min_value] = MIN_DATE
1632
+ row[:max_value] = MAX_DATE
1633
+ when 1184, 1114
1634
+ if Sequel.datetime_class == Time
1635
+ row[:min_value] = MIN_TIMESTAMP
1636
+ row[:max_value] = MAX_TIMESTAMP
1637
+ end
1638
+ end
1639
+ end
1640
+
1577
1641
  [m.call(row.delete(:name)), row]
1578
1642
  end
1579
1643
  end
@@ -0,0 +1,117 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'trilogy'
4
+ require_relative 'shared/mysql'
5
+
6
+ module Sequel
7
+ module Trilogy
8
+ class Database < Sequel::Database
9
+ include Sequel::MySQL::DatabaseMethods
10
+
11
+ QUERY_FLAGS = ::Trilogy::QUERY_FLAGS_CAST | ::Trilogy::QUERY_FLAGS_CAST_BOOLEANS
12
+ LOCAL_TIME_QUERY_FLAGS = QUERY_FLAGS | ::Trilogy::QUERY_FLAGS_LOCAL_TIMEZONE
13
+
14
+ set_adapter_scheme :trilogy
15
+
16
+ # Connect to the database. See Trilogy documentation for options.
17
+ def connect(server)
18
+ opts = server_opts(server)
19
+ opts[:username] ||= opts.delete(:user)
20
+ opts[:found_rows] = true
21
+ conn = ::Trilogy.new(opts)
22
+ mysql_connection_setting_sqls.each{|sql| log_connection_yield(sql, conn){conn.query(sql)}}
23
+ conn
24
+ end
25
+
26
+ def disconnect_connection(c)
27
+ c.discard!
28
+ rescue ::Trilogy::Error
29
+ nil
30
+ end
31
+
32
+ # Execute the given SQL on the given connection and yield the result.
33
+ def execute(sql, opts)
34
+ r = synchronize(opts[:server]) do |conn|
35
+ log_connection_yield((log_sql = opts[:log_sql]) ? sql + log_sql : sql, conn) do
36
+ conn.query_with_flags(sql, timezone.nil? || timezone == :local ? LOCAL_TIME_QUERY_FLAGS : QUERY_FLAGS)
37
+ end
38
+ end
39
+ yield r
40
+ rescue ::Trilogy::Error => e
41
+ raise_error(e)
42
+ end
43
+
44
+ def execute_dui(sql, opts=OPTS)
45
+ execute(sql, opts, &:affected_rows)
46
+ end
47
+
48
+ def execute_insert(sql, opts=OPTS)
49
+ execute(sql, opts, &:last_insert_id)
50
+ end
51
+
52
+ def freeze
53
+ server_version
54
+ super
55
+ end
56
+
57
+ # Return the version of the MySQL server to which we are connecting.
58
+ def server_version(_server=nil)
59
+ @server_version ||= super()
60
+ end
61
+
62
+ private
63
+
64
+ def database_specific_error_class(exception, opts)
65
+ case exception.message
66
+ when /1205 - Lock wait timeout exceeded; try restarting transaction\z/
67
+ DatabaseLockTimeout
68
+ else
69
+ super
70
+ end
71
+ end
72
+
73
+ def connection_execute_method
74
+ :query
75
+ end
76
+
77
+ def database_error_classes
78
+ [::Trilogy::Error]
79
+ end
80
+
81
+ def dataset_class_default
82
+ Dataset
83
+ end
84
+
85
+ # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
86
+ def schema_column_type(db_type)
87
+ db_type =~ /\Atinyint\(1\)/ ? :boolean : super
88
+ end
89
+ end
90
+
91
+ class Dataset < Sequel::Dataset
92
+ include Sequel::MySQL::DatasetMethods
93
+
94
+ def fetch_rows(sql)
95
+ execute(sql) do |r|
96
+ self.columns = r.fields.map!{|c| output_identifier(c.to_s)}
97
+ r.each_hash{|h| yield h}
98
+ end
99
+ self
100
+ end
101
+
102
+ private
103
+
104
+ def execute(sql, opts=OPTS)
105
+ opts = Hash[opts]
106
+ opts[:type] = :select
107
+ super
108
+ end
109
+
110
+ # Handle correct quoting of strings using ::Trilogy#escape.
111
+ def literal_string_append(sql, v)
112
+ sql << "'" << db.synchronize(@opts[:server]){|c| c.escape(v)} << "'"
113
+ end
114
+ end
115
+ end
116
+ end
117
+
@@ -8,7 +8,7 @@ module Sequel
8
8
  # ---------------------
9
9
 
10
10
  # Array of supported database adapters
11
- ADAPTERS = %w'ado amalgalite ibmdb jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite tinytds'.map(&:to_sym)
11
+ ADAPTERS = %w'ado amalgalite ibmdb jdbc mock mysql mysql2 odbc oracle postgres sqlanywhere sqlite tinytds trilogy'.map(&:to_sym)
12
12
 
13
13
  # The Database subclass for the given adapter scheme.
14
14
  # Raises Sequel::AdapterNotFound if the adapter
@@ -900,7 +900,7 @@ module Sequel
900
900
  #
901
901
  # Any other object given is just converted to a string, with "_" converted to " " and upcased.
902
902
  def on_delete_clause(action)
903
- action.to_s.gsub("_", " ").upcase
903
+ action.to_s.tr("_", " ").upcase
904
904
  end
905
905
 
906
906
  # Alias of #on_delete_clause, since the two usually behave the same.
@@ -257,7 +257,7 @@ module Sequel
257
257
  end
258
258
 
259
259
  # Make the column type detection handle registered array types.
260
- def schema_column_type(db_type)
260
+ def schema_array_type(db_type)
261
261
  if (db_type =~ /\A([^(]+)(?:\([^(]+\))?\[\]\z/io) && (type = pg_array_schema_type($1))
262
262
  type
263
263
  else
@@ -166,8 +166,7 @@ module Sequel
166
166
  def schema_post_process(_)
167
167
  super.each do |_, s|
168
168
  oid = s[:oid]
169
- if values = Sequel.synchronize{@enum_labels[oid]}
170
- s[:type] = :enum
169
+ if s[:type] == :enum && (values = Sequel.synchronize{@enum_labels[oid]})
171
170
  s[:enum_values] = values
172
171
  end
173
172
  end
@@ -22,7 +22,6 @@
22
22
  module Sequel
23
23
  module Postgres
24
24
  module ExtendedDateSupport
25
- DATE_YEAR_1 = Date.new(1)
26
25
  DATETIME_YEAR_1 = DateTime.new(1)
27
26
  TIME_YEAR_1 = Time.at(-62135596800).utc
28
27
  INFINITE_TIMESTAMP_STRINGS = ['infinity'.freeze, '-infinity'.freeze].freeze
@@ -38,6 +37,15 @@ module Sequel
38
37
  procs = db.conversion_procs
39
38
  procs[1082] = ::Sequel.method(:string_to_date)
40
39
  procs[1184] = procs[1114] = db.method(:to_application_timestamp)
40
+ if ocps = db.instance_variable_get(:@oid_convertor_map)
41
+ # Clear the oid convertor map entries for timestamps if they
42
+ # exist, so it will regenerate new ones that use this extension.
43
+ # This is only taken when using the jdbc adapter.
44
+ Sequel.synchronize do
45
+ ocps.delete(1184)
46
+ ocps.delete(1114)
47
+ end
48
+ end
41
49
  end
42
50
 
43
51
  # Handle BC dates and times in bound variables. This is necessary for Date values
@@ -181,7 +189,7 @@ module Sequel
181
189
 
182
190
  # Handle BC Date objects.
183
191
  def literal_date(date)
184
- if date < DATE_YEAR_1
192
+ if date.year < 1
185
193
  date <<= ((date.year) * 24 - 12)
186
194
  date.strftime("'%Y-%m-%d BC'")
187
195
  else
@@ -221,7 +221,7 @@ module Sequel
221
221
  private
222
222
 
223
223
  # Recognize the registered database multirange types.
224
- def schema_column_type(db_type)
224
+ def schema_multirange_type(db_type)
225
225
  @pg_multirange_schema_types[db_type] || super
226
226
  end
227
227
 
@@ -234,7 +234,7 @@ module Sequel
234
234
  private
235
235
 
236
236
  # Recognize the registered database range types.
237
- def schema_column_type(db_type)
237
+ def schema_range_type(db_type)
238
238
  @pg_range_schema_types[db_type] || super
239
239
  end
240
240
 
@@ -538,12 +538,8 @@ module Sequel
538
538
  private
539
539
 
540
540
  # Make the column type detection handle registered row types.
541
- def schema_column_type(db_type)
542
- if type = @row_schema_types[db_type]
543
- type
544
- else
545
- super
546
- end
541
+ def schema_composite_type(db_type)
542
+ @row_schema_types[db_type] || super
547
543
  end
548
544
  end
549
545
  end
@@ -8,6 +8,9 @@ module Sequel
8
8
  # automatically creates class methods for public dataset
9
9
  # methods.
10
10
  class DatasetModule < Dataset::DatasetModule
11
+ # The model class related to this dataset module.
12
+ attr_reader :model
13
+
11
14
  # Store the model related to this dataset module.
12
15
  def initialize(model)
13
16
  @model = model
@@ -125,14 +125,15 @@ module Sequel
125
125
  ds = @dataset.with_quote_identifiers(false)
126
126
  table_name = ds.literal(ds.first_source_table)
127
127
  reflections = {}
128
- @constraint_validations = (Sequel.synchronize{hash[table_name]} || []).map{|r| constraint_validation_array(r, reflections)}
128
+ allow_missing_columns = db_schema.select{|col, sch| sch[:allow_null] == false && nil != sch[:default]}.map(&:first)
129
+ @constraint_validations = (Sequel.synchronize{hash[table_name]} || []).map{|r| constraint_validation_array(r, reflections, allow_missing_columns)}
129
130
  @constraint_validation_reflections = reflections
130
131
  end
131
132
  end
132
133
 
133
134
  # Given a specific database constraint validation metadata row hash, transform
134
135
  # it in an validation method call array suitable for splatting to send.
135
- def constraint_validation_array(r, reflections)
136
+ def constraint_validation_array(r, reflections, allow_missing_columns=EMPTY_ARRAY)
136
137
  opts = {}
137
138
  opts[:message] = r[:message] if r[:message]
138
139
  opts[:allow_nil] = true if db.typecast_value(:boolean, r[:allow_nil])
@@ -191,11 +192,13 @@ module Sequel
191
192
  reflection_opts[:argument] = arg
192
193
  end
193
194
 
194
- a << column
195
- unless opts.empty?
196
- a << opts
195
+ opts[:from] = :values
196
+ if column.is_a?(Symbol) && allow_missing_columns.include?(column)
197
+ opts[:allow_missing] = true
197
198
  end
198
199
 
200
+ a << column << opts
201
+
199
202
  if column.is_a?(Array) && column.length == 1
200
203
  column = column.first
201
204
  end
@@ -28,7 +28,9 @@ module Sequel
28
28
  #
29
29
  # This plugin only works on the postgres adapter when using the pg 0.16+ driver,
30
30
  # PostgreSQL 9.3+ server, and PostgreSQL 9.3+ client library (libpq). In other cases
31
- # it will be a no-op.
31
+ # it will be a no-op. Additionally, the plugin only handles models that select
32
+ # from tables. It does not handle models that select from subqueries, such as
33
+ # subclasses of models using the class_table_inheritance plugin.
32
34
  #
33
35
  # Example:
34
36
  #
@@ -75,6 +75,10 @@ module Sequel
75
75
  # "#{Array(attribute).join(I18n.t('errors.joiner'))} #{error_msg}"
76
76
  # end
77
77
  # end
78
+ #
79
+ # It is recommended that users of this plugin that use validates_schema_types also use
80
+ # the validation_helpers_generic_type_messages plugin for more useful type validation
81
+ # failure messages.
78
82
  module ValidationHelpers
79
83
  DEFAULT_OPTIONS = {
80
84
  :exact_length=>{:message=>lambda{|exact| "is not #{exact} characters"}},
@@ -211,7 +215,7 @@ module Sequel
211
215
  klass = klass.to_s.constantize if klass.is_a?(String) || klass.is_a?(Symbol)
212
216
  validatable_attributes_for_type(:type, atts, opts) do |a,v,m|
213
217
  if klass.is_a?(Array) ? !klass.any?{|kls| v.is_a?(kls)} : !v.is_a?(klass)
214
- validation_error_message(m, klass)
218
+ validates_type_error_message(m, klass)
215
219
  end
216
220
  end
217
221
  end
@@ -338,6 +342,9 @@ module Sequel
338
342
  def validation_error_message(message, *args)
339
343
  message.is_a?(Proc) ? message.call(*args) : message
340
344
  end
345
+
346
+ # The validation error message for type validations, for the given class.
347
+ alias validates_type_error_message validation_error_message
341
348
  end
342
349
  end
343
350
  end
@@ -0,0 +1,73 @@
1
+ # frozen-string-literal: true
2
+
3
+ require_relative 'validation_helpers'
4
+
5
+ module Sequel
6
+ module Plugins
7
+ # The validation_helpers_generic_type_messages plugin overrides the default
8
+ # type validation failure messages in the validation_helpers plugin to be
9
+ # more generic and understandable by the average user, instead of always
10
+ # be based on the names of the allowed classes for the type. For example:
11
+ #
12
+ # # :blob type
13
+ # # validation_helpers default: "value is not a valid sequel::sql::blob"
14
+ # # with this plugin: "value is not a blob"
15
+ #
16
+ # # :boolean type
17
+ # # validation_helpers default: "value is not a valid trueclass or falseclass"
18
+ # # with this plugin: "value is not true or false"
19
+ #
20
+ # # :datetime type
21
+ # # validation_helpers default: "value is not a valid time or datetime"
22
+ # # with this plugin: "value is not a valid timestamp"
23
+ #
24
+ # # custom/database-specific types
25
+ # # validation_helpers default: "value is not a valid sequel::class_name"
26
+ # # with this plugin: "value is not the expected type"
27
+ #
28
+ # It is expected that this plugin will become the default behavior of
29
+ # validation_helpers in Sequel 6.
30
+ #
31
+ # To enable this the use of generic type messages for all models, load this
32
+ # plugin into Sequel::Model.
33
+ #
34
+ # Sequel::Model.plugin :validation_helpers_generic_type_messages
35
+ module ValidationHelpersGenericTypeMessages
36
+ OVERRIDE_PROC = ValidationHelpers::DEFAULT_OPTIONS[:type][:message]
37
+ private_constant :OVERRIDE_PROC
38
+
39
+ TYPE_ERROR_STRINGS = {
40
+ String => 'is not a string'.freeze,
41
+ Integer => 'is not an integer'.freeze,
42
+ Date => 'is not a valid date'.freeze,
43
+ [Time, DateTime].freeze => 'is not a valid timestamp'.freeze,
44
+ Sequel::SQLTime => 'is not a valid time'.freeze,
45
+ [TrueClass, FalseClass].freeze => 'is not true or false'.freeze,
46
+ Float => 'is not a number'.freeze,
47
+ BigDecimal => 'is not a number'.freeze,
48
+ Sequel::SQL::Blob => 'is not a blob'.freeze,
49
+ }
50
+ TYPE_ERROR_STRINGS.default = "is not the expected type".freeze
51
+ TYPE_ERROR_STRINGS.freeze
52
+ private_constant :TYPE_ERROR_STRINGS
53
+
54
+ def self.apply(mod)
55
+ mod.plugin :validation_helpers
56
+ end
57
+
58
+ module InstanceMethods
59
+ private
60
+
61
+ # Use a generic error message for type validations.
62
+ def validates_type_error_message(m, klass)
63
+ # SEQUEL6: Make this the default behavior in validation_helpers
64
+ if OVERRIDE_PROC.equal?(m)
65
+ TYPE_ERROR_STRINGS[klass]
66
+ else
67
+ super
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -6,7 +6,7 @@ module Sequel
6
6
 
7
7
  # The minor version of Sequel. Bumped for every non-patch level
8
8
  # release, generally around once a month.
9
- MINOR = 67
9
+ MINOR = 69
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.67.0
4
+ version: 5.69.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-01 00:00:00.000000000 Z
11
+ date: 2023-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -199,6 +199,8 @@ extra_rdoc_files:
199
199
  - doc/release_notes/5.65.0.txt
200
200
  - doc/release_notes/5.66.0.txt
201
201
  - doc/release_notes/5.67.0.txt
202
+ - doc/release_notes/5.68.0.txt
203
+ - doc/release_notes/5.69.0.txt
202
204
  - doc/release_notes/5.7.0.txt
203
205
  - doc/release_notes/5.8.0.txt
204
206
  - doc/release_notes/5.9.0.txt
@@ -294,6 +296,8 @@ files:
294
296
  - doc/release_notes/5.65.0.txt
295
297
  - doc/release_notes/5.66.0.txt
296
298
  - doc/release_notes/5.67.0.txt
299
+ - doc/release_notes/5.68.0.txt
300
+ - doc/release_notes/5.69.0.txt
297
301
  - doc/release_notes/5.7.0.txt
298
302
  - doc/release_notes/5.8.0.txt
299
303
  - doc/release_notes/5.9.0.txt
@@ -347,6 +351,7 @@ files:
347
351
  - lib/sequel/adapters/sqlanywhere.rb
348
352
  - lib/sequel/adapters/sqlite.rb
349
353
  - lib/sequel/adapters/tinytds.rb
354
+ - lib/sequel/adapters/trilogy.rb
350
355
  - lib/sequel/adapters/utils/columns_limit_1.rb
351
356
  - lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb
352
357
  - lib/sequel/adapters/utils/emulate_offset_with_row_number.rb
@@ -583,6 +588,7 @@ files:
583
588
  - lib/sequel/plugins/validation_class_methods.rb
584
589
  - lib/sequel/plugins/validation_contexts.rb
585
590
  - lib/sequel/plugins/validation_helpers.rb
591
+ - lib/sequel/plugins/validation_helpers_generic_type_messages.rb
586
592
  - lib/sequel/plugins/whitelist_security.rb
587
593
  - lib/sequel/plugins/xml_serializer.rb
588
594
  - lib/sequel/sql.rb