sequel 5.26.0 → 5.27.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: 8c7e9baac1a3a326ffdc2506dde798441b376fecbe71594cd91efb54bc56a9a7
4
- data.tar.gz: d051640fc5fb89053beaa43915eca9920222d7978be91bc704cde94f1b425532
3
+ metadata.gz: 512f72ad99402b33be776e759611a9299b638f49344fb1f349120c8cd1643107
4
+ data.tar.gz: ea0852b3ea61ef9a5a192637a2b457fe47f2374c8ee2eb20d9b02e6eb25a25ac
5
5
  SHA512:
6
- metadata.gz: 0e424392185dec97acca2092fb5b3127a6619033dd62eef683f29501ece0ecacd17ada2a2b1edf27682155c6d59633fa88a475dd1ebf4bdbf8f1641f73a566a8
7
- data.tar.gz: 8c1ac728b94de7b5f0cf9a3df230f35732906accea64a0b61b6eba90203e49396eacc95786ad7a78bc56b3b812cda8bd94d4e8f1d0be188b9d9ae4f49792a9de
6
+ metadata.gz: 4397a4a7530bd3234d7c1e3bf8b1c2b8a6845e659b86b7177dc704edf8ebf2185c499ac7ba04bb7d52006cf1367b8c0835787be1483e7bb481fa4ea2d775680b
7
+ data.tar.gz: 653238c46ae32bd74127bddb87dc4c99637f5eadfb7515a51e8da5bc57df10de57c2e9a97d085828cc45b97303fa66580c1c8832a5f6fbb5cdaffd585ce0ff86
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ === 5.27.0 (2019-12-01)
2
+
3
+ * Add Sequel::DEFAULT for a DEFAULT expression, useful for assigning to default values (jeremyevans)
4
+
5
+ * Make Postgres::ArrayOp#join in pg_array_ops extension work correctly on PostgreSQL <9.1 (jeremyevans)
6
+
7
+ * Make pg_enum extension work correctly on PostgreSQL 8.3-9.0 (jeremyevans)
8
+
9
+ * Emulate FILTER clause for aggregate functions using CASE on databases not supporting it directly (jeremyevans)
10
+
11
+ * Support ordering by NULLS FIRST/NULLS LAST without emulation on SQLite 3.30+ (jeremyevans)
12
+
1
13
  === 5.26.0 (2019-11-01)
2
14
 
3
15
  * Recognize two additional foreign key constraint violation codes on MySQL 8.0.13+ (rianmcguire) (#1657)
@@ -0,0 +1,21 @@
1
+ = New Features
2
+
3
+ * Sequel::DEFAULT has been added a constant for the DEFAULT expression,
4
+ useful in inserts and especially updates:
5
+
6
+ DB[:a].where(:id=>1).update(:b=>Sequel::DEFAULT)
7
+ # UPDATE "a" SET "b" = DEFAULT WHERE "id" = 1
8
+
9
+ * SQL::Function#filter for filtered aggregate functions is now
10
+ supported on all databases. On databases not supporting it natively
11
+ (all except PostgreSQL 9.4+ and SQLite 3.30+), a CASE statement is
12
+ used to emulate the support.
13
+
14
+ = Other Improvements
15
+
16
+ * NULLS FIRST/LAST is now used without emulation on SQLite 3.30+.
17
+
18
+ * The pg_enum extension now works correctly on PostgreSQL 8.3-9.0.
19
+
20
+ * Postgres::ArrayOp#join in the pg_array_ops extension now works
21
+ correctly on PostgreSQL <9.1.
@@ -1955,6 +1955,11 @@ module Sequel
1955
1955
  db.server_version(@opts[:server])
1956
1956
  end
1957
1957
 
1958
+ # PostgreSQL 9.4+ supports the FILTER clause for aggregate functions.
1959
+ def supports_filtered_aggregates?
1960
+ server_version >= 90400
1961
+ end
1962
+
1958
1963
  # PostgreSQL supports quoted function names.
1959
1964
  def supports_quoted_function_names?
1960
1965
  true
@@ -869,9 +869,9 @@ module Sequel
869
869
  end
870
870
  end
871
871
 
872
- # SQLite does not natively support NULLS FIRST/LAST.
872
+ # SQLite supports NULLS FIRST/LAST natively in 3.30+.
873
873
  def requires_emulating_nulls_first?
874
- true
874
+ db.sqlite_version < 33000
875
875
  end
876
876
 
877
877
  # SQLite does not support FOR UPDATE, but silently ignore it
@@ -897,6 +897,11 @@ module Sequel
897
897
  false
898
898
  end
899
899
 
900
+ # SQLite 3.30 supports the FILTER clause for aggregate functions.
901
+ def supports_filtered_aggregates?
902
+ db.sqlite_version >= 33000
903
+ end
904
+
900
905
  # SQLite supports quoted function names.
901
906
  def supports_quoted_function_names?
902
907
  true
@@ -230,6 +230,12 @@ module Sequel
230
230
  supports_cte_in_subqueries?
231
231
  end
232
232
 
233
+ # Whether the dataset supports the FILTER clause for aggregate functions.
234
+ # If not, support is emulated using CASE.
235
+ def supports_filtered_aggregates?
236
+ false
237
+ end
238
+
233
239
  # Whether the database supports quoting function names.
234
240
  def supports_quoted_function_names?
235
241
  false
@@ -492,11 +492,24 @@ module Sequel
492
492
  end
493
493
 
494
494
  sql << '('
495
+ if filter = opts[:filter]
496
+ filter = filter_expr(filter, &opts[:filter_block])
497
+ end
495
498
  if opts[:*]
496
- sql << '*'
499
+ if filter && !supports_filtered_aggregates?
500
+ literal_append(sql, Sequel.case({filter=>1}, nil))
501
+ filter = nil
502
+ else
503
+ sql << '*'
504
+ end
497
505
  else
498
506
  sql << "DISTINCT " if opts[:distinct]
499
- expression_list_append(sql, f.args)
507
+ if filter && !supports_filtered_aggregates?
508
+ expression_list_append(sql, f.args.map{|arg| Sequel.case({filter=>arg}, nil)})
509
+ filter = nil
510
+ else
511
+ expression_list_append(sql, f.args)
512
+ end
500
513
  if order = opts[:order]
501
514
  sql << " ORDER BY "
502
515
  expression_list_append(sql, order)
@@ -510,9 +523,9 @@ module Sequel
510
523
  sql << ')'
511
524
  end
512
525
 
513
- if filter = opts[:filter]
526
+ if filter
514
527
  sql << " FILTER (WHERE "
515
- literal_append(sql, filter_expr(filter, &opts[:filter_block]))
528
+ literal_append(sql, filter)
516
529
  sql << ')'
517
530
  end
518
531
 
@@ -51,8 +51,8 @@
51
51
  # ia.length(2) # array_length(int_array_column, 2)
52
52
  # ia.lower # array_lower(int_array_column, 1)
53
53
  # ia.lower(2) # array_lower(int_array_column, 2)
54
- # ia.join # array_to_string(int_array_column, '', NULL)
55
- # ia.join(':') # array_to_string(int_array_column, ':', NULL)
54
+ # ia.join # array_to_string(int_array_column, '')
55
+ # ia.join(':') # array_to_string(int_array_column, ':')
56
56
  # ia.join(':', ' ') # array_to_string(int_array_column, ':', ' ')
57
57
  # ia.unnest # unnest(int_array_column)
58
58
  # ia.unnest(:b) # unnest(int_array_column, b)
@@ -217,12 +217,16 @@ module Sequel
217
217
 
218
218
  # Call the array_to_string method:
219
219
  #
220
- # array_op.join # array_to_string(array, '', NULL)
221
- # array_op.to_string # array_to_string(array, '', NULL)
222
- # array_op.join(":") # array_to_string(array, ':', NULL)
220
+ # array_op.join # array_to_string(array, '')
221
+ # array_op.to_string # array_to_string(array, '')
222
+ # array_op.join(":") # array_to_string(array, ':')
223
223
  # array_op.join(":", "*") # array_to_string(array, ':', '*')
224
224
  def to_string(joiner="", null=nil)
225
- function(:array_to_string, joiner, null)
225
+ if null.nil?
226
+ function(:array_to_string, joiner)
227
+ else
228
+ function(:array_to_string, joiner, null)
229
+ end
226
230
  end
227
231
  alias join to_string
228
232
 
@@ -133,8 +133,11 @@ module Sequel
133
133
  # the pg_type table to get names and array oids for
134
134
  # enums.
135
135
  def parse_enum_labels
136
+ order = [:enumtypid]
137
+ order << :enumsortorder if server_version >= 90100
138
+
136
139
  enum_labels = metadata_dataset.from(:pg_enum).
137
- order(:enumtypid, :enumsortorder).
140
+ order(*order).
138
141
  select_hash_groups(Sequel.cast(:enumtypid, Integer).as(:v), :enumlabel).freeze
139
142
  enum_labels.each_value(&:freeze)
140
143
 
@@ -1317,6 +1317,7 @@ module Sequel
1317
1317
  CURRENT_DATE = Constant.new(:CURRENT_DATE)
1318
1318
  CURRENT_TIME = Constant.new(:CURRENT_TIME)
1319
1319
  CURRENT_TIMESTAMP = Constant.new(:CURRENT_TIMESTAMP)
1320
+ DEFAULT = Constant.new(:DEFAULT)
1320
1321
  SQLTRUE = TRUE = BooleanConstant.new(true)
1321
1322
  SQLFALSE = FALSE = BooleanConstant.new(false)
1322
1323
  NULL = BooleanConstant.new(nil)
@@ -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 = 26
9
+ MINOR = 27
10
10
 
11
11
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
12
12
  # releases that fix regressions from previous versions.
@@ -70,7 +70,7 @@ describe "PostgreSQL", '#create_table' do
70
70
 
71
71
  it "should create an unlogged table" do
72
72
  @db.create_table(:unlogged_dolls, :unlogged => true){text :name}
73
- end
73
+ end if DB.server_version >= 90100
74
74
 
75
75
  it "should create a table inheriting from another table" do
76
76
  @db.create_table(:unlogged_dolls){text :name}
@@ -615,10 +615,6 @@ describe "A PostgreSQL dataset" do
615
615
  @d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{mode.function.within_group(:a)}.must_equal 1
616
616
  end if DB.server_version >= 90400
617
617
 
618
- it "should support filtered aggregate functions" do
619
- @d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{count(:a).filter(:a=>1)}.must_equal 2
620
- end if DB.server_version >= 90400
621
-
622
618
  it "should support functions with ordinality" do
623
619
  @d.from{generate_series(1,10,3).with_ordinality}.select_map([:generate_series, :ordinality]).must_equal [[1, 1], [4, 2], [7, 3], [10, 4]]
624
620
  end if DB.server_version >= 90400
@@ -1272,7 +1268,7 @@ describe "A PostgreSQL database" do
1272
1268
  end
1273
1269
 
1274
1270
  it "should support indexes with index type" do
1275
- @db.create_table(:posts){point :p; index :p, :type => 'gist'}
1271
+ @db.create_table(:posts){box :geom; index :geom, :type => 'gist'}
1276
1272
  end
1277
1273
 
1278
1274
  it "should support unique indexes with index type" do
@@ -2704,6 +2700,8 @@ describe 'PostgreSQL array handling' do
2704
2700
  if @db.server_version >= 90000
2705
2701
  @ds.get(Sequel.pg_array(:i5).join).must_equal '15'
2706
2702
  @ds.get(Sequel.pg_array(:i5).join(':')).must_equal '1:5'
2703
+ end
2704
+ if @db.server_version >= 90100
2707
2705
  @ds.get(Sequel.pg_array(:i5).join(':', '*')).must_equal '1:*:5'
2708
2706
  end
2709
2707
  if @db.server_version >= 90300
@@ -4475,4 +4473,4 @@ describe "pg_auto_constraint_validations plugin" do
4475
4473
  File.delete(cache_file) if File.file?(cache_file)
4476
4474
  end
4477
4475
  end
4478
- end if DB.respond_to?(:error_info)
4476
+ end if DB.respond_to?(:error_info) && DB.server_version >= 90300
@@ -623,7 +623,7 @@ describe "SQLite", 'INSERT ON CONFLICT' do
623
623
  @ds.insert_conflict(:target=>:a).insert(1, 3, 4, false)
624
624
  @ds.insert_conflict(:target=>:c, :conflict_where=>:c_is_unique).insert(11, 12, 3, true)
625
625
  @ds.all.must_equal [{:a=>1, :b=>2, :c=>3, :c_is_unique=>false}, {:a=>10, :b=>11, :c=>3, :c_is_unique=>true}]
626
- end
626
+ end unless DB.adapter_scheme == :amalgalite
627
627
 
628
628
  it "Dataset#insert_ignore and insert_conflict should work with multi_insert/import" do
629
629
  @ds.insert(1, 2, 3, false)
@@ -353,6 +353,11 @@ describe "Blockless Ruby Filters" do
353
353
  @d.l({:x => Sequel::FALSE}).must_equal '(x IS FALSE)'
354
354
  @d.l({:x => Sequel::SQLTRUE}).must_equal '(x IS TRUE)'
355
355
  @d.l({:x => Sequel::SQLFALSE}).must_equal '(x IS FALSE)'
356
+
357
+ @d.l({:x => Sequel::CURRENT_DATE}).must_equal '(x = CURRENT_DATE)'
358
+ @d.l({:x => Sequel::CURRENT_TIME}).must_equal '(x = CURRENT_TIME)'
359
+ @d.l({:x => Sequel::CURRENT_TIMESTAMP}).must_equal '(x = CURRENT_TIMESTAMP)'
360
+ @d.l({:x => Sequel::DEFAULT}).must_equal '(x = DEFAULT)'
356
361
  end
357
362
 
358
363
  it "should support negation of SQL::Constants" do
@@ -741,14 +746,23 @@ describe Sequel::SQL::VirtualRow do
741
746
  @d.l{mode.function.within_group(:a, :b)}.must_equal 'mode() WITHIN GROUP (ORDER BY "a", "b")'
742
747
  end
743
748
 
749
+ it "should handle emualted filtered aggregate function calls" do
750
+ @d.l{count.function.*.filter(Sequel.&(:a, :b))}.must_equal 'count((CASE WHEN ("a" AND "b") THEN 1 ELSE NULL END))'
751
+ @d.l{count.function.*.filter(:a=>1)}.must_equal 'count((CASE WHEN ("a" = 1) THEN 1 ELSE NULL END))'
752
+ @d.l{count(:a).filter{b > 1}}.must_equal 'count((CASE WHEN ("b" > 1) THEN "a" ELSE NULL END))'
753
+ @d.l{count(:a).filter(:a=>1){b > 1}}.must_equal 'count((CASE WHEN (("a" = 1) AND ("b" > 1)) THEN "a" ELSE NULL END))'
754
+ end
755
+
744
756
  it "should handle filtered aggregate function calls" do
757
+ @d = @d.with_extend{def supports_filtered_aggregates?; true end}
745
758
  @d.l{count.function.*.filter(Sequel.&(:a, :b))}.must_equal 'count(*) FILTER (WHERE ("a" AND "b"))'
746
759
  @d.l{count.function.*.filter(:a=>1)}.must_equal 'count(*) FILTER (WHERE ("a" = 1))'
747
760
  @d.l{count.function.*.filter{b > 1}}.must_equal 'count(*) FILTER (WHERE ("b" > 1))'
748
761
  @d.l{count.function.*.filter(:a=>1){b > 1}}.must_equal 'count(*) FILTER (WHERE (("a" = 1) AND ("b" > 1)))'
749
762
  end
750
763
 
751
- it "should handle fitlered ordered-set and hypothetical-set function calls" do
764
+ it "should handle filtered ordered-set and hypothetical-set function calls" do
765
+ @d = @d.with_extend{def supports_filtered_aggregates?; true end}
752
766
  @d.l{mode.function.within_group(:a).filter(:a=>1)}.must_equal 'mode() WITHIN GROUP (ORDER BY "a") FILTER (WHERE ("a" = 1))'
753
767
  end
754
768
 
@@ -83,9 +83,9 @@ describe "Sequel::Postgres::ArrayOp" do
83
83
  end
84
84
 
85
85
  it "#to_string/join should use the array_to_string function" do
86
- @db.literal(@a.to_string).must_equal "array_to_string(a, '', NULL)"
87
- @db.literal(@a.join).must_equal "array_to_string(a, '', NULL)"
88
- @db.literal(@a.join(':')).must_equal "array_to_string(a, ':', NULL)"
86
+ @db.literal(@a.to_string).must_equal "array_to_string(a, '')"
87
+ @db.literal(@a.join).must_equal "array_to_string(a, '')"
88
+ @db.literal(@a.join(':')).must_equal "array_to_string(a, ':')"
89
89
  @db.literal(@a.join(':', '*')).must_equal "array_to_string(a, ':', '*')"
90
90
  end
91
91
 
@@ -92,6 +92,17 @@ describe "Simple Dataset operations" do
92
92
  @ds.from_self(:alias=>:items).graph(@ds.from_self, {:id=>:id}, :table_alias=>:b).extension(:graph_each).all.must_equal [{:items=>{:id=>1, :number=>10}, :b=>{:id=>1, :number=>10}}]
93
93
  end
94
94
 
95
+ cspecify "should have insert and update work with Sequel::DEFAULT", :sqlite do
96
+ @db.create_table!(:items) do
97
+ Integer :number, :default=>10
98
+ end
99
+ @ds.insert(:number=>Sequel::DEFAULT)
100
+ @ds.select_map(:number).must_equal [10]
101
+ @ds.insert(:number=>20)
102
+ @ds.update(:number=>Sequel::DEFAULT)
103
+ @ds.select_map(:number).must_equal [10, 10]
104
+ end
105
+
95
106
  cspecify "should have insert work correctly when inserting a row with all NULL values", :hsqldb do
96
107
  @db.create_table!(:items) do
97
108
  String :name
@@ -443,6 +454,20 @@ describe Sequel::Dataset do
443
454
  @d.extension(:sequel_4_dataset_methods).interval(:value).to_i.must_equal 6
444
455
  end
445
456
 
457
+ it "should support or emulate filtered aggregate functions" do
458
+ @d.insert(:name => 'abc', :value => 123)
459
+ @d.insert(:name => 'abc', :value => 456)
460
+ @d.insert(:name => 'def', :value => 324)
461
+ @d.get{count.function.*.filter{value > 100}}.must_equal 3
462
+ @d.get{count.function.*.filter{value > 200}}.must_equal 2
463
+ @d.get{count.function.*.filter{value > 400}}.must_equal 1
464
+ @d.get{count.function.*.filter{value > 500}}.must_equal 0
465
+ @d.get{count(:value).filter{value > 100}}.must_equal 3
466
+ @d.get{count(:value).filter{value > 200}}.must_equal 2
467
+ @d.get{count(:value).filter{value > 400}}.must_equal 1
468
+ @d.get{count(:value).filter{value > 500}}.must_equal 0
469
+ end
470
+
446
471
  it "should return the correct records" do
447
472
  @d.to_a.must_equal []
448
473
  @d.insert(:name => 'abc', :value => 123)
@@ -2393,7 +2393,7 @@ describe "string_agg extension" do
2393
2393
  cspecify "should have string_agg return aggregated concatenation for distinct values", :mssql, :sqlite, :oracle, :db2, :derby do
2394
2394
  @ds.select_group(:id).select_append(Sequel.string_agg(:s).order(:s).distinct.as(:v)).map([:id, :v]).must_equal [[1, 'a,b,c'], [2, 'aa,bb']]
2395
2395
  end
2396
- end
2396
+ end if (DB.database_type != :postgres || DB.server_version >= 90000)
2397
2397
 
2398
2398
  describe "insert_conflict plugin" do
2399
2399
  before(:all) do
@@ -62,4 +62,10 @@ if ENV['SEQUEL_FREEZE_DATABASE']
62
62
  DB.freeze
63
63
  end
64
64
 
65
- puts "running #{defined?(SEQUEL_ADAPTER_TEST) ? SEQUEL_ADAPTER_TEST : "integration (database type: #{DB.database_type})"} specs on #{RUBY_ENGINE} #{defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION} with #{DB.adapter_scheme} adapter"
65
+ version = if DB.respond_to?(:server_version)
66
+ DB.server_version
67
+ elsif DB.respond_to?(:sqlite_version)
68
+ DB.sqlite_version
69
+ end
70
+
71
+ puts "running #{defined?(SEQUEL_ADAPTER_TEST) ? SEQUEL_ADAPTER_TEST : "integration (database type: #{DB.database_type})"} specs on #{RUBY_ENGINE} #{defined?(JRUBY_VERSION) ? JRUBY_VERSION : RUBY_VERSION} with #{DB.adapter_scheme} adapter#{" (database version: #{version})" if version}"
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.26.0
4
+ version: 5.27.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: 2019-11-01 00:00:00.000000000 Z
11
+ date: 2019-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -224,6 +224,7 @@ extra_rdoc_files:
224
224
  - doc/release_notes/5.24.0.txt
225
225
  - doc/release_notes/5.25.0.txt
226
226
  - doc/release_notes/5.26.0.txt
227
+ - doc/release_notes/5.27.0.txt
227
228
  files:
228
229
  - CHANGELOG
229
230
  - MIT-LICENSE
@@ -321,6 +322,7 @@ files:
321
322
  - doc/release_notes/5.24.0.txt
322
323
  - doc/release_notes/5.25.0.txt
323
324
  - doc/release_notes/5.26.0.txt
325
+ - doc/release_notes/5.27.0.txt
324
326
  - doc/release_notes/5.3.0.txt
325
327
  - doc/release_notes/5.4.0.txt
326
328
  - doc/release_notes/5.5.0.txt