activerecord-typedstore 1.5.1 → 1.6.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: 5f56fb7b6456937890a85e139a296727a04b2c87a2452f45810782849378357a
4
- data.tar.gz: 17e694f93e4db21a4b5a08c7795285fd10aaf9bc203f74376a14356873c84802
3
+ metadata.gz: 9cbd38a8c2df073a4576501953ef2e9debb1d4c36c673c7e5467c04a247ba9cd
4
+ data.tar.gz: f12be53e1013b2302706e6471bebec9abd0d9edd74efe660d0fcf6d4859368c1
5
5
  SHA512:
6
- metadata.gz: 02d3ce60427903e2c039818c4c77368a42b20c4f9fbf5bf167357e0e932d01c717f5eea6172ea03170b018a468b6b8f0a00d59fd49073a38eb620a27e05870c3
7
- data.tar.gz: 96ff55688ac6c1b2d9f56d9a45e796b4c633e6d3d1dd89cdbdb14025044d97c9f5deefce7a53494f35ff5a227f340e8ec9d9fba70b7d861fe488ee6f52ad98fe
6
+ metadata.gz: 8e9ff18057af10d974dc456f3ff66633dd2483aae664f6acab881a895ef341b8006a25641441b216189dd61f972fefad067e41351e3cd04020e51d9a7d974272
7
+ data.tar.gz: 230a6686e806dac2ad28892f2f2f2344f1f7b6b7627f1eb048a1e0e2cce4e4b5f6336e162aa23f37de52197ca41909fa9ac43476a828b4d3fcf5e7ffbdb0dc96
@@ -9,9 +9,18 @@ jobs:
9
9
  strategy:
10
10
  fail-fast: false
11
11
  matrix:
12
- ruby: ['2.7', '3.0', '3.1']
13
- rails: ['6.1', '7.0', 'edge']
12
+ ruby: ['2.7', '3.0', '3.1', '3.2', '3.3']
13
+ rails: ['6.1', '7.0', '7.1', 'edge']
14
14
  timezone_aware: [0, 1]
15
+ exclude:
16
+ - ruby: '3.2'
17
+ rails: '6.1'
18
+ - ruby: '3.3'
19
+ rails: '6.1'
20
+ - ruby: '2.7'
21
+ rails: 'edge'
22
+ - ruby: '3.0'
23
+ rails: 'edge'
15
24
  env:
16
25
  BUNDLE_GEMFILE: gemfiles/Gemfile.ar-${{ matrix.rails }}
17
26
  TIMEZONE_AWARE: ${{ matrix.timezone_aware }}
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ActiveRecord::TypedStore
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/activerecord-typedstore.png)](http://badge.fury.io/rb/activerecord-typedstore)
3
+ [![Gem Version](https://badge.fury.io/rb/activerecord-typedstore.svg)](http://badge.fury.io/rb/activerecord-typedstore)
4
4
 
5
5
  [ActiveRecord::Store](http://api.rubyonrails.org/classes/ActiveRecord/Store.html) but with typed attributes.
6
6
 
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activerecord', '~> 7.0.0'
@@ -74,20 +74,29 @@ module ActiveRecord::TypedStore
74
74
 
75
75
  private
76
76
 
77
- def attribute_names_for_partial_inserts
78
- # Contrary to all vanilla Rails types, typedstore attribute have an inherent default
79
- # value that doesn't match the database column default.
80
- # As such we need to insert them on partial inserts even if they weren't changed.
81
- super | self.class.typed_stores.keys.map(&:to_s)
82
- end
77
+ if ActiveRecord.version.segments.first >= 7
78
+ def attribute_names_for_partial_inserts
79
+ # Contrary to all vanilla Rails types, typedstore attribute have an inherent default
80
+ # value that doesn't match the database column default.
81
+ # As such we need to insert them on partial inserts even if they weren't changed.
82
+ super | self.class.typed_stores.keys.map(&:to_s)
83
+ end
83
84
 
84
- def attribute_names_for_partial_updates
85
- # On partial updates we shouldn't need to force stores to be persisted. However since
86
- # we weren't persisting them for a while on insertion, we now need to gracefully deal
87
- # with existing records that may have been persisted with a `NULL` store
88
- # We use `blank?` as an heuristic to detect these.
89
- super | self.class.typed_stores.keys.map(&:to_s).select do |store|
90
- @attributes.key?(store) && @attributes[store].value_before_type_cast.blank?
85
+ def attribute_names_for_partial_updates
86
+ # On partial updates we shouldn't need to force stores to be persisted. However since
87
+ # we weren't persisting them for a while on insertion, we now need to gracefully deal
88
+ # with existing records that may have been persisted with a `NULL` store
89
+ # We use `blank?` as an heuristic to detect these.
90
+ super | self.class.typed_stores.keys.map(&:to_s).select do |store|
91
+ has_attribute?(store) && read_attribute_before_type_cast(store).blank?
92
+ end
93
+ end
94
+ else
95
+ # Rails 6.1 capability
96
+ def attribute_names_for_partial_writes
97
+ super | self.class.typed_stores.keys.map(&:to_s).select do |store|
98
+ has_attribute?(store) && read_attribute_before_type_cast(store).blank?
99
+ end
91
100
  end
92
101
  end
93
102
  end
@@ -22,7 +22,12 @@ module ActiveRecord::TypedStore
22
22
  typed_klass = TypedHash.create(dsl.fields.values)
23
23
  const_set("#{store_attribute}_hash".camelize, typed_klass)
24
24
 
25
- if ActiveRecord.version >= Gem::Version.new('6.1.0.alpha')
25
+ if ActiveRecord.version >= Gem::Version.new('7.2.0.alpha')
26
+ decorate_attributes([store_attribute]) do |name, subtype|
27
+ subtype = subtype.subtype if subtype.is_a?(Type)
28
+ Type.new(typed_klass, dsl.coder, subtype)
29
+ end
30
+ elsif ActiveRecord.version >= Gem::Version.new('6.1.0.alpha')
26
31
  attribute(store_attribute) do |subtype|
27
32
  subtype = subtype.subtype if subtype.is_a?(Type)
28
33
  Type.new(typed_klass, dsl.coder, subtype)
@@ -11,12 +11,12 @@ module ActiveRecord::TypedStore
11
11
 
12
12
  @accessor = options.fetch(:accessor, true)
13
13
  @name = name
14
+ @array = options.fetch(:array, false)
14
15
  if options.key?(:default)
15
16
  @default = extract_default(options[:default])
16
17
  end
17
18
  @null = options.fetch(:null, true)
18
19
  @blank = options.fetch(:blank, true)
19
- @array = options.fetch(:array, false)
20
20
  end
21
21
 
22
22
  def has_default?
@@ -27,6 +27,8 @@ module ActiveRecord::TypedStore
27
27
  casted_value = type_cast(value)
28
28
  if !blank
29
29
  casted_value = default if casted_value.blank?
30
+ elsif array && has_default?
31
+ casted_value = default if value.nil?
30
32
  elsif !null
31
33
  casted_value = default if casted_value.nil?
32
34
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module TypedStore
5
- VERSION = '1.5.1'
5
+ VERSION = '1.6.0'
6
6
  end
7
7
  end
@@ -524,7 +524,7 @@ shared_examples 'a store' do |retain_type = true, settings_type = :text|
524
524
  describe 'model.typed_stores' do
525
525
  it "can access keys" do
526
526
  stores = model.class.typed_stores
527
- expect(stores[:settings].keys).to eq [:no_default, :name, :email, :cell_phone, :public, :enabled, :age, :max_length, :rate, :price, :published_on, :remind_on, :published_at_time, :remind_at_time, :published_at, :remind_at, :total_price, :shipping_cost, :grades, :tags, :nickname, :author, :source, :signup, :country]
527
+ expect(stores[:settings].keys).to eq [:no_default, :name, :email, :cell_phone, :public, :enabled, :age, :max_length, :rate, :price, :published_on, :remind_on, :published_at_time, :remind_at_time, :published_at, :remind_at, :total_price, :shipping_cost, :grades, :tags, :subjects, :nickname, :author, :source, :signup, :country]
528
528
  end
529
529
 
530
530
  it "can access keys even when accessors are not defined" do
@@ -889,9 +889,15 @@ shared_examples 'a model supporting arrays' do |pg_native=false|
889
889
  expect(model.reload.grades).to be == [[1, 2], [3, 4, 5]]
890
890
  end
891
891
 
892
+ it 'defaults to [] if provided default is not an array' do
893
+ model.update(subjects: nil)
894
+ expect(model.reload.subjects).to be == []
895
+ end
896
+
897
+ # Not sure about pg_native and if this test should be outside of this block.
892
898
  it 'retreive default if assigned null' do
893
899
  model.update(tags: nil)
894
- expect(model.reload.tags).to be == []
900
+ expect(model.reload.tags).to be == ['article']
895
901
  end
896
902
  end
897
903
  end
@@ -958,6 +964,7 @@ end
958
964
  describe DirtyTrackingModel do
959
965
  it 'stores the default on creation' do
960
966
  model = DirtyTrackingModel.create!
967
+ model = DirtyTrackingModel.find(model.id)
961
968
  expect(model.settings_before_type_cast).to_not be_blank
962
969
  end
963
970
 
@@ -973,4 +980,13 @@ describe DirtyTrackingModel do
973
980
  expect(model.settings_changed?).to be false
974
981
  expect(model.changes).to be_empty
975
982
  end
983
+
984
+ it 'does not update missing attributes in partially loaded records' do
985
+ model = DirtyTrackingModel.create!(active: true)
986
+ model = DirtyTrackingModel.select(:id, :title).find(model.id)
987
+ model.update!(title: "Hello")
988
+
989
+ model = DirtyTrackingModel.find(model.id)
990
+ expect(model.active).to be true
991
+ end
976
992
  end
data/spec/spec_helper.rb CHANGED
@@ -9,9 +9,9 @@ Dir[File.expand_path(File.join(File.dirname(__FILE__), 'support', '**', '*.rb'))
9
9
  Time.zone = 'UTC'
10
10
 
11
11
  if ActiveRecord.respond_to?(:yaml_column_permitted_classes)
12
- ActiveRecord.yaml_column_permitted_classes |= ['Date', 'Time', 'BigDecimal']
12
+ ActiveRecord.yaml_column_permitted_classes |= [Date, Time, BigDecimal]
13
13
  elsif ActiveRecord::Base.respond_to?(:yaml_column_permitted_classes)
14
- ActiveRecord::Base.yaml_column_permitted_classes |= ['Date', 'Time', 'BigDecimal']
14
+ ActiveRecord::Base.yaml_column_permitted_classes |= [Date, Time, BigDecimal]
15
15
  end
16
16
 
17
17
  RSpec.configure do |config|
@@ -43,7 +43,8 @@ def define_columns(t, array: false)
43
43
 
44
44
  if t.is_a?(ActiveRecord::TypedStore::DSL)
45
45
  t.integer :grades, array: true
46
- t.string :tags, array: true, null: false, default: [].to_yaml
46
+ t.string :tags, array: true, null: false, default: ['article']
47
+ t.string :subjects, array: true, null: false, default: ['mathematics'].to_yaml
47
48
 
48
49
  t.string :nickname, blank: false, default: 'Please enter your nickname'
49
50
  end
@@ -190,7 +191,7 @@ Models = [
190
191
  ]
191
192
 
192
193
  class DirtyTrackingModel < ActiveRecord::Base
193
- after_update :read_active
194
+ after_update :read_active, if: -> { has_attribute?(:settings) }
194
195
 
195
196
  typed_store(:settings) do |f|
196
197
  f.boolean :active, default: false, null: false
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-typedstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-03 00:00:00.000000000 Z
11
+ date: 2024-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -111,6 +111,7 @@ files:
111
111
  - activerecord-typedstore.gemspec
112
112
  - gemfiles/Gemfile.ar-6.1
113
113
  - gemfiles/Gemfile.ar-7.0
114
+ - gemfiles/Gemfile.ar-7.1
114
115
  - gemfiles/Gemfile.ar-edge
115
116
  - lib/active_record/typed_store.rb
116
117
  - lib/active_record/typed_store/behavior.rb
@@ -146,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
147
  - !ruby/object:Gem::Version
147
148
  version: '0'
148
149
  requirements: []
149
- rubygems_version: 3.3.7
150
+ rubygems_version: 3.5.5
150
151
  signing_key:
151
152
  specification_version: 4
152
153
  summary: Add type casting and full method attributes support to АctiveRecord store