sequel 5.82.0 → 5.83.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f09a139a164322e0a0e52e9a58c79b2f463972363509c41bf50e7082c1f542b7
4
- data.tar.gz: e7222b81a79111b9853565160f81cb18c72b341f18bec839046c9b49a4b199ea
3
+ metadata.gz: 892c809f3a378e80b21c29cc1c7f95f4a9fd0b47621a10d314b6177641f1ed4b
4
+ data.tar.gz: be68a7d44ecd5af4e7d7d67484ea6fc200e663b8649c250fcfc4be11de9f4c3d
5
5
  SHA512:
6
- metadata.gz: d9f16395ad855ccbc4494bd2e1436b6b78f15ddbfd1c9b80d356040d99415a46a352f50042b2fc9ab23d29b65567dafec2fceb35c709498159b00a1402991ee6
7
- data.tar.gz: a5693c2f3c3791c0216a5af9e933edaa41b0eeb030a3523e52a6951c666e720d0b12ec48ae3f46777ce617b27857f6519d7ce98ec1768a0c8226c4b494e501c1
6
+ metadata.gz: ac626e338969ddf7e99b554070b7383e3ce2e712ca2033b1c65dc2181c36636740a4e1858fa6cdb6bede1493a93aeac8299bbc26acfb2ed515a654a2957de7e4
7
+ data.tar.gz: 660dc4b4bded4eb08e357d92f093be43ac8613e62f1a8a693d1c6d81b64ddec3081147303ac10cd9153f8d62d2ce3459d8fd871412156fd5342c325ca654371c
data/CHANGELOG CHANGED
@@ -1,3 +1,23 @@
1
+ === 5.83.1 (2024-08-08)
2
+
3
+ * Restore unescaping of database file paths in the sqlite and amalgalite adapters (jeremyevans) (#2201)
4
+
5
+ === 5.83.0 (2024-08-01)
6
+
7
+ * Make optimistic_locking plugin not keep lock column in changed_columns after updating instance (jeremyevans) (#2196)
8
+
9
+ * Have defaults_setter plugin pass model instance to default_values callable if it has arity 1 (pedrocarmona) (#2195)
10
+
11
+ * Support string_agg extension on SQLite 3.44+ (segiddins) (#2191)
12
+
13
+ * Support schema-qualified table names when using create_table :temp with a Sequel::SQL::QualifiedIdentifier (jeremyevans) (#2185)
14
+
15
+ * Support MERGE WHEN NOT MATCHED BY SOURCE on PostgreSQL 17+ (jeremyevans)
16
+
17
+ * Add stdio_logger extension for a minimal logger that Sequel::Database can use (jeremyevans)
18
+
19
+ * Simplify Database#inspect output to database_type, host, database, and user (jeremyevans)
20
+
1
21
  === 5.82.0 (2024-07-01)
2
22
 
3
23
  * Limit tactically eager loading to objects that have the same association reflection (jeremyevans) (#2181)
data/bin/sequel CHANGED
@@ -18,21 +18,6 @@ load_dirs = []
18
18
  exclusive_options = []
19
19
  loggers = []
20
20
 
21
- logger_class = Class.new do
22
- def initialize(device)
23
- @device = device
24
- end
25
-
26
- def debug(msg)
27
- end
28
-
29
- [:info, :warn, :error].each do |meth|
30
- define_method(meth) do |msg|
31
- @device.puts("#{Time.now.strftime('%Y-%m-%d %T')} #{meth.to_s.upcase}: #{msg}")
32
- end
33
- end
34
- end
35
-
36
21
  options = OptionParser.new do |opts|
37
22
  opts.banner = "Sequel: The Database Toolkit for Ruby"
38
23
  opts.define_head "Usage: sequel [options] <uri|path> [file]"
@@ -76,7 +61,7 @@ options = OptionParser.new do |opts|
76
61
  end
77
62
 
78
63
  opts.on("-E", "--echo", "echo SQL statements") do
79
- loggers << logger_class.new($stdout)
64
+ loggers << $stdout
80
65
  end
81
66
 
82
67
  opts.on("-I", "--include dir", "specify $LOAD_PATH directory") do |v|
@@ -84,7 +69,9 @@ options = OptionParser.new do |opts|
84
69
  end
85
70
 
86
71
  opts.on("-l", "--log logfile", "log SQL statements to log file") do |v|
87
- loggers << logger_class.new(File.open(v, 'a'))
72
+ file = File.open(v, 'a')
73
+ file.sync = true
74
+ loggers << file
88
75
  end
89
76
 
90
77
  opts.on("-L", "--load-dir DIR", "loads all *.rb under specifed directory") do |v|
@@ -168,6 +155,11 @@ begin
168
155
  end
169
156
  end
170
157
 
158
+ unless loggers.empty?
159
+ Sequel.extension :stdio_logger
160
+ loggers.map!{|io| Sequel::StdioLogger.new(io)}
161
+ end
162
+
171
163
  DB = connect_proc[db]
172
164
  load_dirs.each{|d| d.is_a?(Array) ? require(d.first) : Dir["#{d}/**/*.rb"].each{|f| load(f)}}
173
165
  if migrate_dir
@@ -0,0 +1,56 @@
1
+ = New Features
2
+
3
+ * MERGE WHEN NOT MATCHED BY SOURCE is now supported when using
4
+ PostgreSQL 17+. You can use this SQL syntax via the following
5
+ Dataset methods:
6
+
7
+ * merge_delete_when_not_matched_by_source
8
+ * merge_update_when_not_matched_by_source
9
+ * merge_do_nothing_when_not_matched_by_source
10
+
11
+ These are similar to the existing merge_delete, merge_update,
12
+ and merge_do_nothing_when_matched, except they use
13
+ WHEN NOT MATCHED BY SOURCE instead of WHEN MATCHED.
14
+
15
+ * An stdio_logger extension has been added. This adds the
16
+ Sequel::StdioLogger class, which is a minimal logger implementation
17
+ that is compatible for usage with Sequel::Database. Example:
18
+
19
+ Sequel.extension :stdio_logger
20
+ DB.loggers << Sequel::StdioLogger.new($stdout)
21
+
22
+ = Other Improvements
23
+
24
+ * Database#inspect now only displays the database type, host, database
25
+ name, and user. In addition to being easier to read, this also
26
+ prevents displaying the password, enhancing security.
27
+
28
+ * The string_agg extension now supports SQLite 3.44+.
29
+
30
+ * The defaults_setter plugin now passes the model instance to a
31
+ default_values proc if the proc has arity 1. This allows default
32
+ values to depend on model instance state.
33
+
34
+ * The optimistic_locking plugin no longer adds the lock column to
35
+ changed_columns after updating the model instance.
36
+
37
+ * Database#create_temp with :temp option and an
38
+ SQL::QualifiedIdentifier table name will now attempt to create a
39
+ schema qualified table. Note that schema qualified temporary
40
+ tables are not supported by many (any?) databases, but this
41
+ change prevents the CREATE TABLE statement from succeeding with
42
+ an unexpected table name.
43
+
44
+ = Backwards Compatibility
45
+
46
+ * The Database.uri_to_options private class method now handles
47
+ conversion of URI parameters to options. Previously, this was
48
+ handled by callers of this method (change reverted in 5.83.1).
49
+
50
+ * The _merge_matched_sql and _merge_not_matched_sql private Dataset
51
+ methods in PostgreSQL have been replaced with
52
+ _merge_do_nothing_sql.
53
+
54
+ * An unnecessary space in submitted SQL has been removed when using
55
+ MERGE INSERT on PostgreSQL. This should only affect your code if
56
+ you are explicitly checking the produced SQL.
@@ -115,7 +115,7 @@ module Sequel
115
115
  # Temporary table creation on Derby uses DECLARE instead of CREATE.
116
116
  def create_table_prefix_sql(name, options)
117
117
  if options[:temp]
118
- "DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)}"
118
+ "DECLARE GLOBAL TEMPORARY TABLE #{create_table_table_name_sql(name, options)}"
119
119
  else
120
120
  super
121
121
  end
@@ -198,7 +198,7 @@ module Sequel
198
198
  # http://www.ibm.com/developerworks/data/library/techarticle/dm-0912globaltemptable/
199
199
  def create_table_prefix_sql(name, options)
200
200
  if options[:temp]
201
- "DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)}"
201
+ "DECLARE GLOBAL TEMPORARY TABLE #{create_table_table_name_sql(name, options)}"
202
202
  else
203
203
  super
204
204
  end
@@ -379,9 +379,21 @@ module Sequel
379
379
  # a regular and temporary table, with temporary table names starting with
380
380
  # a #.
381
381
  def create_table_prefix_sql(name, options)
382
- "CREATE TABLE #{quote_schema_table(options[:temp] ? "##{name}" : name)}"
382
+ "CREATE TABLE #{create_table_table_name_sql(name, options)}"
383
383
  end
384
-
384
+
385
+ # The SQL to use for the table name for a temporary table.
386
+ def create_table_temp_table_name_sql(name, _options)
387
+ case name
388
+ when String, Symbol
389
+ "##{name}"
390
+ when SQL::Identifier
391
+ "##{name.value}"
392
+ else
393
+ raise Error, "temporary table names must be strings, symbols, or Sequel::SQL::Identifier instances on Microsoft SQL Server"
394
+ end
395
+ end
396
+
385
397
  # MSSQL doesn't support CREATE TABLE AS, it only supports SELECT INTO.
386
398
  # Emulating CREATE TABLE AS using SELECT INTO is only possible if a dataset
387
399
  # is given as the argument, it can't work with a string, so raise an
@@ -1429,7 +1429,7 @@ module Sequel
1429
1429
  'UNLOGGED '
1430
1430
  end
1431
1431
 
1432
- "CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{options[:temp] ? quote_identifier(name) : quote_schema_table(name)}"
1432
+ "CREATE #{prefix_sql}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
1433
1433
  end
1434
1434
 
1435
1435
  # SQL for creating a table with PostgreSQL specific options
@@ -2068,6 +2068,19 @@ module Sequel
2068
2068
  end
2069
2069
  end
2070
2070
 
2071
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN DELETE clause added to the
2072
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2073
+ # use it as additional conditions for the match.
2074
+ #
2075
+ # merge_delete_not_matched_by_source
2076
+ # # WHEN NOT MATCHED BY SOURCE THEN DELETE
2077
+ #
2078
+ # merge_delete_not_matched_by_source{a > 30}
2079
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN DELETE
2080
+ def merge_delete_when_not_matched_by_source(&block)
2081
+ _merge_when(:type=>:delete_not_matched_by_source, &block)
2082
+ end
2083
+
2071
2084
  # Return a dataset with a WHEN MATCHED THEN DO NOTHING clause added to the
2072
2085
  # MERGE statement. If a block is passed, treat it as a virtual row and
2073
2086
  # use it as additional conditions for the match.
@@ -2094,6 +2107,19 @@ module Sequel
2094
2107
  _merge_when(:type=>:not_matched, &block)
2095
2108
  end
2096
2109
 
2110
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN DO NOTHING clause added to the
2111
+ # MERGE BY SOURCE statement. If a block is passed, treat it as a virtual row and
2112
+ # use it as additional conditions for the match.
2113
+ #
2114
+ # merge_do_nothing_when_not_matched_by_source
2115
+ # # WHEN NOT MATCHED BY SOURCE THEN DO NOTHING
2116
+ #
2117
+ # merge_do_nothing_when_not_matched_by_source{a > 30}
2118
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN DO NOTHING
2119
+ def merge_do_nothing_when_not_matched_by_source(&block)
2120
+ _merge_when(:type=>:not_matched_by_source, &block)
2121
+ end
2122
+
2097
2123
  # Support OVERRIDING USER|SYSTEM VALUE for MERGE INSERT.
2098
2124
  def merge_insert(*values, &block)
2099
2125
  h = {:type=>:insert, :values=>values}
@@ -2103,6 +2129,19 @@ module Sequel
2103
2129
  _merge_when(h, &block)
2104
2130
  end
2105
2131
 
2132
+ # Return a dataset with a WHEN NOT MATCHED BY SOURCE THEN UPDATE clause added to the
2133
+ # MERGE statement. If a block is passed, treat it as a virtual row and
2134
+ # use it as additional conditions for the match.
2135
+ #
2136
+ # merge_update_not_matched_by_source(i1: Sequel[:i1]+:i2+10, a: Sequel[:a]+:b+20)
2137
+ # # WHEN NOT MATCHED BY SOURCE THEN UPDATE SET i1 = (i1 + i2 + 10), a = (a + b + 20)
2138
+ #
2139
+ # merge_update_not_matched_by_source(i1: :i2){a > 30}
2140
+ # # WHEN NOT MATCHED BY SOURCE AND (a > 30) THEN UPDATE SET i1 = i2
2141
+ def merge_update_when_not_matched_by_source(values, &block)
2142
+ _merge_when(:type=>:update_not_matched_by_source, :values=>values, &block)
2143
+ end
2144
+
2106
2145
  # Use OVERRIDING USER VALUE for INSERT statements, so that identity columns
2107
2146
  # always use the user supplied value, and an error is not raised for identity
2108
2147
  # columns that are GENERATED ALWAYS.
@@ -2296,7 +2335,7 @@ module Sequel
2296
2335
 
2297
2336
  # Append the INSERT sql used in a MERGE
2298
2337
  def _merge_insert_sql(sql, data)
2299
- sql << " THEN INSERT "
2338
+ sql << " THEN INSERT"
2300
2339
  columns, values = _parse_insert_sql_args(data[:values])
2301
2340
  _insert_columns_sql(sql, columns)
2302
2341
  if override = data[:override]
@@ -2305,10 +2344,9 @@ module Sequel
2305
2344
  _insert_values_sql(sql, values)
2306
2345
  end
2307
2346
 
2308
- def _merge_matched_sql(sql, data)
2347
+ def _merge_do_nothing_sql(sql, data)
2309
2348
  sql << " THEN DO NOTHING"
2310
2349
  end
2311
- alias _merge_not_matched_sql _merge_matched_sql
2312
2350
 
2313
2351
  # Support MERGE RETURNING on PostgreSQL 17+.
2314
2352
  def _merge_when_sql(sql)
@@ -34,10 +34,7 @@ module Sequel
34
34
  uri = URI.parse(conn_string)
35
35
  scheme = uri.scheme
36
36
  c = adapter_class(scheme)
37
- uri_options = c.send(:uri_to_options, uri)
38
- uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
39
- uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)}
40
- opts = uri_options.merge(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
37
+ opts = c.send(:options_from_uri, uri).merge!(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
41
38
  end
42
39
  when Hash
43
40
  opts = conn_string.merge(opts)
@@ -82,6 +82,14 @@ module Sequel
82
82
  end
83
83
  private_class_method :uri_to_options
84
84
 
85
+ def self.options_from_uri(uri)
86
+ uri_options = uri_to_options(uri)
87
+ uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
88
+ uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)}
89
+ uri_options
90
+ end
91
+ private_class_method :options_from_uri
92
+
85
93
  # The options hash for this database
86
94
  attr_reader :opts
87
95
 
@@ -253,15 +261,27 @@ module Sequel
253
261
  Sequel.convert_output_timestamp(v, timezone)
254
262
  end
255
263
 
256
- # Returns a string representation of the database object including the
257
- # class name and connection URI and options used when connecting (if any).
264
+ # Returns a string representation of the Database object, including
265
+ # the database type, host, database, and user, if present.
258
266
  def inspect
259
- a = []
260
- a << uri.inspect if uri
261
- if (oo = opts[:orig_opts]) && !oo.empty?
262
- a << oo.inspect
267
+ s = String.new
268
+ s << "#<#{self.class}"
269
+ s << " database_type=#{database_type}" if database_type && database_type != adapter_scheme
270
+
271
+ keys = [:host, :database, :user]
272
+ opts = self.opts
273
+ if !keys.any?{|k| opts[k]} && opts[:uri]
274
+ opts = self.class.send(:options_from_uri, URI.parse(opts[:uri]))
275
+ end
276
+
277
+ keys.each do |key|
278
+ val = opts[key]
279
+ if val && val != ''
280
+ s << " #{key}=#{val}"
281
+ end
263
282
  end
264
- "#<#{self.class}: #{a.join(' ')}>"
283
+
284
+ s << ">"
265
285
  end
266
286
 
267
287
  # Proxy the literal call to the dataset.
@@ -775,7 +775,21 @@ module Sequel
775
775
 
776
776
  # SQL fragment for initial part of CREATE TABLE statement
777
777
  def create_table_prefix_sql(name, options)
778
- "CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{options[:temp] ? quote_identifier(name) : quote_schema_table(name)}"
778
+ "CREATE #{temporary_table_sql if options[:temp]}TABLE#{' IF NOT EXISTS' if options[:if_not_exists]} #{create_table_table_name_sql(name, options)}"
779
+ end
780
+
781
+ # The SQL to use for a table name when creating a table.
782
+ # Use of the :temp option can result in different SQL,
783
+ # because the rules for temp table naming can differ
784
+ # between databases, and temp tables should not use the
785
+ # default_schema.
786
+ def create_table_table_name_sql(name, options)
787
+ options[:temp] ? create_table_temp_table_name_sql(name, options) : quote_schema_table(name)
788
+ end
789
+
790
+ # The SQL to use for the table name for a temporary table.
791
+ def create_table_temp_table_name_sql(name, _options)
792
+ name.is_a?(String) ? quote_identifier(name) : literal(name)
779
793
  end
780
794
 
781
795
  # SQL fragment for initial part of CREATE VIEW statement
@@ -901,18 +901,31 @@ module Sequel
901
901
  MERGE_TYPE_SQL = {
902
902
  :insert => ' WHEN NOT MATCHED',
903
903
  :delete => ' WHEN MATCHED',
904
+ :delete_not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
904
905
  :update => ' WHEN MATCHED',
906
+ :update_not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
905
907
  :matched => ' WHEN MATCHED',
906
908
  :not_matched => ' WHEN NOT MATCHED',
909
+ :not_matched_by_source => ' WHEN NOT MATCHED BY SOURCE',
907
910
  }.freeze
908
911
  private_constant :MERGE_TYPE_SQL
909
912
 
913
+ MERGE_NORMALIZE_TYPE_MAP = {
914
+ :delete_not_matched_by_source => :delete,
915
+ :update_not_matched_by_source => :update,
916
+ :matched => :do_nothing,
917
+ :not_matched => :do_nothing,
918
+ :not_matched_by_source => :do_nothing,
919
+ }.freeze
920
+ private_constant :MERGE_NORMALIZE_TYPE_MAP
921
+
910
922
  # Add the WHEN clauses to the MERGE SQL
911
923
  def _merge_when_sql(sql)
912
924
  raise Error, "no WHEN [NOT] MATCHED clauses provided for MERGE" unless merge_when = @opts[:merge_when]
913
925
  merge_when.each do |data|
914
926
  type = data[:type]
915
927
  sql << MERGE_TYPE_SQL[type]
928
+ type = MERGE_NORMALIZE_TYPE_MAP[type] || type
916
929
  _merge_when_conditions_sql(sql, data)
917
930
  send(:"_merge_#{type}_sql", sql, data)
918
931
  end
@@ -0,0 +1,48 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The stdio_logger extension exposes a Sequel::StdioLogger class that
4
+ # can be used for logging with Sequel, as a minimal alternative to
5
+ # the logger library. It exposes debug/info/warn/error methods for the
6
+ # different warning levels. The debug method is a no-op, so that setting
7
+ # the Database sql_log_level to debug will result in no output for normal
8
+ # queries. The info/warn/error methods log the current time, log level,
9
+ # and the given message.
10
+ #
11
+ # To use this extension:
12
+ #
13
+ # Sequel.extension :stdio_logger
14
+ #
15
+ # Then you you can use Sequel::StdioLogger to wrap IO objects that you
16
+ # would like Sequel to log to:
17
+ #
18
+ # DB.loggers << Sequel::StdioLogger.new($stdout)
19
+ #
20
+ # log_file = File.open("db_queries.log", 'a')
21
+ # log_file.sync = true
22
+ # DB.loggers << Sequel::StdioLogger.new(log_file)
23
+ #
24
+ # This is implemented as a global extension instead of a Database extension
25
+ # because Database loggers must be set before Database extensions are loaded.
26
+ #
27
+ # Related module: Sequel::StdioLogger
28
+
29
+ #
30
+ module Sequel
31
+ class StdioLogger
32
+ def initialize(device)
33
+ @device = device
34
+ end
35
+
36
+ # Do not log debug messages. This is so setting the Database
37
+ # sql_log_level to debug will result in no output.
38
+ def debug(msg)
39
+ end
40
+
41
+ [:info, :warn, :error].each do |meth|
42
+ define_method(meth) do |msg|
43
+ @device.write("#{Time.now.strftime('%F %T')} #{meth.to_s.upcase}: #{msg}\n")
44
+ nil
45
+ end
46
+ end
47
+ end
48
+ end
@@ -54,6 +54,7 @@
54
54
  # * MySQL
55
55
  # * HSQLDB
56
56
  # * H2
57
+ # * SQLite 3.44+ (distinct only works when separator is ',')
57
58
  #
58
59
  # Related module: Sequel::SQL::StringAgg
59
60
 
@@ -94,6 +95,19 @@ module Sequel
94
95
  distinct = sa.is_distinct?
95
96
 
96
97
  case db_type = db.database_type
98
+ when :sqlite
99
+ raise Error, "string_agg(DISTINCT) is not supported with a non-comma separator on #{db.database_type}" if distinct && separator != ","
100
+
101
+ args = [expr]
102
+ args << separator unless distinct
103
+ f = Function.new(:group_concat, *args)
104
+ if order
105
+ f = f.order(*order)
106
+ end
107
+ if distinct
108
+ f = f.distinct
109
+ end
110
+ literal_append(sql, f)
97
111
  when :postgres, :sqlanywhere
98
112
  f = Function.new(db_type == :postgres ? :string_agg : :list, expr, separator)
99
113
  if order
@@ -151,7 +165,7 @@ module Sequel
151
165
  freeze
152
166
  end
153
167
 
154
- # Whether the current expression uses distinct expressions
168
+ # Whether the current expression uses distinct expressions
155
169
  def is_distinct?
156
170
  @distinct == true
157
171
  end
@@ -178,4 +192,3 @@ module Sequel
178
192
 
179
193
  Dataset.register_extension(:string_agg, SQL::StringAgg::DatasetMethods)
180
194
  end
181
-
@@ -26,6 +26,12 @@ module Sequel
26
26
  # Album.default_values[:a] = lambda{Date.today}
27
27
  # Album.new.a # => Date.today
28
28
  #
29
+ # If the proc accepts a single argument, it is passed the instance, allowing
30
+ # default values to depend on instance-specific state:
31
+ #
32
+ # Album.default_values[:a] = lambda{|album| album.b + 1}
33
+ # Album.new(b: 10).a # => 11
34
+ #
29
35
  # By default, default values returned are not cached:
30
36
  #
31
37
  # Album.new.a.equal?(Album.new.a) # => false
@@ -43,13 +49,13 @@ module Sequel
43
49
  # album.values # => {}
44
50
  # album.a
45
51
  # album.values # => {:a => Date.today}
46
- #
52
+ #
47
53
  # Usage:
48
54
  #
49
55
  # # Make all model subclass instances set defaults (called before loading subclasses)
50
56
  # Sequel::Model.plugin :defaults_setter
51
57
  #
52
- # # Make the Album class set defaults
58
+ # # Make the Album class set defaults
53
59
  # Album.plugin :defaults_setter
54
60
  module DefaultsSetter
55
61
  # Set the default values based on the model schema. Options:
@@ -76,7 +82,7 @@ module Sequel
76
82
  def cache_default_values?
77
83
  @cache_default_values
78
84
  end
79
-
85
+
80
86
  # Freeze default values when freezing model class
81
87
  def freeze
82
88
  @default_values.freeze
@@ -133,7 +139,13 @@ module Sequel
133
139
  def [](k)
134
140
  if new? && !values.has_key?(k)
135
141
  v = model.default_values.fetch(k){return}
136
- v = v.call if v.respond_to?(:call)
142
+ if v.respond_to?(:call)
143
+ v = if v.respond_to?(:arity) && v.arity == 1
144
+ v.call(self)
145
+ else
146
+ v.call
147
+ end
148
+ end
137
149
  values[k] = v if model.cache_default_values?
138
150
  v
139
151
  else
@@ -45,6 +45,8 @@ module Sequel
45
45
  columns[lc] = lcv + 1
46
46
  super
47
47
  set_column_value("#{lc}=", lcv + 1)
48
+ changed_columns.delete(lc)
49
+ nil
48
50
  end
49
51
  end
50
52
  end
@@ -6,11 +6,11 @@ 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 = 82
9
+ MINOR = 83
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
13
- TINY = 0
13
+ TINY = 1
14
14
 
15
15
  # The version of Sequel you are using, as a string (e.g. "2.11.0")
16
16
  VERSION = [MAJOR, MINOR, TINY].join('.').freeze
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.82.0
4
+ version: 5.83.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-01 00:00:00.000000000 Z
11
+ date: 2024-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -230,6 +230,7 @@ extra_rdoc_files:
230
230
  - doc/release_notes/5.80.0.txt
231
231
  - doc/release_notes/5.81.0.txt
232
232
  - doc/release_notes/5.82.0.txt
233
+ - doc/release_notes/5.83.0.txt
233
234
  - doc/release_notes/5.9.0.txt
234
235
  files:
235
236
  - CHANGELOG
@@ -340,6 +341,7 @@ files:
340
341
  - doc/release_notes/5.80.0.txt
341
342
  - doc/release_notes/5.81.0.txt
342
343
  - doc/release_notes/5.82.0.txt
344
+ - doc/release_notes/5.83.0.txt
343
345
  - doc/release_notes/5.9.0.txt
344
346
  - doc/schema_modification.rdoc
345
347
  - doc/security.rdoc
@@ -519,6 +521,7 @@ files:
519
521
  - lib/sequel/extensions/sql_expr.rb
520
522
  - lib/sequel/extensions/sql_log_normalizer.rb
521
523
  - lib/sequel/extensions/sqlite_json_ops.rb
524
+ - lib/sequel/extensions/stdio_logger.rb
522
525
  - lib/sequel/extensions/string_agg.rb
523
526
  - lib/sequel/extensions/string_date_time.rb
524
527
  - lib/sequel/extensions/symbol_aref.rb
@@ -674,7 +677,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
674
677
  - !ruby/object:Gem::Version
675
678
  version: '0'
676
679
  requirements: []
677
- rubygems_version: 3.5.9
680
+ rubygems_version: 3.5.11
678
681
  signing_key:
679
682
  specification_version: 4
680
683
  summary: The Database Toolkit for Ruby