sequel 5.82.0 → 5.83.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: f09a139a164322e0a0e52e9a58c79b2f463972363509c41bf50e7082c1f542b7
4
- data.tar.gz: e7222b81a79111b9853565160f81cb18c72b341f18bec839046c9b49a4b199ea
3
+ metadata.gz: 66956ac28806c0389a6c809b0aa70d2746a7aff47fd5b039d238c08f621cdbff
4
+ data.tar.gz: d2b8d3f88b13432c60e6164fda3577725300e18a0dfa03682871405d074d7ba0
5
5
  SHA512:
6
- metadata.gz: d9f16395ad855ccbc4494bd2e1436b6b78f15ddbfd1c9b80d356040d99415a46a352f50042b2fc9ab23d29b65567dafec2fceb35c709498159b00a1402991ee6
7
- data.tar.gz: a5693c2f3c3791c0216a5af9e933edaa41b0eeb030a3523e52a6951c666e720d0b12ec48ae3f46777ce617b27857f6519d7ce98ec1768a0c8226c4b494e501c1
6
+ metadata.gz: 55d45f7c3cb7154f275ddf5ea3649d78a38f147abdb49f1286358d8dbec9f607e3bf43c9ebe1dc31276d28820f455fc82dcce7b4c9808b325288380acf90edf4
7
+ data.tar.gz: b8301c7880dcb598ca027d225f5be791200ac1f13f4efe5351222d351b218019351a8efa1f485d499a0650cd4213ba0a148c3f10f0a67aa0b3c04f4ee611b074
data/CHANGELOG CHANGED
@@ -1,3 +1,19 @@
1
+ === 5.83.0 (2024-08-01)
2
+
3
+ * Make optimistic_locking plugin not keep lock column in changed_columns after updating instance (jeremyevans) (#2196)
4
+
5
+ * Have defaults_setter plugin pass model instance to default_values callable if it has arity 1 (pedrocarmona) (#2195)
6
+
7
+ * Support string_agg extension on SQLite 3.44+ (segiddins) (#2191)
8
+
9
+ * Support schema-qualified table names when using create_table :temp with a Sequel::SQL::QualifiedIdentifier (jeremyevans) (#2185)
10
+
11
+ * Support MERGE WHEN NOT MATCHED BY SOURCE on PostgreSQL 17+ (jeremyevans)
12
+
13
+ * Add stdio_logger extension for a minimal logger that Sequel::Database can use (jeremyevans)
14
+
15
+ * Simplify Database#inspect output to database_type, host, database, and user (jeremyevans)
16
+
1
17
  === 5.82.0 (2024-07-01)
2
18
 
3
19
  * 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.
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(:uri_to_options, 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)
@@ -72,13 +72,16 @@ module Sequel
72
72
  # Converts a uri to an options hash. These options are then passed
73
73
  # to a newly created database object.
74
74
  def self.uri_to_options(uri)
75
- {
75
+ uri_options = {
76
76
  :user => uri.user,
77
77
  :password => uri.password,
78
78
  :port => uri.port,
79
79
  :host => uri.hostname,
80
80
  :database => (m = /\/(.*)/.match(uri.path)) && (m[1])
81
81
  }
82
+ 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?
83
+ uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)}
84
+ uri_options
82
85
  end
83
86
  private_class_method :uri_to_options
84
87
 
@@ -253,15 +256,27 @@ module Sequel
253
256
  Sequel.convert_output_timestamp(v, timezone)
254
257
  end
255
258
 
256
- # Returns a string representation of the database object including the
257
- # class name and connection URI and options used when connecting (if any).
259
+ # Returns a string representation of the Database object, including
260
+ # the database type, host, database, and user, if present.
258
261
  def inspect
259
- a = []
260
- a << uri.inspect if uri
261
- if (oo = opts[:orig_opts]) && !oo.empty?
262
- a << oo.inspect
262
+ s = String.new
263
+ s << "#<#{self.class}"
264
+ s << " database_type=#{database_type}" if database_type && database_type != adapter_scheme
265
+
266
+ keys = [:host, :database, :user]
267
+ opts = self.opts
268
+ if !keys.any?{|k| opts[k]} && opts[:uri]
269
+ opts = self.class.send(:uri_to_options, URI.parse(opts[:uri]))
263
270
  end
264
- "#<#{self.class}: #{a.join(' ')}>"
271
+
272
+ keys.each do |key|
273
+ val = opts[key]
274
+ if val && val != ''
275
+ s << " #{key}=#{val}"
276
+ end
277
+ end
278
+
279
+ s << ">"
265
280
  end
266
281
 
267
282
  # 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,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 = 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.
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.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: 2024-07-01 00:00:00.000000000 Z
11
+ date: 2024-08-01 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