jsonb_accessor 1.3.2 → 1.3.3

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: 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