sequel 4.27.0 → 4.28.0

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
  SHA1:
3
- metadata.gz: c8e0006e87c72a9cee83298b0fab32a7ccea74ef
4
- data.tar.gz: 46a222bb7aa35ce30d2a931c56c0cc49d8fd1b3a
3
+ metadata.gz: 4342ce776d6f7e929b8ef1e9621f79f4544357b4
4
+ data.tar.gz: 64ed417591b155d46f3ca0abdbe38f515ea9e15f
5
5
  SHA512:
6
- metadata.gz: db00224bfcada026d014fbe777cee84849e8786a33519258197a371e9f48970c8a37a1e45e05462f90e0c9e89fb638dcfd1c5442855f1d6b02e7a79b2a21901d
7
- data.tar.gz: 79bbb7ad3a536b02bd7242c2fd2b6f08b2772a5b44ba5acdca66224fe93c009e093861ec9e61b877b8349d77ae3d2c5350edcae41cfd6f10827984be0e77ffde
6
+ metadata.gz: 2e672203108c7301da9abcaf7596368a1aa09b8302175bb6f49d9bc189993a84e7089343e16fcdb69b9409d3677746694b36e7cbb25d1c179779ab605cd63343
7
+ data.tar.gz: 198aa8d381bd263e27bb03b646f0fa50d45225b5370084236d6da55eb1f6032396c6548f114c8ccf0d187091ab2a195c5d298e62e5a185bf992ce4fb06615d15
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ === 4.28.0 (2015-11-02)
2
+
3
+ * Add boolean_subsets plugin, which adds a subset for each boolean column (jeremyevans)
4
+
5
+ * Add subset_conditions plugin, which adds a method for each subset returning the filter conditions for the subset (jeremyevans)
6
+
7
+ * Make the list plugin work better with the auto_validations plugin when there is a validation on the position column (jeremyevans)
8
+
9
+ * Make to_csv for model datasets call instance methods, just like Model#to_csv, in the csv_serializer plugin (skrobul) (#1088)
10
+
11
+ * Raise Sequel::NoExistingObject instead of generic error if Model#refresh can't find the related row (jeremyevans)
12
+
1
13
  === 4.27.0 (2015-10-01)
2
14
 
3
15
  * Don't stub Sequel.synchronize on MRI (YorickPeterse) (#1083)
@@ -0,0 +1,57 @@
1
+ = New Features
2
+
3
+ * A subset_conditions plugin has been added, which adds a method
4
+ for each subset that returns the filter conditions for the
5
+ subset. This makes it easier to reuse the subset conditions:
6
+
7
+ class Foo < Sequel::Model
8
+ plugin :subset_conditions
9
+ subset :active, :active=>true
10
+ end
11
+
12
+ Foo.exclude(Foo.active_conditions)
13
+ Foo.where(:a=>1).or(Foo.active_conditions)
14
+
15
+ * A boolean_subsets plugin has been added, which adds a subset for each
16
+ boolean column:
17
+
18
+ # Assume boolean column :active
19
+ Foo.plugin :boolean_subsets
20
+
21
+ Foo.active
22
+ # SELECT * FROM foos WHERE (active IS TRUE)
23
+
24
+ You can provide a block to the plugin to change the arguments passed
25
+ to subset:
26
+
27
+ Foo.plugin :boolean_subsets do |column|
28
+ [:"where_#{column}", column]
29
+ end
30
+
31
+ Foo.where_active
32
+ # SELECT * FROM foos WHERE active
33
+
34
+ As with similar plugins, you can add the boolean_subsets plugin to
35
+ Sequel::Model itself, and all subclasses created afterward will have
36
+ the boolean subset methods automatically created.
37
+
38
+ = Other Improvements
39
+
40
+ * If Model#refresh can't find the related row, Sequel now raises a
41
+ Sequel::NoExistingObject exception instead of a generic
42
+ Sequel::Error exception.
43
+
44
+ * In the csv_serializer plugin, when calling #to_csv on a model class
45
+ or dataset, instead of using #[] to access data, #send is used to
46
+ call methods. This is more similar to other plugins as well as
47
+ Model#to_csv.
48
+
49
+ * The list plugin now works better with the auto_validations plugin,
50
+ or any other time there is a validation on the position column.
51
+
52
+ = Backwards Compatibility
53
+
54
+ * The change to the csv_serializer plugin can change results if you
55
+ are overriding any of the column accessor methods. It can also
56
+ break existing code if one of the columns being used isn't defined
57
+ as a method or the method requires more than one argument.
@@ -6,7 +6,10 @@ Sequel uses autocommit mode by default for all of its database adapters, so in g
6
6
  * Model#save
7
7
  * Model#destroy
8
8
  * Migrations if the database supports transactional schema
9
- * A few model plugins
9
+ * Database#use_cursor in the postgres adapter
10
+ * Dataset#lock on PostgreSQL if given a block
11
+ * setter methods created by the association_pks plugin
12
+ * move* methods in the list plugin
10
13
 
11
14
  Everywhere else, it is up to you to use a database transaction if you want to.
12
15
 
@@ -1,6 +1,6 @@
1
1
  = Model Validations
2
2
 
3
- This guide is based on http://guides.rubyonrails.org/activerecord_validations_callbacks.html
3
+ This guide is based on http://guides.rubyonrails.org/active_record_validations.html
4
4
 
5
5
  == Overview
6
6
 
@@ -674,9 +674,11 @@ module Sequel
674
674
  end
675
675
 
676
676
  # Uses a cursor for fetching records, instead of fetching the entire result
677
- # set at once. Can be used to process large datasets without holding
678
- # all rows in memory (which is what the underlying drivers may do
679
- # by default). Options:
677
+ # set at once. Note this uses a transaction around the cursor usage by
678
+ # default and can be changed using `hold: true` as described below.
679
+ # Cursors can be used to process large datasets without holding all rows
680
+ # in memory (which is what the underlying drivers may do by default).
681
+ # Options:
680
682
  #
681
683
  # :cursor_name :: The name assigned to the cursor (default 'sequel_cursor').
682
684
  # Nested cursors require different names.
@@ -1867,7 +1867,7 @@ module Sequel
1867
1867
  # Refresh using a particular dataset, used inside save to make sure the same server
1868
1868
  # is used for reading newly inserted values from the database
1869
1869
  def _refresh(dataset)
1870
- _refresh_set_values(_refresh_get(dataset) || raise(Error, "Record not found"))
1870
+ _refresh_set_values(_refresh_get(dataset) || raise(NoExistingObject, "Record not found"))
1871
1871
  changed_columns.clear
1872
1872
  end
1873
1873
 
@@ -1939,7 +1939,7 @@ module Sequel
1939
1939
  # default values of all columns. Separated from _save so it
1940
1940
  # can be overridden to avoid the refresh.
1941
1941
  def _save_refresh
1942
- _save_set_values(_refresh_get(this.server?(:default)) || raise(Error, "Record not found"))
1942
+ _save_set_values(_refresh_get(this.server?(:default)) || raise(NoExistingObject, "Record not found"))
1943
1943
  changed_columns.clear
1944
1944
  end
1945
1945
 
@@ -0,0 +1,56 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The boolean_subsets plugin allows for the automatic creation of subsets for
4
+ # for boolean columns, which can DRY up model classes that define such subsets
5
+ # manually. By default, subsets are created for all columns of type :boolean,
6
+ # with the subset name being the same as column name, and the conditions being
7
+ # <tt>column IS TRUE</tt> (assuming the database supports that syntax).
8
+ #
9
+ # You can provide a block to the plugin, which will be called with column name
10
+ # symbol, and should return an array of arguments to pass to +subset+.
11
+ # Using this, you can change the method name and arguments for each column.
12
+ # This block is executed in the context of the model class.
13
+ #
14
+ # Usage:
15
+ #
16
+ # # Add boolean subset methods for all columns of type :boolean
17
+ # # in all model subclasses (called before loading subclasses)
18
+ # Sequel::Model.plugin :boolean_subsets
19
+ #
20
+ # # Add subsets for all boolean columns in the Album class
21
+ # Album.plugin(:boolean_subsets)
22
+ #
23
+ # # Remove is_ from the front of the column name when creating the subset
24
+ # # method name, and use (column = 'Y') as the filter conditions
25
+ # Sequel::Model.plugin :boolean_subsets do |column|
26
+ # [column.to_s.sub(/\Ais_/, ''), {column=>'Y'}]
27
+ # end
28
+ module BooleanSubsets
29
+ # Add the boolean_attribute? class method to the model, and create
30
+ # attribute? boolean reader methods for the class's columns if the class has a dataset.
31
+ def self.configure(model, &block)
32
+ model.instance_eval do
33
+ (class << self; self; end).send(:define_method, :boolean_subset_args, &block) if block
34
+ send(:create_boolean_subsets) if @dataset
35
+ end
36
+ end
37
+
38
+ module ClassMethods
39
+ Plugins.after_set_dataset(self, :create_boolean_subsets)
40
+
41
+ private
42
+
43
+ # The arguments to use when automatically defining a boolean subset for the given column.
44
+ def boolean_subset_args(c)
45
+ [c, {c=>true}]
46
+ end
47
+
48
+ # Add subset methods for all of the boolean columns in this model.
49
+ def create_boolean_subsets
50
+ cs = columns rescue return
51
+ cs.each{|c| subset(*boolean_subset_args(c)) if db_schema[c][:type] == :boolean}
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -163,7 +163,7 @@ module Sequel
163
163
 
164
164
  CSV.generate(opts) do |csv|
165
165
  items.each do |object|
166
- csv << opts[:headers].map{|header| object[header]}
166
+ csv << opts[:headers].map{|header| object.send(header) }
167
167
  end
168
168
  end
169
169
  end
@@ -87,15 +87,6 @@ module Sequel
87
87
  list_dataset.first(position_field => p)
88
88
  end
89
89
 
90
- # Set the value of the position_field to the maximum value plus 1 unless the
91
- # position field already has a value.
92
- def before_create
93
- unless get_column_value(position_field)
94
- set_column_value("#{position_field}=", list_dataset.max(position_field).to_i+1)
95
- end
96
- super
97
- end
98
-
99
90
  # When destroying an instance, move all entries after the instance down
100
91
  # one position, so that there aren't any gaps
101
92
  def after_destroy
@@ -179,6 +170,15 @@ module Sequel
179
170
 
180
171
  private
181
172
 
173
+ # Set the value of the position_field to the maximum value plus 1 unless the
174
+ # position field already has a value.
175
+ def _before_validation
176
+ unless get_column_value(position_field)
177
+ set_column_value("#{position_field}=", list_dataset.max(position_field).to_i+1)
178
+ end
179
+ super
180
+ end
181
+
182
182
  # The model's position field, an instance method for ease of use.
183
183
  def position_field
184
184
  model.position_field
@@ -0,0 +1,36 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The subset_conditions plugin creates an additional *_conditions method
4
+ # for every subset created, which returns the filter conditions the subset
5
+ # uses. This can be useful if you want to use the conditions for a separate
6
+ # filter or combine them with OR.
7
+ #
8
+ # Usage:
9
+ #
10
+ # # Add subset_conditions in the Album class
11
+ # Album.plugin :subset_conditions
12
+ #
13
+ # # This will now create a published_conditions method
14
+ # Album.subset :published, :published => true
15
+ #
16
+ # Album.where(Album.published_conditions).sql
17
+ # # SELECT * FROM albums WHERE (published IS TRUE)
18
+ #
19
+ # Album.exclude(Album.published_conditions).sql
20
+ # # SELECT * FROM albums WHERE (published IS NOT TRUE)
21
+ #
22
+ # Album.where(Sequel.|(Album.published_conditions, :ready=>true)).sql
23
+ # # SELECT * FROM albums WHERE ((published IS TRUE) OR (ready IS TRUE))
24
+ module SubsetConditions
25
+ module ClassMethods
26
+ # Also create a method that returns the conditions the filter uses.
27
+ def subset(name, *args, &block)
28
+ super
29
+ cond = args
30
+ cond = cond.first if cond.size == 1
31
+ def_dataset_method(:"#{name}_conditions"){filter_expr(cond, &block)}
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 4
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 27
6
+ MINOR = 28
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
9
  TINY = 0
@@ -0,0 +1,47 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "boolean_subsets plugin" do
4
+ before do
5
+ @db = Sequel::Database.new
6
+ def @db.supports_schema_parsing?() true end
7
+ def @db.schema(*args)
8
+ [[:asdaf9898as, {}], [:active, {:type=>:boolean}]]
9
+ end
10
+
11
+ @c = Class.new(Sequel::Model(@db[:items]))
12
+ @p = proc do
13
+ @columns = [:asdaf9898as, :active]
14
+ def columns; @columns; end
15
+ end
16
+ @c.instance_eval(&@p)
17
+ end
18
+
19
+ it "should create subsets only for boolean attributes" do
20
+ @c.plugin(:boolean_subsets)
21
+ @c.active.sql.must_equal "SELECT * FROM items WHERE (active IS TRUE)"
22
+ @c.respond_to?(:asdaf9898as).must_equal false
23
+ end
24
+
25
+ it "should handle a block passed to the plugin" do
26
+ @c.plugin(:boolean_subsets){|c| ["where_#{c}", c]}
27
+ @c.where_active.sql.must_equal "SELECT * FROM items WHERE active"
28
+ @c.respond_to?(:active).must_equal false
29
+ end
30
+
31
+ it "should create boolean subsets when set_dataset is called" do
32
+ c = Class.new(Sequel::Model(@db))
33
+ c.instance_eval(&@p)
34
+ c.plugin(:boolean_subsets)
35
+ c.respond_to?(:active).must_equal false
36
+
37
+ c.set_dataset(@db[:items])
38
+ c.active.sql.must_equal "SELECT * FROM items WHERE (active IS TRUE)"
39
+ c.respond_to?(:asdaf9898as).must_equal false
40
+ end
41
+
42
+ it "should handle cases where getting the columns raises an error" do
43
+ @c.meta_def(:columns){raise Sequel::Error}
44
+ @c.plugin(:boolean_subsets)
45
+ @c.respond_to?(:active).must_equal false
46
+ end
47
+ end
@@ -264,4 +264,15 @@ describe "List plugin" do
264
264
  @o.prev(-1).must_equal @c.load(:id=>9, :position=>4)
265
265
  @db.sqls.must_equal ["SELECT * FROM items WHERE (position = 4) ORDER BY position LIMIT 1"]
266
266
  end
267
+
268
+ it "should work correctly with validation on position" do
269
+ @c.class_eval do
270
+ def validate
271
+ super
272
+ errors.add(:position, "not set") unless position
273
+ end
274
+ end
275
+ @c.create
276
+ @db.sqls.must_equal ["SELECT max(position) AS max FROM items LIMIT 1", "INSERT INTO items (position) VALUES (2)", "SELECT * FROM items WHERE (id = 10) ORDER BY position LIMIT 1"]
277
+ end
267
278
  end
@@ -0,0 +1,38 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
+
3
+ describe "subset_conditions plugin" do
4
+ before do
5
+ @c = Class.new(Sequel::Model(:a))
6
+ @c.plugin :subset_conditions
7
+ end
8
+
9
+ it "should provide *_conditions method return the arguments passed" do
10
+ @c.subset(:published, :published => true)
11
+ @c.where(@c.published_conditions).sql.must_equal @c.published.sql
12
+
13
+ @c.subset(:active, :active)
14
+ @c.where(@c.active_conditions).sql.must_equal @c.active.sql
15
+
16
+ @c.subset(:active_published, :active, :published => true)
17
+ @c.where(@c.active_published_conditions).sql.must_equal @c.active_published.sql
18
+ @c.where(Sequel.&(@c.active_conditions, @c.published_conditions)).sql.must_equal @c.active_published.sql
19
+ @c.where(Sequel.|(@c.active_conditions, @c.published_conditions)).sql.must_equal "SELECT * FROM a WHERE (active OR (published IS TRUE))"
20
+ @c.where(Sequel.|(@c.active_published_conditions, :foo)).sql.must_equal "SELECT * FROM a WHERE ((active AND (published IS TRUE)) OR foo)"
21
+ end
22
+
23
+ it "should work with blocks" do
24
+ p1 = proc{{:published=>true}}
25
+ @c.subset(:published, &p1)
26
+ @c.where(@c.published_conditions).sql.must_equal @c.published.sql
27
+
28
+ p2 = proc{:active}
29
+ @c.subset(:active, &p2)
30
+ @c.where(@c.active_conditions).sql.must_equal @c.active.sql
31
+
32
+ @c.subset(:active_published, p2, &p1)
33
+ @c.where(@c.active_published_conditions).sql.must_equal @c.active_published.sql
34
+ @c.where(Sequel.&(@c.active_conditions, @c.published_conditions)).sql.must_equal @c.active_published.sql
35
+ @c.where(Sequel.|(@c.active_conditions, @c.published_conditions)).sql.must_equal "SELECT * FROM a WHERE (active OR (published IS TRUE))"
36
+ @c.where(Sequel.|(@c.active_published_conditions, :foo)).sql.must_equal "SELECT * FROM a WHERE ((active AND (published IS TRUE)) OR foo)"
37
+ end
38
+ end
@@ -67,6 +67,12 @@ describe "Model#save" do
67
67
  DB.sqls.must_equal ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE (id = 13) LIMIT 1"]
68
68
  end
69
69
 
70
+ it "should raise if the object can't be refreshed after save" do
71
+ o = @c.new(:x => 1)
72
+ @c.instance_dataset._fetch =@c.dataset._fetch = []
73
+ proc{o.save}.must_raise(Sequel::NoExistingObject)
74
+ end
75
+
70
76
  it "should use dataset's insert_select method if present" do
71
77
  ds = @c.instance_dataset
72
78
  ds._fetch = {:y=>2}
@@ -1738,7 +1744,7 @@ describe Sequel::Model, "#refresh" do
1738
1744
  it "should raise if the instance is not found" do
1739
1745
  @m = @c.new(:id => 555)
1740
1746
  @c.instance_dataset._fetch =@c.dataset._fetch = []
1741
- proc {@m.refresh}.must_raise(Sequel::Error)
1747
+ proc {@m.refresh}.must_raise(Sequel::NoExistingObject)
1742
1748
  DB.sqls.must_equal ["SELECT * FROM items WHERE (id = 555) LIMIT 1"]
1743
1749
  end
1744
1750
 
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: 4.27.0
4
+ version: 4.28.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: 2015-10-01 00:00:00.000000000 Z
11
+ date: 2015-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -228,6 +228,7 @@ extra_rdoc_files:
228
228
  - doc/release_notes/4.25.0.txt
229
229
  - doc/release_notes/4.26.0.txt
230
230
  - doc/release_notes/4.27.0.txt
231
+ - doc/release_notes/4.28.0.txt
231
232
  files:
232
233
  - CHANGELOG
233
234
  - MIT-LICENSE
@@ -343,6 +344,7 @@ files:
343
344
  - doc/release_notes/4.25.0.txt
344
345
  - doc/release_notes/4.26.0.txt
345
346
  - doc/release_notes/4.27.0.txt
347
+ - doc/release_notes/4.28.0.txt
346
348
  - doc/release_notes/4.3.0.txt
347
349
  - doc/release_notes/4.4.0.txt
348
350
  - doc/release_notes/4.5.0.txt
@@ -535,6 +537,7 @@ files:
535
537
  - lib/sequel/plugins/before_after_save.rb
536
538
  - lib/sequel/plugins/blacklist_security.rb
537
539
  - lib/sequel/plugins/boolean_readers.rb
540
+ - lib/sequel/plugins/boolean_subsets.rb
538
541
  - lib/sequel/plugins/caching.rb
539
542
  - lib/sequel/plugins/class_table_inheritance.rb
540
543
  - lib/sequel/plugins/column_conflicts.rb
@@ -584,6 +587,7 @@ files:
584
587
  - lib/sequel/plugins/static_cache.rb
585
588
  - lib/sequel/plugins/string_stripper.rb
586
589
  - lib/sequel/plugins/subclasses.rb
590
+ - lib/sequel/plugins/subset_conditions.rb
587
591
  - lib/sequel/plugins/table_select.rb
588
592
  - lib/sequel/plugins/tactical_eager_loading.rb
589
593
  - lib/sequel/plugins/timestamps.rb
@@ -637,6 +641,7 @@ files:
637
641
  - spec/extensions/blacklist_security_spec.rb
638
642
  - spec/extensions/blank_spec.rb
639
643
  - spec/extensions/boolean_readers_spec.rb
644
+ - spec/extensions/boolean_subsets_spec.rb
640
645
  - spec/extensions/caching_spec.rb
641
646
  - spec/extensions/class_table_inheritance_spec.rb
642
647
  - spec/extensions/column_conflicts_spec.rb
@@ -737,6 +742,7 @@ files:
737
742
  - spec/extensions/string_date_time_spec.rb
738
743
  - spec/extensions/string_stripper_spec.rb
739
744
  - spec/extensions/subclasses_spec.rb
745
+ - spec/extensions/subset_conditions_spec.rb
740
746
  - spec/extensions/table_select_spec.rb
741
747
  - spec/extensions/tactical_eager_loading_spec.rb
742
748
  - spec/extensions/thread_local_timezones_spec.rb
@@ -858,4 +864,3 @@ signing_key:
858
864
  specification_version: 4
859
865
  summary: The Database Toolkit for Ruby
860
866
  test_files: []
861
- has_rdoc: true