jsonb_accessor 1.2.0 → 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 +5 -5
- data/.github/workflows/ci.yml +92 -0
- data/.rubocop.yml +19 -20
- data/.ruby-version +1 -1
- data/Appraisals +8 -0
- data/CHANGELOG.md +9 -0
- data/Dockerfile +12 -0
- data/README.md +34 -21
- data/Rakefile +21 -2
- data/bin/console +4 -4
- data/db/config.yml +2 -3
- data/db/migrate/20150407031737_set_up_testing_db.rb +2 -0
- data/db/schema.rb +3 -3
- data/docker-compose.yml +29 -0
- data/gemfiles/activerecord_6.1.0.gemfile +8 -0
- data/gemfiles/activerecord_7.0.1.gemfile +8 -0
- data/jsonb_accessor.gemspec +5 -7
- data/lib/jsonb_accessor/attribute_query_methods.rb +42 -0
- data/lib/jsonb_accessor/helpers.rb +9 -0
- data/lib/jsonb_accessor/macro.rb +34 -42
- data/lib/jsonb_accessor/query_builder.rb +1 -3
- data/lib/jsonb_accessor/query_helper.rb +10 -9
- data/lib/jsonb_accessor/version.rb +1 -1
- data/lib/jsonb_accessor.rb +4 -2
- metadata +31 -39
- data/.travis.yml +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f098f30fabf2c5bbbe39acaecc6487c84516837bb8f55ff1ecfcde0bdda24e2f
|
4
|
+
data.tar.gz: 9dd89e98ec2937007ca3a11794ad3c0b3d48f8510a8f2836e0a1276b9ba8d5e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
3
|
-
|
2
|
+
NewCops: enable
|
3
|
+
TargetRubyVersion: 2.7.2
|
4
|
+
SuggestExtensions: false
|
4
5
|
Exclude:
|
5
|
-
- db/**/*
|
6
|
-
- gemfiles/**/*
|
7
|
-
- vendor/**/*
|
8
|
-
|
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
|
-
|
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
|
-
|
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.
|
1
|
+
2.7.2
|
data/Appraisals
CHANGED
data/CHANGELOG.md
ADDED
data/Dockerfile
ADDED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Created by [<img src="https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/tandem-logo.png" alt="Tandem Logo" />](https://www.madeintandem.com/)
|
4
4
|
|
5
|
-
[](http://badge.fury.io/rb/jsonb_accessor)  
|
5
|
+
[](http://badge.fury.io/rb/jsonb_accessor)  <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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
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.
|
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.
|
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.
|
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 "
|
9
|
-
|
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("
|
7
|
+
require File.expand_path("../spec/spec_helper.rb", __dir__)
|
10
8
|
|
11
|
-
dbconfig = YAML.
|
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
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:
|
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
|
data/docker-compose.yml
ADDED
@@ -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:
|
data/jsonb_accessor.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
|
-
lib = File.expand_path("
|
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 = "
|
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", "~>
|
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
|
data/lib/jsonb_accessor/macro.rb
CHANGED
@@ -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.
|
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
|
-
|
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 |
|
75
|
-
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
|
-
|
79
|
-
|
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
|
-
|
82
|
-
|
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.
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
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.
|
66
|
-
|
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
|
data/lib/jsonb_accessor.rb
CHANGED
@@ -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.
|
19
|
-
ActiveRecord::Base.
|
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.
|
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:
|
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:
|
72
|
+
name: awesome_print
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
74
74
|
requirements:
|
75
|
-
- - "
|
75
|
+
- - ">="
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
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:
|
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:
|
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-
|
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:
|
142
|
+
name: psych
|
143
143
|
requirement: !ruby/object:Gem::Requirement
|
144
144
|
requirements:
|
145
|
-
- - "
|
145
|
+
- - "~>"
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
version: '
|
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: '
|
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:
|
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:
|
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
|
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
|
-
|
265
|
-
|
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
|