jsonb_accessor 1.2.0 → 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
- SHA1:
3
- metadata.gz: 80ed7aa0b3f529122a97b2a00b4f81011ef18014
4
- data.tar.gz: 407d572cea056870ce66d7b92c89d1b3e15bdb2d
2
+ SHA256:
3
+ metadata.gz: f098f30fabf2c5bbbe39acaecc6487c84516837bb8f55ff1ecfcde0bdda24e2f
4
+ data.tar.gz: 9dd89e98ec2937007ca3a11794ad3c0b3d48f8510a8f2836e0a1276b9ba8d5e0
5
5
  SHA512:
6
- metadata.gz: be4ffe5fc2318edc84b98ffee5296d30d2a9d03817540c4622f04875d0a41c19022c19c0c998357f6730cad37103ce79c43b46c5aa08a46dce8078b77f03752d
7
- data.tar.gz: c02e7189b7354d5d112aa9414e9cb4e5329d57b97b75b4d07a7e64da1abab04c63a0419509335fd557728eb48df1183d2a2d00c9c84ed7216ac4461205ec1c4d
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
@@ -1,11 +1,16 @@
1
1
  AllCops:
2
- Include:
3
- - "**/Rakefile"
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.7.2
4
+ SuggestExtensions: false
4
5
  Exclude:
5
- - db/**/*
6
- - gemfiles/**/*
7
- - vendor/**/*
8
- Style/SpaceBeforeFirstArg:
6
+ - "db/**/*"
7
+ - "gemfiles/**/*"
8
+ - "vendor/**/*"
9
+ Layout/SpaceBeforeFirstArg:
10
+ Enabled: false
11
+ Layout/LineLength:
12
+ Enabled: false
13
+ Layout/SpaceAroundEqualsInParameterDefault:
9
14
  Enabled: false
10
15
  Lint/UnusedBlockArgument:
11
16
  Enabled: false
@@ -17,8 +22,6 @@ Metrics/ClassLength:
17
22
  Enabled: false
18
23
  Metrics/CyclomaticComplexity:
19
24
  Enabled: false
20
- Metrics/LineLength:
21
- Enabled: false
22
25
  Metrics/MethodLength:
23
26
  Enabled: false
24
27
  Metrics/ModuleLength:
@@ -27,10 +30,6 @@ Metrics/PerceivedComplexity:
27
30
  Enabled: false
28
31
  Metrics/BlockLength:
29
32
  Enabled: false
30
- Security/YAMLLoad:
31
- Enabled: false
32
- Style/AlignParameters:
33
- Enabled: false
34
33
  Style/ClassAndModuleChildren:
35
34
  Enabled: false
36
35
  Style/ClassVars:
@@ -39,25 +38,25 @@ Style/Documentation:
39
38
  Enabled: false
40
39
  Style/DoubleNegation:
41
40
  Enabled: false
42
- Style/FileName:
41
+ Naming/FileName:
43
42
  Enabled: false
44
43
  Style/GuardClause:
45
44
  Enabled: false
46
- Style/IndentHash:
47
- Enabled: false
48
45
  Style/NilComparison:
49
46
  Enabled: false
50
- Style/OpMethod:
51
- Enabled: false
52
47
  Style/RescueModifier:
53
48
  Enabled: false
54
49
  Style/SignalException:
55
50
  Enabled: false
56
51
  Style/SingleLineMethods:
57
52
  Enabled: false
58
- Style/SpaceAroundEqualsInParameterDefault:
59
- Enabled: false
60
53
  Style/StringLiterals:
61
54
  EnforcedStyle: double_quotes
62
- Performance/EndWith:
55
+ Naming/BinaryOperatorParameterName:
56
+ Enabled: false
57
+ Naming/VariableNumber:
58
+ Enabled: false
59
+ Gemspec/RequiredRubyVersion:
60
+ Enabled: false
61
+ Gemspec/RequireMFA:
63
62
  Enabled: false
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.4.1
1
+ 2.7.2
data/Appraisals CHANGED
@@ -7,3 +7,11 @@ end
7
7
  appraise "activerecord-5.1.0" do
8
8
  gem "activerecord", "~> 5.1.3"
9
9
  end
10
+
11
+ appraise "activerecord-6.1.0" do
12
+ gem "activerecord", "~> 6.1"
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/Dockerfile ADDED
@@ -0,0 +1,12 @@
1
+ ARG RUBY_VERSION=latest
2
+ FROM ruby:${RUBY_VERSION}
3
+
4
+ WORKDIR /usr/src/app
5
+
6
+ RUN mkdir -p lib/jsonb_accessor
7
+ COPY lib/jsonb_accessor/version.rb ./lib/jsonb_accessor/
8
+ COPY *.gemspec Gemfile* ./
9
+
10
+ RUN bundle install
11
+
12
+ COPY . .
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
 
@@ -10,15 +10,15 @@ It also adds generic scopes for querying `jsonb` columns.
10
10
 
11
11
  ## Table of Contents
12
12
 
13
- * [Installation](#installation)
14
- * [Usage](#usage)
15
- * [Scopes](#scopes)
16
- * [Single-Table Inheritance](#single-table-inheritance)
17
- * [Dependencies](#dependencies)
18
- * [Validations](#validations)
19
- * [Upgrading](#upgrading)
20
- * [Development](#development)
21
- * [Contributing](#contributing)
13
+ - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ - [Scopes](#scopes)
16
+ - [Single-Table Inheritance](#single-table-inheritance)
17
+ - [Dependencies](#dependencies)
18
+ - [Validations](#validations)
19
+ - [Upgrading](#upgrading)
20
+ - [Development](#development)
21
+ - [Contributing](#contributing)
22
22
 
23
23
  ## Installation
24
24
 
@@ -158,6 +158,7 @@ Product.all.jsonb_where(:data, reviewed_at: { before: Time.current }, p: { great
158
158
 
159
159
  Product.all.data_where(reviewed_at: { before: Time.current }, price: { greater_than: 5 })
160
160
  ```
161
+
161
162
  This scope makes use of the `jsonb_contains`, `jsonb_number_where`, and `jsonb_time_where` `scope`s.
162
163
 
163
164
  ### `jsonb_where_not`
@@ -219,14 +220,14 @@ Product.all.jsonb_number_where(:data, :price_in_cents, :greater_than, 300)
219
220
 
220
221
  It supports:
221
222
 
222
- * `>`
223
- * `>=`
224
- * `greater_than`
225
- * `greater_than_or_equal_to`
226
- * `<`
227
- * `<=`
228
- * `less_than`
229
- * `less_than_or_equal_to`
223
+ - `>`
224
+ - `>=`
225
+ - `greater_than`
226
+ - `greater_than_or_equal_to`
227
+ - `<`
228
+ - `<=`
229
+ - `less_than`
230
+ - `less_than_or_equal_to`
230
231
 
231
232
  and it is indifferent to strings/symbols.
232
233
 
@@ -259,9 +260,9 @@ Product.all.jsonb_time_where_not(:data, :reviewed_at, :before, 2.days.ago)
259
260
  ## Single-Table Inheritance
260
261
 
261
262
  One of the big issues with `ActiveRecord` single-table inheritance (STI)
262
- is sparse columns. Essentially, as sub-types of the original table
263
+ is sparse columns. Essentially, as sub-types of the original table
263
264
  diverge further from their parent more columns are left empty in a given
264
- table. Postgres' `jsonb` type provides part of the solution in that
265
+ table. Postgres' `jsonb` type provides part of the solution in that
265
266
  the values in an `jsonb` column does not impose a structure - different
266
267
  rows can have different values.
267
268
 
@@ -305,7 +306,7 @@ end
305
306
  ```
306
307
 
307
308
  From here any attributes specific to any sub-class can be stored in the
308
- `jsonb` column avoiding sparse data. Indices can also be created on
309
+ `jsonb` column avoiding sparse data. Indices can also be created on
309
310
  individual fields in an `jsonb` column.
310
311
 
311
312
  This approach was originally conceived by Joe Hirn in [this blog
@@ -326,12 +327,24 @@ See the [upgrade guide](UPGRADE_GUIDE.md).
326
327
 
327
328
  ## Development
328
329
 
330
+ ### On your local machine
331
+
329
332
  After checking out the repo, run `bin/setup` to install dependencies (make sure postgres is running first).
330
333
 
331
334
  Run `bin/console` for an interactive prompt that will allow you to experiment.
332
335
 
333
336
  `rake` will run Rubocop and the specs.
334
337
 
338
+ ### With Docker
339
+
340
+ ```
341
+ # setup
342
+ docker-compose build
343
+ docker-compose run ruby rake db:migrate
344
+ # run test suite
345
+ docker-compose run ruby rake spec
346
+ ```
347
+
335
348
  ## Contributing
336
349
 
337
350
  1. [Fork it](https://github.com/madeintandem/jsonb_accessor/fork)
data/Rakefile CHANGED
@@ -5,10 +5,29 @@ require "bundler/setup"
5
5
  require "bundler/gem_tasks"
6
6
  require "rspec/core/rake_task"
7
7
  require "rubocop/rake_task"
8
- require "standalone_migrations"
9
- StandaloneMigrations::Tasks.load_tasks
8
+ require "active_record"
9
+ require "erb"
10
10
 
11
11
  RSpec::Core::RakeTask.new
12
12
  RuboCop::RakeTask.new
13
13
 
14
+ # rubocop:disable Style/MixinUsage
15
+ include ActiveRecord::Tasks
16
+ # rubocop:enable Style/MixinUsage
17
+
18
+ root = File.expand_path __dir__
19
+ db_dir = File.join(root, "db")
20
+ DatabaseTasks.root = root
21
+ DatabaseTasks.db_dir = db_dir
22
+ DatabaseTasks.database_configuration = YAML.safe_load(ERB.new(File.read(File.join(db_dir, "config.yml"))).result, aliases: true)
23
+ DatabaseTasks.migrations_paths = [File.join(db_dir, "migrate")]
24
+ DatabaseTasks.env = "test"
25
+
26
+ task :environment do
27
+ ActiveRecord::Base.configurations = DatabaseTasks.database_configuration
28
+ ActiveRecord::Base.establish_connection DatabaseTasks.env.to_sym
29
+ end
30
+
31
+ load "active_record/railties/databases.rake"
32
+
14
33
  task(default: %i[rubocop spec])
data/bin/console CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- # rubocop:disable Lint/UselessAssignment
5
-
6
4
  require "bundler/setup"
7
5
  require "jsonb_accessor"
8
6
  require "rspec"
9
- require File.expand_path("../../spec/spec_helper.rb", __FILE__)
7
+ require File.expand_path("../spec/spec_helper.rb", __dir__)
10
8
 
11
- 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)
12
10
  ActiveRecord::Base.establish_connection(dbconfig["development"])
13
11
 
12
+ # rubocop:disable Lint/UselessAssignment
14
13
  x = Product.new
14
+ # rubocop:enable Lint/UselessAssignment
15
15
 
16
16
  Pry.start
data/db/config.yml CHANGED
@@ -1,9 +1,8 @@
1
1
  default: &default
2
2
  adapter: postgresql
3
3
  database: jsonb_accessor
4
-
5
- development:
6
- <<: *default
4
+ host: <%= ENV.fetch("DATABASE_HOST") { "127.0.0.1" } %>
5
+ user: postgres
7
6
 
8
7
  test:
9
8
  <<: *default
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class SetUpTestingDb < ActiveRecord::Migration[5.0]
2
4
  def change
3
5
  create_table :products do |t|
data/db/schema.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is auto-generated from the current state of the database. Instead
2
4
  # of editing this file, please use the migrations feature of Active Record to
3
5
  # incrementally modify your database, and then regenerate this schema definition.
@@ -10,8 +12,7 @@
10
12
  #
11
13
  # It's strongly recommended that you check this file into your version control system.
12
14
 
13
- ActiveRecord::Schema.define(version: 20150407031737) do
14
-
15
+ ActiveRecord::Schema.define(version: 20_150_407_031_737) do
15
16
  # These are extensions that must be enabled in order to support this database
16
17
  enable_extension "plpgsql"
17
18
 
@@ -32,5 +33,4 @@ ActiveRecord::Schema.define(version: 20150407031737) do
32
33
  t.datetime "datetime_type"
33
34
  t.decimal "decimal_type"
34
35
  end
35
-
36
36
  end
@@ -0,0 +1,29 @@
1
+ version: '3'
2
+
3
+ services:
4
+ ruby:
5
+ environment:
6
+ - DATABASE_HOST=postgres
7
+ build:
8
+ args:
9
+ - RUBY_VERSION=${RUBY_VERSION:-2.7.2}
10
+ context: .
11
+ volumes:
12
+ - '.:/usr/src/app'
13
+ depends_on:
14
+ - postgres
15
+
16
+
17
+ postgres:
18
+ image: postgres:12
19
+ environment:
20
+ - POSTGRES_HOST_AUTH_METHOD=trust
21
+ - POSTGRES_DB=jsonb_accessor
22
+ - PGDATA=/var/lib/postgresql/data/pgdata
23
+ volumes:
24
+ - pg_data:/var/lib/postgresql/data/pgdata
25
+ ports:
26
+ - 5432:5432
27
+
28
+ volumes:
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", "~> 6.1"
7
+
8
+ gemspec path: "../"
@@ -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: "../"
@@ -1,7 +1,6 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
5
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
5
  require "jsonb_accessor/version"
7
6
 
@@ -15,7 +14,7 @@ Gem::Specification.new do |spec|
15
14
  spec.description = "Adds typed jsonb backed fields to your ActiveRecord models."
16
15
  spec.homepage = "https://github.com/devmynd/jsonb_accessor"
17
16
  spec.license = "MIT"
18
- spec.required_ruby_version = "~> 2.0"
17
+ spec.required_ruby_version = ">= 2"
19
18
 
20
19
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) || f.match(/png\z/) }
21
20
  spec.bindir = "exe"
@@ -27,14 +26,13 @@ Gem::Specification.new do |spec|
27
26
  spec.add_dependency "pg", ">= 0.18.1"
28
27
 
29
28
  spec.add_development_dependency "appraisal", "~> 2.2.0"
30
- spec.add_development_dependency "bundler", "~> 2.1.4"
31
- spec.add_development_dependency "database_cleaner", "~> 1.6.0"
32
29
  spec.add_development_dependency "awesome_print"
30
+ spec.add_development_dependency "database_cleaner", "~> 1.6.0"
33
31
  spec.add_development_dependency "pry"
34
32
  spec.add_development_dependency "pry-doc"
35
33
  spec.add_development_dependency "pry-nav"
34
+ spec.add_development_dependency "psych", "~> 3"
36
35
  spec.add_development_dependency "rake", ">= 12.3.3"
37
36
  spec.add_development_dependency "rspec", "~> 3.6.0"
38
- spec.add_development_dependency "rubocop", "~> 0.48.1"
39
- spec.add_development_dependency "standalone_migrations", "~> 5.2.0"
37
+ spec.add_development_dependency "rubocop", "~> 1"
40
38
  end
@@ -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
@@ -55,7 +55,7 @@ module JsonbAccessor
55
55
  # each time it is evaluated.
56
56
  all_defaults_mapping_proc =
57
57
  if all_defaults_mapping.present?
58
- -> { all_defaults_mapping.map { |key, value| [key, value.respond_to?(:call) ? value.call : value] }.to_h }
58
+ -> { all_defaults_mapping.transform_values { |value| value.respond_to?(:call) ? value.call : value }.to_h.compact }
59
59
  end
60
60
  attribute jsonb_attribute, :jsonb, default: all_defaults_mapping_proc if all_defaults_mapping_proc.present?
61
61
 
@@ -65,65 +65,57 @@ 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
72
79
 
73
80
  # Overrides the jsonb attribute setter to make sure the jsonb fields are kept in sync.
74
- define_method("#{jsonb_attribute}=") do |given_value|
75
- value = given_value || {}
81
+ define_method("#{jsonb_attribute}=") do |value|
82
+ value ||= {}
76
83
  names_to_store_keys = self.class.public_send(store_key_mapping_method_name)
77
84
 
78
- empty_store_key_attributes = names_to_store_keys.values.each_with_object({}) { |name, defaults| defaults[name] = nil }
79
- empty_named_attributes = names_to_store_keys.keys.each_with_object({}) { |name, defaults| defaults[name] = nil }
85
+ # this is the raw hash we want to save in the jsonb_attribute
86
+ value_with_store_keys = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(value, names_to_store_keys)
87
+ write_attribute(jsonb_attribute, value_with_store_keys)
80
88
 
81
- store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(value, names_to_store_keys)
82
- write_attribute(jsonb_attribute, empty_store_key_attributes.merge(store_key_attributes))
89
+ # this maps attributes to values
90
+ value_with_named_keys = ::JsonbAccessor::QueryHelper.convert_store_keys_to_keys(value, names_to_store_keys)
83
91
 
84
- empty_named_attributes.merge(value).each { |name, attribute_value| write_attribute(name, attribute_value) }
92
+ empty_named_attributes = names_to_store_keys.transform_values { nil }
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
+
98
+ write_attribute(name, attribute_value)
99
+ end
85
100
  end
86
101
  end
87
102
  include setters
88
103
 
89
104
  # Makes sure new objects have the appropriate values in their jsonb fields.
90
105
  after_initialize do
91
- if has_attribute?(jsonb_attribute)
92
- jsonb_values = public_send(jsonb_attribute) || {}
93
- jsonb_values.each do |store_key, value|
94
- name = names_and_store_keys.key(store_key)
95
- next unless name
96
-
97
- write_attribute(name, value)
98
- clear_attribute_change(name) if persisted?
99
- 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?
100
115
  end
101
116
  end
102
117
 
103
- # <jsonb_attribute>_where scope
104
- scope("#{jsonb_attribute}_where", lambda do |attributes|
105
- store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
106
- jsonb_where(jsonb_attribute, store_key_attributes)
107
- end)
108
-
109
- # <jsonb_attribute>_where_not scope
110
- scope("#{jsonb_attribute}_where_not", lambda do |attributes|
111
- store_key_attributes = ::JsonbAccessor::QueryHelper.convert_keys_to_store_keys(attributes, all.model.public_send(store_key_mapping_method_name))
112
- jsonb_where_not(jsonb_attribute, store_key_attributes)
113
- end)
114
-
115
- # <jsonb_attribute>_order scope
116
- scope("#{jsonb_attribute}_order", lambda do |*args|
117
- ordering_options = args.extract_options!
118
- order_by_defaults = args.each_with_object({}) { |attribute, config| config[attribute] = :asc }
119
- store_key_mapping = all.model.public_send(store_key_mapping_method_name)
120
-
121
- order_by_defaults.merge(ordering_options).reduce(all) do |query, (name, direction)|
122
- key = store_key_mapping[name.to_s]
123
- order_query = jsonb_order(jsonb_attribute, key, direction)
124
- query.merge(order_query)
125
- end
126
- end)
118
+ ::JsonbAccessor::AttributeQueryMethods.new(self).define(store_key_mapping_method_name, jsonb_attribute)
127
119
  end
128
120
  end
129
121
  end
@@ -61,9 +61,7 @@ module JsonbAccessor
61
61
  excludes_attributes = {}
62
62
 
63
63
  attributes.each do |name, value|
64
- if value.is_a?(Range)
65
- raise JsonbAccessor::QueryHelper::NotSupported, "`jsonb_where_not` scope does not accept ranges as arguments. Given `#{value}` for `#{name}` field"
66
- end
64
+ raise JsonbAccessor::QueryHelper::NotSupported, "`jsonb_where_not` scope does not accept ranges as arguments. Given `#{value}` for `#{name}` field" if value.is_a?(Range)
67
65
 
68
66
  if JsonbAccessor::QueryHelper.number_query_arguments?(value)
69
67
  value.each { |operator, query_value| query = query.jsonb_number_where_not(column_name, name, operator, query_value) }
@@ -42,9 +42,7 @@ module JsonbAccessor
42
42
 
43
43
  class << self
44
44
  def validate_column_name!(query, column_name)
45
- if query.model.columns.none? { |column| column.name == column_name.to_s }
46
- raise InvalidColumnName, "a column named `#{column_name}` does not exist on the `#{query.model.table_name}` table"
47
- end
45
+ raise InvalidColumnName, "a column named `#{column_name}` does not exist on the `#{query.model.table_name}` table" if query.model.columns.none? { |column| column.name == column_name.to_s }
48
46
  end
49
47
 
50
48
  def validate_field_name!(query, column_name, field_name)
@@ -56,18 +54,21 @@ module JsonbAccessor
56
54
  end
57
55
 
58
56
  def validate_direction!(option)
59
- if ORDER_DIRECTIONS.exclude?(option)
60
- raise InvalidDirection, "`#{option}` is not a valid direction for ordering, only `asc` and `desc` are accepted"
61
- end
57
+ raise InvalidDirection, "`#{option}` is not a valid direction for ordering, only `asc` and `desc` are accepted" if ORDER_DIRECTIONS.exclude?(option)
62
58
  end
63
59
 
60
+ # Replaces all keys in `attributes` that have a defined store_key with the store_key
64
61
  def convert_keys_to_store_keys(attributes, store_key_mapping)
65
- attributes.each_with_object({}) do |(name, value), new_attributes|
66
- store_key = store_key_mapping[name.to_s]
67
- new_attributes[store_key] = value
62
+ attributes.stringify_keys.transform_keys do |key|
63
+ store_key_mapping[key] || key
68
64
  end
69
65
  end
70
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
+
71
72
  def number_query_arguments?(arg)
72
73
  arg.is_a?(Hash) && arg.keys.map(&:to_s).all? { |key| NUMBER_OPERATORS.include?(key) }
73
74
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JsonbAccessor
4
- VERSION = "1.2.0"
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
@@ -15,6 +17,6 @@ module JsonbAccessor
15
17
  end
16
18
 
17
19
  ActiveSupport.on_load(:active_record) do
18
- ActiveRecord::Base.send(:include, JsonbAccessor)
19
- ActiveRecord::Base.send(:include, JsonbAccessor::QueryBuilder)
20
+ ActiveRecord::Base.include JsonbAccessor
21
+ ActiveRecord::Base.include JsonbAccessor::QueryBuilder
20
22
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonb_accessor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Crismali
8
8
  - Joe Hirn
9
9
  - Jason Haruska
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-05-03 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
@@ -69,19 +69,19 @@ dependencies:
69
69
  - !ruby/object:Gem::Version
70
70
  version: 2.2.0
71
71
  - !ruby/object:Gem::Dependency
72
- name: bundler
72
+ name: awesome_print
73
73
  requirement: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - "~>"
75
+ - - ">="
76
76
  - !ruby/object:Gem::Version
77
- version: 2.1.4
77
+ version: '0'
78
78
  type: :development
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - "~>"
82
+ - - ">="
83
83
  - !ruby/object:Gem::Version
84
- version: 2.1.4
84
+ version: '0'
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: database_cleaner
87
87
  requirement: !ruby/object:Gem::Requirement
@@ -97,7 +97,7 @@ dependencies:
97
97
  - !ruby/object:Gem::Version
98
98
  version: 1.6.0
99
99
  - !ruby/object:Gem::Dependency
100
- name: awesome_print
100
+ name: pry
101
101
  requirement: !ruby/object:Gem::Requirement
102
102
  requirements:
103
103
  - - ">="
@@ -111,7 +111,7 @@ dependencies:
111
111
  - !ruby/object:Gem::Version
112
112
  version: '0'
113
113
  - !ruby/object:Gem::Dependency
114
- name: pry
114
+ name: pry-doc
115
115
  requirement: !ruby/object:Gem::Requirement
116
116
  requirements:
117
117
  - - ">="
@@ -125,7 +125,7 @@ dependencies:
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
127
  - !ruby/object:Gem::Dependency
128
- name: pry-doc
128
+ name: pry-nav
129
129
  requirement: !ruby/object:Gem::Requirement
130
130
  requirements:
131
131
  - - ">="
@@ -139,19 +139,19 @@ dependencies:
139
139
  - !ruby/object:Gem::Version
140
140
  version: '0'
141
141
  - !ruby/object:Gem::Dependency
142
- name: pry-nav
142
+ name: psych
143
143
  requirement: !ruby/object:Gem::Requirement
144
144
  requirements:
145
- - - ">="
145
+ - - "~>"
146
146
  - !ruby/object:Gem::Version
147
- version: '0'
147
+ version: '3'
148
148
  type: :development
149
149
  prerelease: false
150
150
  version_requirements: !ruby/object:Gem::Requirement
151
151
  requirements:
152
- - - ">="
152
+ - - "~>"
153
153
  - !ruby/object:Gem::Version
154
- version: '0'
154
+ version: '3'
155
155
  - !ruby/object:Gem::Dependency
156
156
  name: rake
157
157
  requirement: !ruby/object:Gem::Requirement
@@ -186,28 +186,14 @@ dependencies:
186
186
  requirements:
187
187
  - - "~>"
188
188
  - !ruby/object:Gem::Version
189
- version: 0.48.1
190
- type: :development
191
- prerelease: false
192
- version_requirements: !ruby/object:Gem::Requirement
193
- requirements:
194
- - - "~>"
195
- - !ruby/object:Gem::Version
196
- version: 0.48.1
197
- - !ruby/object:Gem::Dependency
198
- name: standalone_migrations
199
- requirement: !ruby/object:Gem::Requirement
200
- requirements:
201
- - - "~>"
202
- - !ruby/object:Gem::Version
203
- version: 5.2.0
189
+ version: '1'
204
190
  type: :development
205
191
  prerelease: false
206
192
  version_requirements: !ruby/object:Gem::Requirement
207
193
  requirements:
208
194
  - - "~>"
209
195
  - !ruby/object:Gem::Version
210
- version: 5.2.0
196
+ version: '1'
211
197
  description: Adds typed jsonb backed fields to your ActiveRecord models.
212
198
  email:
213
199
  - michael@crismali.com
@@ -217,13 +203,15 @@ executables: []
217
203
  extensions: []
218
204
  extra_rdoc_files: []
219
205
  files:
206
+ - ".github/workflows/ci.yml"
220
207
  - ".gitignore"
221
208
  - ".rspec"
222
209
  - ".rubocop.yml"
223
210
  - ".ruby-version"
224
- - ".travis.yml"
225
211
  - Appraisals
212
+ - CHANGELOG.md
226
213
  - CODE_OF_CONDUCT.md
214
+ - Dockerfile
227
215
  - Gemfile
228
216
  - LICENSE.txt
229
217
  - README.md
@@ -234,10 +222,15 @@ files:
234
222
  - db/config.yml
235
223
  - db/migrate/20150407031737_set_up_testing_db.rb
236
224
  - db/schema.rb
225
+ - docker-compose.yml
237
226
  - gemfiles/activerecord_5.0.0.gemfile
238
227
  - gemfiles/activerecord_5.1.0.gemfile
228
+ - gemfiles/activerecord_6.1.0.gemfile
229
+ - gemfiles/activerecord_7.0.1.gemfile
239
230
  - jsonb_accessor.gemspec
240
231
  - lib/jsonb_accessor.rb
232
+ - lib/jsonb_accessor/attribute_query_methods.rb
233
+ - lib/jsonb_accessor/helpers.rb
241
234
  - lib/jsonb_accessor/macro.rb
242
235
  - lib/jsonb_accessor/query_builder.rb
243
236
  - lib/jsonb_accessor/query_helper.rb
@@ -246,24 +239,23 @@ homepage: https://github.com/devmynd/jsonb_accessor
246
239
  licenses:
247
240
  - MIT
248
241
  metadata: {}
249
- post_install_message:
242
+ post_install_message:
250
243
  rdoc_options: []
251
244
  require_paths:
252
245
  - lib
253
246
  required_ruby_version: !ruby/object:Gem::Requirement
254
247
  requirements:
255
- - - "~>"
248
+ - - ">="
256
249
  - !ruby/object:Gem::Version
257
- version: '2.0'
250
+ version: '2'
258
251
  required_rubygems_version: !ruby/object:Gem::Requirement
259
252
  requirements:
260
253
  - - ">="
261
254
  - !ruby/object:Gem::Version
262
255
  version: '0'
263
256
  requirements: []
264
- rubyforge_project:
265
- rubygems_version: 2.6.11
266
- signing_key:
257
+ rubygems_version: 3.1.4
258
+ signing_key:
267
259
  specification_version: 4
268
260
  summary: Adds typed jsonb backed fields to your ActiveRecord models.
269
261
  test_files: []
data/.travis.yml DELETED
@@ -1,20 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.3.8
4
- - 2.4.5
5
- - 2.5.3
6
- - 2.6.1
7
- addons:
8
- postgresql: "9.4"
9
- before_install:
10
- - gem update --system
11
- - gem --version
12
- - gem install bundler:2.1.4
13
- before_script:
14
- - bundle exec rake db:create
15
- - bundle exec rake db:migrate
16
- install: bundle _2.1.4_ install --jobs=3 --retry=3 --path=${BUNDLE_PATH:-vendor/bundle}
17
- cache: bundler
18
- gemfile:
19
- - gemfiles/activerecord_5.0.0.gemfile
20
- - gemfiles/activerecord_5.1.0.gemfile