sequel 4.27.0 → 4.28.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
  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