activerecord-typedstore 1.5.1 → 1.6.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
  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