jsonb_accessor 1.3.2 → 1.3.3

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: 5b446e2b5fcf294a928c055c00334951830d068f7161437ec8fcab443cf2cee5
4
- data.tar.gz: 443355750846f163a89307f662cd06d5034b5b922e7305209e8101b879f75b3e
3
+ metadata.gz: f098f30fabf2c5bbbe39acaecc6487c84516837bb8f55ff1ecfcde0bdda24e2f
4
+ data.tar.gz: 9dd89e98ec2937007ca3a11794ad3c0b3d48f8510a8f2836e0a1276b9ba8d5e0
5
5
  SHA512:
6
- metadata.gz: 98019ca7f52229b5ca88a11b29ece4919bdd308a4c101dbc3a1b53ffa9d783ab90d9c09219be7ff7de37641a4545593851ed60da69cfc57dd53dfe6b7ee04238
7
- data.tar.gz: 0e7b87df70bc3fdd71f4e384857970863b89bf60931c623b15b0983e554875cc1581672977bb274f0104fb393052d81447e05db4759826f83255d8cf03f355bd
6
+ metadata.gz: 2f7ca35afa36d13d4907b7e81ccf9c380c9eba36d7a18c6b6a10a1dcc6e423096fd39ab7c69ef372d9a217a01f31530b271e2f5a72ed482be1faa4dcc43806ea
7
+ data.tar.gz: 7389bebb7a9f7d6d4fcbde9cecc339f8505ae5cda68a6dbdd0489f10bcb1172919c9bd60d8bddee9be9a1053867ba99eefafce0be7cbf0022a151f9207fac069
@@ -0,0 +1,92 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: ['**']
8
+
9
+ jobs:
10
+ tests:
11
+ services:
12
+ db:
13
+ image: postgres:9.4
14
+ env:
15
+ POSTGRES_HOST_AUTH_METHOD: trust
16
+ POSTGRES_DB: jsonb_accessor
17
+ ports: ['5432:5432']
18
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
19
+
20
+ runs-on: ubuntu-latest
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ include:
25
+ - gemfile: activerecord_5.0.0
26
+ ruby: 2.4.5
27
+
28
+ - gemfile: activerecord_5.1.0
29
+ ruby: 2.4.5
30
+
31
+ - gemfile: activerecord_5.0.0
32
+ ruby: 2.5.3
33
+
34
+ - gemfile: activerecord_5.1.0
35
+ ruby: 2.5.3
36
+
37
+ - gemfile: activerecord_6.1.0
38
+ ruby: 2.5.3
39
+
40
+ - gemfile: activerecord_5.0.0
41
+ ruby: 2.6.1
42
+
43
+ - gemfile: activerecord_5.1.0
44
+ ruby: 2.6.1
45
+
46
+ - gemfile: activerecord_6.1.0
47
+ ruby: 2.6.1
48
+
49
+ - gemfile: activerecord_5.0.0
50
+ ruby: 2.7.2
51
+
52
+ - gemfile: activerecord_5.1.0
53
+ ruby: 2.7.2
54
+
55
+ - gemfile: activerecord_6.1.0
56
+ ruby: 2.7.2
57
+
58
+ - gemfile: activerecord_7.0.1
59
+ ruby: 2.7.2
60
+
61
+ - gemfile: activerecord_6.1.0
62
+ ruby: 3.0.0
63
+
64
+ - gemfile: activerecord_7.0.1
65
+ ruby: 3.0.0
66
+
67
+ - gemfile: activerecord_7.0.1
68
+ ruby: 3.1.0
69
+
70
+ name: ${{ matrix.gemfile }}, ruby ${{ matrix.ruby }}
71
+
72
+ steps:
73
+ - uses: actions/checkout@v2
74
+
75
+ - name: Set up Ruby
76
+ uses: ruby/setup-ruby@v1
77
+ with:
78
+ ruby-version: ${{ matrix.ruby }}
79
+ bundler-cache: true
80
+
81
+ - name: Bundle install
82
+ run: |
83
+ bundle config set gemfile "${GITHUB_WORKSPACE}/gemfiles/${{ matrix.gemfile }}.gemfile"
84
+ bundle install --jobs 4 --retry 3
85
+
86
+ - name: Setup DB
87
+ run: |
88
+ bundle exec rake db:create db:schema:load
89
+
90
+ - name: Run tests
91
+ run: |
92
+ bundle exec rake spec
data/.rubocop.yml CHANGED
@@ -30,8 +30,6 @@ Metrics/PerceivedComplexity:
30
30
  Enabled: false
31
31
  Metrics/BlockLength:
32
32
  Enabled: false
33
- Security/YAMLLoad:
34
- Enabled: false
35
33
  Style/ClassAndModuleChildren:
36
34
  Enabled: false
37
35
  Style/ClassVars:
@@ -60,3 +58,5 @@ Naming/VariableNumber:
60
58
  Enabled: false
61
59
  Gemspec/RequiredRubyVersion:
62
60
  Enabled: false
61
+ Gemspec/RequireMFA:
62
+ Enabled: false
data/Appraisals CHANGED
@@ -11,3 +11,7 @@ end
11
11
  appraise "activerecord-6.1.0" do
12
12
  gem "activerecord", "~> 6.1"
13
13
  end
14
+
15
+ appraise "activerecord-7.0.1" do
16
+ gem "activerecord", "~> 7.0.1"
17
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+ ## [Unreleased]
3
+
4
+ ## [1.3.3] - 2022-01-29
5
+ ### Fixed
6
+
7
+ - Bug fix: DateTime objects are now correctly written without timezone
8
+ information [#137](https://github.com/madeintandem/jsonb_accessor/pull/137).
9
+ Thanks @caiohsramos
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Created by &nbsp;&nbsp;&nbsp; [<img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/tandem-logo.png" alt="Tandem Logo" />](https://www.madeintandem.com/)
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/jsonb_accessor.svg)](http://badge.fury.io/rb/jsonb_accessor) &nbsp;&nbsp;&nbsp;[![Build Status](https://travis-ci.org/madeintandem/jsonb_accessor.svg)](https://travis-ci.org/madeintandem/jsonb_accessor) <img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/json-bee.png" alt="JSONb Accessor Logo" align="right" />
5
+ [![Gem Version](https://badge.fury.io/rb/jsonb_accessor.svg)](http://badge.fury.io/rb/jsonb_accessor) &nbsp;&nbsp;&nbsp;![CI](https://github.com/madeintandem/jsonb_accessor/actions/workflows/ci.yml/badge.svg) <img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/json-bee.png" alt="JSONb Accessor Logo" align="right" />
6
6
 
7
7
  Adds typed `jsonb` backed fields as first class citizens to your `ActiveRecord` models. This gem is similar in spirit to [HstoreAccessor](https://github.com/madeintandem/hstore_accessor), but the `jsonb` column in PostgreSQL has a few distinct advantages, mostly around nested documents and support for collections.
8
8
 
data/Rakefile CHANGED
@@ -19,7 +19,7 @@ root = File.expand_path __dir__
19
19
  db_dir = File.join(root, "db")
20
20
  DatabaseTasks.root = root
21
21
  DatabaseTasks.db_dir = db_dir
22
- DatabaseTasks.database_configuration = YAML.load(ERB.new(File.read(File.join(db_dir, "config.yml"))).result)
22
+ DatabaseTasks.database_configuration = YAML.safe_load(ERB.new(File.read(File.join(db_dir, "config.yml"))).result, aliases: true)
23
23
  DatabaseTasks.migrations_paths = [File.join(db_dir, "migrate")]
24
24
  DatabaseTasks.env = "test"
25
25
 
data/bin/console CHANGED
@@ -6,7 +6,7 @@ require "jsonb_accessor"
6
6
  require "rspec"
7
7
  require File.expand_path("../spec/spec_helper.rb", __dir__)
8
8
 
9
- dbconfig = YAML.load(File.open("db/config.yml"))
9
+ dbconfig = YAML.safe_load(ERB.new(File.read(File.join("db", "config.yml"))).result, aliases: true)
10
10
  ActiveRecord::Base.establish_connection(dbconfig["development"])
11
11
 
12
12
  # rubocop:disable Lint/UselessAssignment
data/docker-compose.yml CHANGED
@@ -13,6 +13,7 @@ services:
13
13
  depends_on:
14
14
  - postgres
15
15
 
16
+
16
17
  postgres:
17
18
  image: postgres:12
18
19
  environment:
@@ -21,6 +22,8 @@ services:
21
22
  - PGDATA=/var/lib/postgresql/data/pgdata
22
23
  volumes:
23
24
  - pg_data:/var/lib/postgresql/data/pgdata
25
+ ports:
26
+ - 5432:5432
24
27
 
25
28
  volumes:
26
29
  pg_data:
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "pg"
6
+ gem "activerecord", "~> 7.0.1"
7
+
8
+ gemspec path: "../"
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "pry"
32
32
  spec.add_development_dependency "pry-doc"
33
33
  spec.add_development_dependency "pry-nav"
34
+ spec.add_development_dependency "psych", "~> 3"
34
35
  spec.add_development_dependency "rake", ">= 12.3.3"
35
36
  spec.add_development_dependency "rspec", "~> 3.6.0"
36
37
  spec.add_development_dependency "rubocop", "~> 1"
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JsonbAccessor
4
+ class AttributeQueryMethods
5
+ def initialize(klass)
6
+ @klass = klass
7
+ end
8
+
9
+ def define(store_key_mapping_method_name, jsonb_attribute)
10
+ return if klass.superclass.respond_to? store_key_mapping_method_name
11
+
12
+ # <jsonb_attribute>_where scope
13
+ klass.define_singleton_method "#{jsonb_attribute}_where" do |attributes|
14
+ store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
15
+ jsonb_where(jsonb_attribute, store_key_attributes)
16
+ end
17
+
18
+ # <jsonb_attribute>_where_not scope
19
+ klass.define_singleton_method "#{jsonb_attribute}_where_not" do |attributes|
20
+ store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
21
+ jsonb_where_not(jsonb_attribute, store_key_attributes)
22
+ end
23
+
24
+ # <jsonb_attribute>_order scope
25
+ klass.define_singleton_method "#{jsonb_attribute}_order" do |*args|
26
+ ordering_options = args.extract_options!
27
+ order_by_defaults = args.each_with_object({}) { |attribute, config| config[attribute] = :asc }
28
+ store_key_mapping = all.model.public_send(store_key_mapping_method_name)
29
+
30
+ order_by_defaults.merge(ordering_options).reduce(all) do |query, (name, direction)|
31
+ key = store_key_mapping[name.to_s]
32
+ order_query = jsonb_order(jsonb_attribute, key, direction)
33
+ query.merge(order_query)
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :klass
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ module JsonbAccessor
2
+ module Helpers
3
+ module_function
4
+
5
+ def active_record_default_timezone
6
+ ActiveRecord.try(:default_timezone) || ActiveRecord::Base.default_timezone
7
+ end
8
+ end
9
+ end
@@ -65,7 +65,14 @@ module JsonbAccessor
65
65
  names_and_store_keys.each do |name, store_key|
66
66
  define_method("#{name}=") do |value|
67
67
  super(value)
68
- new_values = (public_send(jsonb_attribute) || {}).merge(store_key => public_send(name))
68
+
69
+ attribute_value = public_send(name)
70
+ # Rails always saves time based on `default_timezone`. Since #as_json considers timezone, manual conversion is needed
71
+ if attribute_value.acts_like?(:time)
72
+ attribute_value = (::JsonbAccessor::Helpers.active_record_default_timezone == :utc ? attribute_value.utc : attribute_value.in_time_zone).strftime("%F %R:%S.%L")
73
+ end
74
+
75
+ new_values = (public_send(jsonb_attribute) || {}).merge(store_key => attribute_value)
69
76
  write_attribute(jsonb_attribute, new_values)
70
77
  end
71
78
  end
@@ -74,21 +81,20 @@ module JsonbAccessor
74
81
  define_method("#{jsonb_attribute}=") do |value|
75
82
  value ||= {}
76
83
  names_to_store_keys = self.class.public_send(store_key_mapping_method_name)
77
- store_keys_to_names = names_to_store_keys.invert
78
84
 
79
85
  # this is the raw hash we want to save in the jsonb_attribute
80
- value_with_store_keys = value.transform_keys do |k|
81
- names_to_store_keys[k.to_s] || k
82
- end
86
+ value_with_store_keys = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(value, names_to_store_keys)
83
87
  write_attribute(jsonb_attribute, value_with_store_keys)
84
88
 
85
89
  # this maps attributes to values
86
- value_with_named_keys = value.transform_keys do |k|
87
- store_keys_to_names[k.to_s] || k
88
- end
90
+ value_with_named_keys = ::JsonbAccessor::QueryHelper.convert_store_keys_to_keys(value, names_to_store_keys)
89
91
 
90
92
  empty_named_attributes = names_to_store_keys.transform_values { nil }
91
93
  empty_named_attributes.merge(value_with_named_keys).each do |name, attribute_value|
94
+ # Undefined keys: There might be things in the JSON that haven't been defined using jsonb_accessor
95
+ # It should still be possible to save arbitrary data in the JSON
96
+ next unless has_attribute? name
97
+
92
98
  write_attribute(name, attribute_value)
93
99
  end
94
100
  end
@@ -97,42 +103,19 @@ module JsonbAccessor
97
103
 
98
104
  # Makes sure new objects have the appropriate values in their jsonb fields.
99
105
  after_initialize do
100
- if has_attribute?(jsonb_attribute)
101
- jsonb_values = public_send(jsonb_attribute) || {}
102
- jsonb_values.each do |store_key, value|
103
- name = names_and_store_keys.key(store_key)
104
- next unless name
105
-
106
- write_attribute(name, value)
107
- clear_attribute_change(name) if persisted?
108
- end
106
+ next unless jsonb_attribute
107
+
108
+ jsonb_values = public_send(jsonb_attribute) || {}
109
+ jsonb_values.each do |store_key, value|
110
+ name = names_and_store_keys.key(store_key)
111
+ next unless name
112
+
113
+ write_attribute(name, value)
114
+ clear_attribute_change(name) if persisted?
109
115
  end
110
116
  end
111
117
 
112
- # <jsonb_attribute>_where scope
113
- scope("#{jsonb_attribute}_where", lambda do |attributes|
114
- store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
115
- jsonb_where(jsonb_attribute, store_key_attributes)
116
- end)
117
-
118
- # <jsonb_attribute>_where_not scope
119
- scope("#{jsonb_attribute}_where_not", lambda do |attributes|
120
- store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
121
- jsonb_where_not(jsonb_attribute, store_key_attributes)
122
- end)
123
-
124
- # <jsonb_attribute>_order scope
125
- scope("#{jsonb_attribute}_order", lambda do |*args|
126
- ordering_options = args.extract_options!
127
- order_by_defaults = args.each_with_object({}) { |attribute, config| config[attribute] = :asc }
128
- store_key_mapping = all.model.public_send(store_key_mapping_method_name)
129
-
130
- order_by_defaults.merge(ordering_options).reduce(all) do |query, (name, direction)|
131
- key = store_key_mapping[name.to_s]
132
- order_query = jsonb_order(jsonb_attribute, key, direction)
133
- query.merge(order_query)
134
- end
135
- end)
118
+ ::JsonbAccessor::AttributeQueryMethods.new(self).define(store_key_mapping_method_name, jsonb_attribute)
136
119
  end
137
120
  end
138
121
  end
@@ -57,13 +57,18 @@ module JsonbAccessor
57
57
  raise InvalidDirection, "`#{option}` is not a valid direction for ordering, only `asc` and `desc` are accepted" if ORDER_DIRECTIONS.exclude?(option)
58
58
  end
59
59
 
60
+ # Replaces all keys in `attributes` that have a defined store_key with the store_key
60
61
  def convert_keys_to_store_keys(attributes, store_key_mapping)
61
- attributes.each_with_object({}) do |(name, value), new_attributes|
62
- store_key = store_key_mapping[name.to_s]
63
- new_attributes[store_key] = value
62
+ attributes.stringify_keys.transform_keys do |key|
63
+ store_key_mapping[key] || key
64
64
  end
65
65
  end
66
66
 
67
+ # Replaces all keys in `attributes` that have a defined store_key with the named key (alias)
68
+ def convert_store_keys_to_keys(attributes, store_key_mapping)
69
+ convert_keys_to_store_keys(attributes, store_key_mapping.invert)
70
+ end
71
+
67
72
  def number_query_arguments?(arg)
68
73
  arg.is_a?(Hash) && arg.keys.map(&:to_s).all? { |key| NUMBER_OPERATORS.include?(key) }
69
74
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JsonbAccessor
4
- VERSION = "1.3.2"
4
+ VERSION = "1.3.3"
5
5
  end
@@ -5,9 +5,11 @@ require "active_record"
5
5
  require "active_record/connection_adapters/postgresql_adapter"
6
6
 
7
7
  require "jsonb_accessor/version"
8
+ require "jsonb_accessor/helpers"
8
9
  require "jsonb_accessor/macro"
9
10
  require "jsonb_accessor/query_helper"
10
11
  require "jsonb_accessor/query_builder"
12
+ require "jsonb_accessor/attribute_query_methods"
11
13
 
12
14
  module JsonbAccessor
13
15
  extend ActiveSupport::Concern
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonb_accessor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Crismali
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-05-12 00:00:00.000000000 Z
13
+ date: 2022-01-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -138,6 +138,20 @@ dependencies:
138
138
  - - ">="
139
139
  - !ruby/object:Gem::Version
140
140
  version: '0'
141
+ - !ruby/object:Gem::Dependency
142
+ name: psych
143
+ requirement: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - "~>"
146
+ - !ruby/object:Gem::Version
147
+ version: '3'
148
+ type: :development
149
+ prerelease: false
150
+ version_requirements: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - "~>"
153
+ - !ruby/object:Gem::Version
154
+ version: '3'
141
155
  - !ruby/object:Gem::Dependency
142
156
  name: rake
143
157
  requirement: !ruby/object:Gem::Requirement
@@ -189,12 +203,13 @@ executables: []
189
203
  extensions: []
190
204
  extra_rdoc_files: []
191
205
  files:
206
+ - ".github/workflows/ci.yml"
192
207
  - ".gitignore"
193
208
  - ".rspec"
194
209
  - ".rubocop.yml"
195
210
  - ".ruby-version"
196
- - ".travis.yml"
197
211
  - Appraisals
212
+ - CHANGELOG.md
198
213
  - CODE_OF_CONDUCT.md
199
214
  - Dockerfile
200
215
  - Gemfile
@@ -211,8 +226,11 @@ files:
211
226
  - gemfiles/activerecord_5.0.0.gemfile
212
227
  - gemfiles/activerecord_5.1.0.gemfile
213
228
  - gemfiles/activerecord_6.1.0.gemfile
229
+ - gemfiles/activerecord_7.0.1.gemfile
214
230
  - jsonb_accessor.gemspec
215
231
  - lib/jsonb_accessor.rb
232
+ - lib/jsonb_accessor/attribute_query_methods.rb
233
+ - lib/jsonb_accessor/helpers.rb
216
234
  - lib/jsonb_accessor/macro.rb
217
235
  - lib/jsonb_accessor/query_builder.rb
218
236
  - lib/jsonb_accessor/query_helper.rb
data/.travis.yml DELETED
@@ -1,30 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.4.5
4
- - 2.5.3
5
- - 2.6.1
6
- - 2.7.2
7
- - 3.0.0
8
- addons:
9
- postgresql: "9.4"
10
- before_install:
11
- - gem update --system
12
- - gem --version
13
- - gem install bundler:2.1.4
14
- before_script:
15
- - bundle exec rake db:create
16
- - bundle exec rake db:migrate
17
- install: bundle _2.1.4_ install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
18
- cache: bundler
19
- gemfile:
20
- - gemfiles/activerecord_5.0.0.gemfile
21
- - gemfiles/activerecord_5.1.0.gemfile
22
- - gemfiles/activerecord_6.1.0.gemfile
23
- jobs:
24
- exclude:
25
- - rvm: 2.4.5
26
- gemfile: gemfiles/activerecord_6.1.0.gemfile
27
- - rvm: 3.0.0
28
- gemfile: gemfiles/activerecord_5.0.0.gemfile
29
- - rvm: 3.0.0
30
- gemfile: gemfiles/activerecord_5.1.0.gemfile