sequel 5.38.0 → 5.39.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: 0f1a5546546a02086c315afdb93e50fb2df1f12ee665f048cd36589bff6da6cd
4
- data.tar.gz: f42f5a4ec65f1ed13de8f01f8091673688346be075fee60507adc13473e8528f
3
+ metadata.gz: b995589f8bb51611b490ae4cd1d84c2ecfbb5889cb4f940dd786a841fe9ecf9f
4
+ data.tar.gz: afa86ae9dfc39cd21138aff35955fb4194c359a1ea56c9a80026f04b85b79a4a
5
5
  SHA512:
6
- metadata.gz: 5838cb5c5a9b24ba5646967a88bc4d487b99e760f8112ab455f0fb19dcfbd63cf884e1032bc31055eaeb0d1a89ab7d61b0865f89bfa35587b13ef4060fc8348c
7
- data.tar.gz: d113cbddf7ccc677e0b43dd919fccdf3461d3f2157374b37cf89cfb1ce5f3156d43aab2bfcd9498ff99500bcd5fcd350fb8424894141a02cd648be128f36d0fc
6
+ metadata.gz: 553d5c2b92a49d079503c9e8e0f8dfecef1a4abf2ed2fe242c8aec19d53c918912de4f5d1453626a05c1b654c5582c508199df10aa7540ec590331b3ecb355da
7
+ data.tar.gz: f0fc7bceadccc74651573f82ed957ab91061ecb05f5f30050d0814a0142b915a79175d146b3bcac6f7269cd4f3b3b69eb58a92a4df439a944c081b45f1deaa2c
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ === 5.39.0 (2020-12-01)
2
+
3
+ * Support :clustered option for primary key and unique constraints on Microsoft SQL Server (jeremyevans)
4
+
5
+ * Do not modify the size of binary columns when using set_column_allow_null on Microsoft SQL Server (jeremyevans) (#1736)
6
+
7
+ * Add a fork safety guide with more detail on how to use Sequel with libraries that fork (janko) (#1733)
8
+
9
+ * Make the roots_dataset method in the tree plugin work with queries using joins (jeremyevans) (#1731)
10
+
11
+ * Make Database#tables return partitioned tables on PostgreSQL 10+ (epoberezhny) (#1729, #1730)
12
+
1
13
  === 5.38.0 (2020-11-01)
2
14
 
3
15
  * Do not add new Database instances to Sequel::DATABASES if the test connection fails (jeremyevans) (#1727)
@@ -883,7 +883,7 @@ raise an error by default:
883
883
  == Sequel Release Policy
884
884
 
885
885
  New major versions of Sequel do not have a defined release policy, but historically have
886
- occurred once ever few years.
886
+ occurred once every few years.
887
887
 
888
888
  New minor versions of Sequel are released around once a month near the start of the month.
889
889
 
@@ -95,18 +95,18 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
95
95
 
96
96
  === AND/OR/NOT
97
97
 
98
- DB[:items].where{(x > 5) & (y > 10)}.sql
98
+ DB[:items].where{(x > 5) & (y > 10)}
99
99
  # SELECT * FROM items WHERE ((x > 5) AND (y > 10))
100
100
 
101
- DB[:items].where(Sequel.or(x: 1, y: 2) & Sequel.~(z: 3)).sql
101
+ DB[:items].where(Sequel.or(x: 1, y: 2) & Sequel.~(z: 3))
102
102
  # SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))
103
103
 
104
104
  === Mathematical operators
105
105
 
106
- DB[:items].where{x + y > z}.sql
106
+ DB[:items].where{x + y > z}
107
107
  # SELECT * FROM items WHERE ((x + y) > z)
108
108
 
109
- DB[:items].where{price - 100 < avg(price)}.sql
109
+ DB[:items].where{price - 100 < avg(price)}
110
110
  # SELECT * FROM items WHERE ((price - 100) < avg(price))
111
111
 
112
112
  === Raw SQL Fragments
@@ -130,7 +130,7 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
130
130
 
131
131
  == Joins
132
132
 
133
- DB[:items].left_outer_join(:categories, id: :category_id).sql
133
+ DB[:items].left_outer_join(:categories, id: :category_id)
134
134
  # SELECT * FROM items
135
135
  # LEFT OUTER JOIN categories ON categories.id = items.category_id
136
136
 
@@ -100,15 +100,3 @@ and freezing them can easily be achieved through the plugin:
100
100
  # ... setup models
101
101
  # Now finalize associations & freeze models by calling the plugin:
102
102
  Sequel::Model.freeze_descendents
103
-
104
- == Disconnect If Using Forking Webserver with Code Preloading
105
-
106
- If you are using a forking webserver such as unicorn or passenger, with
107
- a feature that loads your Sequel code before forking connections (code
108
- preloading), then you must disconnect your database connections before
109
- forking. If you don't do this, you can end up with child processes
110
- sharing database connections and all sorts of weird behavior. Sequel
111
- will automatically reconnect on an as needed basis in the child
112
- processes, so you only need to do the following in the parent process:
113
-
114
- DB.disconnect
@@ -0,0 +1,84 @@
1
+ = Fork Safety
2
+
3
+ If you are forking or using a library that forks after you have created a
4
+ Sequel::Database instance, then you must disconnect database connections before forking. If you
5
+ don't do this, you can end up with child processes sharing database connections
6
+ and all sorts of weird behavior, including crashes. Sequel will automatically create new
7
+ connections on an as needed basis in the child processes, so you only need to do the following in
8
+ the parent process:
9
+
10
+ DB.disconnect
11
+
12
+ Or if you have connections to multiple databases:
13
+
14
+ Sequel::DATABASES.each(&:disconnect)
15
+
16
+ == Puma
17
+
18
+ When using the Puma web server in clustered mode (which is the default behavior in Puma 5+ when
19
+ using multiple processes), you should disconnect inside the +before_fork+ hook in your
20
+ Puma config:
21
+
22
+ before_fork do
23
+ Sequel::DATABASES.each(&:disconnect)
24
+ end
25
+
26
+ == Unicorn
27
+
28
+ When using the Unicorn web server and preloading the application (+preload_app true+ in the Unicorn
29
+ config), you should disconnect inside the +before_fork+ hook in the Unicorn config:
30
+
31
+ before_fork do
32
+ Sequel::DATABASES.each(&:disconnect)
33
+ end
34
+
35
+ == Passenger
36
+
37
+ In Passenger web server, you should disconnect inside the
38
+ +starting_worker_process+ event hook:
39
+
40
+ if defined?(PhusionPassenger)
41
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
42
+ Sequel::DATABASES.each(&:disconnect) if forked
43
+ end
44
+ end
45
+
46
+ Note that this disconnects after forking instead of before forking. Passenger does not
47
+ offer a before fork hook.
48
+
49
+ == Spring
50
+
51
+ In Spring application preloader, you should disconnect inside the +after_fork+ hook:
52
+
53
+ if defined?(Spring)
54
+ Spring.after_fork do
55
+ Sequel::DATABASES.each(&:disconnect)
56
+ end
57
+ end
58
+
59
+ As the method indicates, this disconnects after forking instead of before forking.
60
+ Spring does not offer a before fork hook.
61
+
62
+ == Resque
63
+
64
+ In Resque, you should disconnect inside the +before_fork+ hook:
65
+
66
+ Resque.before_fork do |job|
67
+ Sequel::DATABASES.each(&:disconnect)
68
+ end
69
+
70
+ == Parallel
71
+
72
+ If you're using the Parallel gem with processes, you should disconnect before
73
+ calling it:
74
+
75
+ Sequel::DATABASES.each(&:disconnect)
76
+ Parallel.map(['a','b','c'], in_processes: 3) { |one_letter| }
77
+
78
+ == Other Libraries Calling fork
79
+
80
+ For any other library that calls fork, you should disconnect before calling
81
+ a method that forks:
82
+
83
+ Sequel::DATABASES.each(&:disconnect)
84
+ SomeLibrary.method_that_forks
@@ -213,7 +213,7 @@ other tables. Support may be added in the future.
213
213
  === Creating Unlogged Tables
214
214
 
215
215
  PostgreSQL allows users to create unlogged tables, which are faster but not crash safe. Sequel
216
- allows you do create an unlogged table by specifying the <tt>unlogged: true</tt> option to +create_table+:
216
+ allows you to create an unlogged table by specifying the <tt>unlogged: true</tt> option to +create_table+:
217
217
 
218
218
  DB.create_table(:table, unlogged: true){Integer :i}
219
219
  # CREATE UNLOGGED TABLE "table" ("i" integer)
@@ -746,7 +746,7 @@ shortcuts for all common (and most uncommon) join types. For example
746
746
 
747
747
  Album.join(:artists, id: :artist_id)
748
748
  # SELECT * FROM albums
749
- # INNER JOIN artists ON (artists.id = albums.artist_id))))
749
+ # INNER JOIN artists ON (artists.id = albums.artist_id)
750
750
 
751
751
  And +left_join+ does a LEFT JOIN:
752
752
 
@@ -870,14 +870,14 @@ In this case, you don't even need to specify any conditions.
870
870
  ==== Join Blocks
871
871
 
872
872
  You can provide a block to any of the join methods that accept
873
- conditions. This block should accept 3 arguments, the table alias
873
+ conditions. This block should accept 3 arguments: the table alias
874
874
  for the table currently being joined, the table alias for the last
875
875
  table joined (or first table), and an array of previous
876
876
  <tt>Sequel::SQL::JoinClause</tt>s.
877
877
 
878
878
  This allows you to qualify columns similar to how the implicit
879
879
  qualification works, without worrying about the specific aliases
880
- being used. For example, lets say you wanted to join the albums
880
+ being used. For example, let's say you wanted to join the albums
881
881
  and artists tables, but only want albums where the artist's name
882
882
  comes before the album's name.
883
883
 
@@ -0,0 +1,19 @@
1
+ = New Features
2
+
3
+ * On Microsoft SQL Server, the :clustered option is now supported
4
+ for primary key and unique constraints. You can use a true value
5
+ for CLUSTERED and a false value for NONCLUSTERED.
6
+
7
+ = Other Improvements
8
+
9
+ * Partitioned tables are now included in the result of
10
+ Database#tables on PostgreSQL.
11
+
12
+ * alter_table set_column_allow_null no longer drops the size of
13
+ binary columns on Microsoft SQL Server.
14
+
15
+ * In the tree plugin, the roots_dataset method now works correctly
16
+ with queries using joins by qualifying the parent column.
17
+
18
+ * A fork safety guide has been added, discussing fork safety issues
19
+ when using Sequel.
@@ -244,6 +244,16 @@ module Sequel
244
244
 
245
245
  private
246
246
 
247
+ # Add CLUSTERED or NONCLUSTERED as needed
248
+ def add_clustered_sql_fragment(sql, opts)
249
+ clustered = opts[:clustered]
250
+ unless clustered.nil?
251
+ sql += " #{'NON' unless clustered}CLUSTERED"
252
+ end
253
+
254
+ sql
255
+ end
256
+
247
257
  # Add dropping of the default constraint to the list of SQL queries.
248
258
  # This is necessary before dropping the column or changing its type.
249
259
  def add_drop_default_constraint_sql(sqls, table, column)
@@ -284,7 +294,7 @@ module Sequel
284
294
  when :set_column_null
285
295
  sch = schema(table).find{|k,v| k.to_s == op[:name].to_s}.last
286
296
  type = sch[:db_type]
287
- if [:string, :decimal].include?(sch[:type]) && !["text", "ntext"].include?(type) && (size = (sch[:max_chars] || sch[:column_size]))
297
+ if [:string, :decimal, :blob].include?(sch[:type]) && !["text", "ntext"].include?(type) && (size = (sch[:max_chars] || sch[:column_size]))
288
298
  size = "MAX" if size == -1
289
299
  type += "(#{size}#{", #{sch[:scale]}" if sch[:scale] && sch[:scale].to_i > 0})"
290
300
  end
@@ -396,6 +406,11 @@ module Sequel
396
406
  super.with_quote_identifiers(true)
397
407
  end
398
408
 
409
+ # Handle clustered and nonclustered primary keys
410
+ def primary_key_constraint_sql_fragment(opts)
411
+ add_clustered_sql_fragment(super, opts)
412
+ end
413
+
399
414
  # Use sp_rename to rename the table
400
415
  def rename_table_sql(name, new_name)
401
416
  "sp_rename #{literal(quote_schema_table(name))}, #{quote_identifier(schema_and_table(new_name).pop)}"
@@ -492,6 +507,11 @@ module Sequel
492
507
  :'varbinary(max)'
493
508
  end
494
509
 
510
+ # Handle clustered and nonclustered unique constraints
511
+ def unique_constraint_sql_fragment(opts)
512
+ add_clustered_sql_fragment(super, opts)
513
+ end
514
+
495
515
  # MSSQL supports views with check option, but not local.
496
516
  def view_with_check_option_support
497
517
  true
@@ -846,7 +846,7 @@ module Sequel
846
846
  # :schema :: The schema to search
847
847
  # :server :: The server to use
848
848
  def tables(opts=OPTS, &block)
849
- pg_class_relname('r', opts, &block)
849
+ pg_class_relname(['r', 'p'], opts, &block)
850
850
  end
851
851
 
852
852
  # Check whether the given type name string/symbol (e.g. :hstore) is supported by
@@ -143,8 +143,14 @@ module Sequel
143
143
  # :identity :: Create an identity column.
144
144
  #
145
145
  # MySQL specific options:
146
+ #
146
147
  # :generated_type :: Set the type of column when using :generated_always_as,
147
148
  # should be :virtual or :stored to force a type.
149
+ #
150
+ # Microsoft SQL Server specific options:
151
+ #
152
+ # :clustered :: When using :primary_key or :unique, marks the primary key or unique
153
+ # constraint as CLUSTERED (if true), or NONCLUSTERED (if false).
148
154
  def column(name, type, opts = OPTS)
149
155
  columns << {:name => name, :type => type}.merge!(opts)
150
156
  if index_opts = opts[:index]
@@ -580,14 +580,14 @@ module Sequel
580
580
  sql << ' NULL'
581
581
  end
582
582
  end
583
-
583
+
584
584
  # Add primary key SQL fragment to column creation SQL.
585
585
  def column_definition_primary_key_sql(sql, column)
586
586
  if column[:primary_key]
587
587
  if name = column[:primary_key_constraint_name]
588
588
  sql << " CONSTRAINT #{quote_identifier(name)}"
589
589
  end
590
- sql << ' PRIMARY KEY'
590
+ sql << " " << primary_key_constraint_sql_fragment(column)
591
591
  constraint_deferrable_sql_append(sql, column[:primary_key_deferrable])
592
592
  end
593
593
  end
@@ -608,7 +608,7 @@ module Sequel
608
608
  if name = column[:unique_constraint_name]
609
609
  sql << " CONSTRAINT #{quote_identifier(name)}"
610
610
  end
611
- sql << ' UNIQUE'
611
+ sql << ' ' << unique_constraint_sql_fragment(column)
612
612
  constraint_deferrable_sql_append(sql, column[:unique_deferrable])
613
613
  end
614
614
  end
@@ -656,11 +656,11 @@ module Sequel
656
656
  check = "(#{check})" unless check[0..0] == '(' && check[-1..-1] == ')'
657
657
  sql << "CHECK #{check}"
658
658
  when :primary_key
659
- sql << "PRIMARY KEY #{literal(constraint[:columns])}"
659
+ sql << "#{primary_key_constraint_sql_fragment(constraint)} #{literal(constraint[:columns])}"
660
660
  when :foreign_key
661
661
  sql << column_references_table_constraint_sql(constraint.merge(:deferrable=>nil))
662
662
  when :unique
663
- sql << "UNIQUE #{literal(constraint[:columns])}"
663
+ sql << "#{unique_constraint_sql_fragment(constraint)} #{literal(constraint[:columns])}"
664
664
  else
665
665
  raise Error, "Invalid constraint type #{constraint[:type]}, should be :check, :primary_key, :foreign_key, or :unique"
666
666
  end
@@ -892,6 +892,11 @@ module Sequel
892
892
  on_delete_clause(action)
893
893
  end
894
894
 
895
+ # Add fragment for primary key specification, separated for easier overridding.
896
+ def primary_key_constraint_sql_fragment(_)
897
+ 'PRIMARY KEY'
898
+ end
899
+
895
900
  # Proxy the quote_schema_table method to the dataset
896
901
  def quote_schema_table(table)
897
902
  schema_utility_dataset.quote_schema_table(table)
@@ -1047,6 +1052,11 @@ module Sequel
1047
1052
  "#{type}#{literal(Array(elements)) if elements}#{' UNSIGNED' if column[:unsigned]}"
1048
1053
  end
1049
1054
 
1055
+ # Add fragment for unique specification, separated for easier overridding.
1056
+ def unique_constraint_sql_fragment(_)
1057
+ 'UNIQUE'
1058
+ end
1059
+
1050
1060
  # Whether clob should be used for String text: true columns.
1051
1061
  def uses_clob_for_text?
1052
1062
  false
@@ -82,7 +82,7 @@ module Sequel
82
82
  # :server :: The server/shard the transaction is being executed on.
83
83
  def rollback_on_exit(opts=OPTS)
84
84
  synchronize(opts[:server]) do |conn|
85
- raise Error, "Cannot call Sequel:: Database#rollback_on_exit! unless inside a transaction" unless h = _trans(conn)
85
+ raise Error, "Cannot call Sequel:: Database#rollback_on_exit unless inside a transaction" unless h = _trans(conn)
86
86
  rollback = !opts[:cancel]
87
87
 
88
88
  if supports_savepoints?
@@ -251,6 +251,8 @@ module Sequel
251
251
  super
252
252
  end
253
253
 
254
+ private
255
+
254
256
  # Don't allow use of prepared statements.
255
257
  def use_prepared_statements_for?(type)
256
258
  false
@@ -45,6 +45,7 @@ module Sequel
45
45
 
46
46
  model.instance_exec do
47
47
  @parent_column = opts[:key]
48
+ @qualified_parent_column = Sequel.deep_qualify(table_name, opts[:key])
48
49
  @tree_order = opts[:order]
49
50
  @parent_association_name = parent
50
51
  @children_association_name = children
@@ -59,17 +60,21 @@ module Sequel
59
60
  # The column symbol or array of column symbols on which to order the tree.
60
61
  attr_accessor :tree_order
61
62
 
62
- # The symbol for the column containing the value pointing to the
63
- # parent of the leaf.
63
+ # The symbol or array of symbols for the column containing the value pointing to the
64
+ # parent of the node.
64
65
  attr_accessor :parent_column
65
66
 
67
+ # The qualified identifier or array of qualified identifiers for the column
68
+ # containing the value pointing to the parent of the node.
69
+ attr_accessor :qualified_parent_column
70
+
66
71
  # The association name for the parent association
67
72
  attr_reader :parent_association_name
68
73
 
69
74
  # The association name for the children association
70
75
  attr_reader :children_association_name
71
76
 
72
- Plugins.inherited_instance_variables(self, :@parent_column=>nil, :@tree_order=>nil, :@parent_association_name=>nil, :@children_association_name=>nil)
77
+ Plugins.inherited_instance_variables(self, :@parent_column=>nil, :@qualified_parent_column=>nil, :@tree_order=>nil, :@parent_association_name=>nil, :@children_association_name=>nil)
73
78
  Plugins.def_dataset_methods(self, [:roots, :roots_dataset])
74
79
 
75
80
  # Should freeze tree order if it is an array when freezing the model class.
@@ -151,7 +156,7 @@ module Sequel
151
156
  #
152
157
  # TreeClass.roots_dataset # => Sequel::Dataset instance
153
158
  def roots_dataset
154
- ds = where(Sequel.or(Array(model.parent_column).zip([])))
159
+ ds = where(Sequel.or(Array(model.qualified_parent_column).zip([])))
155
160
  ds = ds.order(*model.tree_order) if model.tree_order
156
161
  ds
157
162
  end
@@ -10,9 +10,14 @@ module Sequel
10
10
  Timezones = SequelMethods
11
11
  Deprecation.deprecate_constant(self, :Timezones)
12
12
 
13
- # Sequel doesn't pay much attention to timezones by default, but you can set it
14
- # handle timezones if you want. There are three separate timezone settings, application_timezone,
15
- # database_timezone, and typecast_timezone. All three timezones have getter and setter methods.
13
+ # Sequel doesn't pay much attention to timezones by default, but you can set it to
14
+ # handle timezones if you want. There are three separate timezone settings:
15
+ #
16
+ # * application_timezone
17
+ # * database_timezone
18
+ # * typecast_timezone
19
+ #
20
+ # All three timezones have getter and setter methods.
16
21
  # You can set all three timezones to the same value at once via <tt>Sequel.default_timezone=</tt>.
17
22
  #
18
23
  # The only timezone values that are supported by default are <tt>:utc</tt> (convert to UTC),
@@ -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 = 38
9
+ MINOR = 39
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.38.0
4
+ version: 5.39.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: 2020-11-01 00:00:00.000000000 Z
11
+ date: 2020-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -147,6 +147,7 @@ extra_rdoc_files:
147
147
  - doc/testing.rdoc
148
148
  - doc/validations.rdoc
149
149
  - doc/transactions.rdoc
150
+ - doc/fork_safety.rdoc
150
151
  - doc/release_notes/5.5.0.txt
151
152
  - doc/release_notes/5.6.0.txt
152
153
  - doc/release_notes/5.0.0.txt
@@ -186,6 +187,7 @@ extra_rdoc_files:
186
187
  - doc/release_notes/5.36.0.txt
187
188
  - doc/release_notes/5.37.0.txt
188
189
  - doc/release_notes/5.38.0.txt
190
+ - doc/release_notes/5.39.0.txt
189
191
  files:
190
192
  - CHANGELOG
191
193
  - MIT-LICENSE
@@ -200,6 +202,7 @@ files:
200
202
  - doc/dataset_basics.rdoc
201
203
  - doc/dataset_filtering.rdoc
202
204
  - doc/extensions.rdoc
205
+ - doc/fork_safety.rdoc
203
206
  - doc/mass_assignment.rdoc
204
207
  - doc/migration.rdoc
205
208
  - doc/model_dataset_method_design.rdoc
@@ -245,6 +248,7 @@ files:
245
248
  - doc/release_notes/5.36.0.txt
246
249
  - doc/release_notes/5.37.0.txt
247
250
  - doc/release_notes/5.38.0.txt
251
+ - doc/release_notes/5.39.0.txt
248
252
  - doc/release_notes/5.4.0.txt
249
253
  - doc/release_notes/5.5.0.txt
250
254
  - doc/release_notes/5.6.0.txt