attr_json 0.4.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +54 -11
- data/Appraisals +8 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile +3 -3
- data/README.md +24 -7
- data/attr_json.gemspec +2 -2
- data/gemfiles/rails_5_0.gemfile +2 -2
- data/gemfiles/rails_5_1.gemfile +2 -2
- data/gemfiles/rails_5_2.gemfile +2 -2
- data/gemfiles/rails_6_0.gemfile +18 -0
- data/gemfiles/rails_edge.gemfile +19 -0
- data/gemfiles/rails_edge_6.gemfile +3 -3
- data/lib/attr_json.rb +0 -1
- data/lib/attr_json/attribute_definition.rb +9 -2
- data/lib/attr_json/attribute_definition/registry.rb +5 -0
- data/lib/attr_json/record.rb +46 -18
- data/lib/attr_json/record/query_builder.rb +15 -3
- data/lib/attr_json/record/query_scopes.rb +6 -0
- data/lib/attr_json/type/model.rb +7 -4
- data/lib/attr_json/type/polymorphic_model.rb +2 -0
- data/lib/attr_json/version.rb +1 -1
- metadata +12 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be1175039b6fbd78d5a9c1bcaae7c4ce003d29f403ef1e86d71d3c226e659a0b
|
4
|
+
data.tar.gz: 588710deb7c2b6076ba1cf1094f9b4ab67fb7bd74cecfc8c560de5b0ef50eafb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d71520892d16915465eab7c9e373f5e5ecabb8efee7a295da6532fbedd0c9817890da7e689e31f1bf1c7b3c1cad73f071f3563d7eb6d5637516de40174fce627
|
7
|
+
data.tar.gz: ea225c01754abfa5dec0e8749fd91ff68e1a329b54e684a27fee14655de7eb4eddf832538a961b14bbf83e222e0b90bfe554a8fdac001ca95aefb456353ed763
|
data/.travis.yml
CHANGED
@@ -1,21 +1,64 @@
|
|
1
1
|
#
|
2
|
-
dist: trusty
|
3
2
|
sudo: false
|
4
3
|
addons:
|
5
4
|
postgresql: '9.4'
|
6
5
|
chrome: stable
|
7
6
|
language: ruby
|
8
7
|
cache: bundler
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
8
|
+
|
9
|
+
# rvm:
|
10
|
+
# - 2.4.5
|
11
|
+
# - 2.5.3
|
12
|
+
# - 2.6.5
|
13
|
+
# - 2.7.0
|
14
|
+
# gemfile:
|
15
|
+
# - gemfiles/rails_5_0.gemfile
|
16
|
+
# - gemfiles/rails_5_1.gemfile
|
17
|
+
# - gemfiles/rails_5_2.gemfile
|
18
|
+
# - gemfiles/rails_6_0.gemfile
|
19
|
+
# - gemfiles/rails_edge.gemfile
|
20
|
+
|
17
21
|
before_install:
|
18
|
-
- gem install bundler -v
|
22
|
+
- gem install bundler -v "~> 2.0"
|
23
|
+
|
19
24
|
matrix:
|
25
|
+
include:
|
26
|
+
- rvm: 2.4.5
|
27
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
28
|
+
|
29
|
+
- rvm: 2.4.5
|
30
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
31
|
+
|
32
|
+
- rvm: 2.4.5
|
33
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
34
|
+
|
35
|
+
- rvm: 2.5.3
|
36
|
+
gemfile: gemfiles/rails_5_0.gemfile
|
37
|
+
|
38
|
+
- rvm: 2.5.3
|
39
|
+
gemfile: gemfiles/rails_5_1.gemfile
|
40
|
+
|
41
|
+
- rvm: 2.5.3
|
42
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
43
|
+
|
44
|
+
- rvm: 2.5.3
|
45
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
46
|
+
|
47
|
+
- rvm: 2.6.5
|
48
|
+
gemfile: gemfiles/rails_5_2.gemfile
|
49
|
+
|
50
|
+
- rvm: 2.6.5
|
51
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
52
|
+
|
53
|
+
- rvm: 2.7.0
|
54
|
+
gemfile: gemfiles/rails_6_0.gemfile
|
55
|
+
|
56
|
+
- rvm: 2.7.0
|
57
|
+
gemfile: gemfiles/rails_edge.gemfile
|
58
|
+
|
20
59
|
allow_failures:
|
21
|
-
- gemfile: gemfiles/
|
60
|
+
- gemfile: gemfiles/rails_edge.gemfile
|
61
|
+
fast_finish: true
|
62
|
+
|
63
|
+
|
64
|
+
|
data/Appraisals
CHANGED
@@ -25,10 +25,17 @@ appraise "rails-5-2" do
|
|
25
25
|
gem "pg", "~> 1.0"
|
26
26
|
end
|
27
27
|
|
28
|
+
appraise "rails-6-0" do
|
29
|
+
gem 'combustion', "~> 1.0"
|
30
|
+
|
31
|
+
gem "rails", ">= 6.0.0.beta1", "< 6.1"
|
32
|
+
gem "pg", "~> 1.0"
|
33
|
+
end
|
34
|
+
|
28
35
|
appraise "rails-edge-6" do
|
29
36
|
# Edge rails needs unreleased combustion
|
30
37
|
# https://github.com/pat/combustion/issues/92
|
31
|
-
gem 'combustion',
|
38
|
+
gem 'combustion', "~> 1.0"
|
32
39
|
|
33
40
|
gem "rails", git: "https://github.com/rails/rails.git", branch: "master"
|
34
41
|
gem "pg", "~> 1.0"
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Changelog
|
2
|
+
Notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased](https://github.com/jrochkind/attr_json/compare/v1.1.0...HEAD)
|
8
|
+
|
9
|
+
## [1.1.0](https://github.com/jrochkind/attr_json/compare/v1.0.0...v1.1.0)
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
* not_jsonb_contains query method, like `jsonb_contains` but negated. https://github.com/jrochkind/attr_json/pull/85
|
data/Gemfile
CHANGED
@@ -10,7 +10,7 @@ gemspec
|
|
10
10
|
# We also have these development dependencies here in the Gemfile instead of the
|
11
11
|
# gemspec so appraisal can override them from our Appraisal file.
|
12
12
|
|
13
|
-
gem 'combustion', '~>
|
13
|
+
gem 'combustion', '~> 1.1'
|
14
14
|
|
15
15
|
# all of rails is NOT a dependency, just activerecord.
|
16
16
|
# But we use it for integration testing with combustion. Hmm, a bit annoying
|
@@ -24,13 +24,13 @@ gem 'rails'
|
|
24
24
|
gem 'railties'
|
25
25
|
|
26
26
|
gem "pg"
|
27
|
-
gem "rspec-rails", "~>
|
27
|
+
gem "rspec-rails", "~> 4.0"
|
28
28
|
gem "simple_form", ">= 4.0"
|
29
29
|
gem 'cocoon', ">= 1.2"
|
30
30
|
gem 'jquery-rails'
|
31
31
|
|
32
32
|
gem 'capybara', "~> 3.0"
|
33
|
-
gem
|
33
|
+
gem 'webdrivers', '~> 4.0'
|
34
34
|
gem "selenium-webdriver"
|
35
35
|
|
36
36
|
gem "byebug"
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/attr_json.svg)](https://badge.fury.io/rb/attr_json)
|
4
4
|
|
5
5
|
|
6
|
-
ActiveRecord attributes stored serialized in a json column, super smooth. For Rails 5.0, 5.1,
|
6
|
+
ActiveRecord attributes stored serialized in a json column, super smooth. For Rails 5.0, 5.1, 5.2, or 6.0. Ruby 2.4+.
|
7
7
|
|
8
8
|
Typed and cast like Active Record. Supporting [nested models](#nested), [dirty tracking](#dirty), some [querying](#querying) (with postgres [jsonb](https://www.postgresql.org/docs/9.5/static/datatype-json.html) contains), and [working smoothy with form builders](#forms).
|
9
9
|
|
@@ -11,8 +11,6 @@ Typed and cast like Active Record. Supporting [nested models](#nested), [dirty t
|
|
11
11
|
|
12
12
|
[Why might you want or not want this?](#why)
|
13
13
|
|
14
|
-
AttrJson is pre-1.0. The functionality that is documented here _is_ already implemented (these docs are real, not vaporware) and seems pretty solid. It may still have backwards-incompat changes before 1.0 release. Review and feedback is very welcome.
|
15
|
-
|
16
14
|
Developed for postgres, but most features should work with MySQL json columns too, although
|
17
15
|
has not yet been tested with MySQL.
|
18
16
|
|
@@ -140,6 +138,9 @@ MyModel.jsonb_contains(my_string: "foo", my_integer: 100).first
|
|
140
138
|
# Implemented with scopes, this is an ordinary relation, you can
|
141
139
|
# combine it with whatever, just like ordinary `where`.
|
142
140
|
|
141
|
+
MyModel.not_jsonb_contains(my:string: "foo", my_integer: 100).to_sql
|
142
|
+
# SELECT "products".* FROM "products" WHERE NOT (products.json_attributes @> ('{"my_string":"foo","my_integer":100}')::jsonb)
|
143
|
+
|
143
144
|
# typecasts much like ActiveRecord on query too:
|
144
145
|
MyModel.jsonb_contains(my_string: "foo", my_integer: "100")
|
145
146
|
# no problem
|
@@ -285,6 +286,20 @@ always mean 'contains' -- the previous query needs a `my_labels.hello`
|
|
285
286
|
which is a hash that includes the key/value, `lang: en`, it can have
|
286
287
|
other key/values in it too. String values will need to match exactly.
|
287
288
|
|
289
|
+
<a name="arbitrary-json-data"></a>
|
290
|
+
## Storing Arbitrary JSON data
|
291
|
+
|
292
|
+
Arbitrary JSON data (hashes, arrays, primitives of any depth) can be stored within attributes by using the rails built in `ActiveModel::Type::Value` as the attribute type. This is basically a "no-op" value type -- JSON alone will be used to serialize/deserialize whatever values you put there, because of the json type on the container field.
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
class MyModel < ActiveRecord::Base
|
296
|
+
include AttrJson::Record
|
297
|
+
|
298
|
+
attr_json :arbitrary_hash, ActiveModel::Type::Value.new
|
299
|
+
end
|
300
|
+
|
301
|
+
```
|
302
|
+
|
288
303
|
|
289
304
|
<a name="forms"></a>
|
290
305
|
## Forms and Form Builders
|
@@ -383,16 +398,16 @@ to prevent overwriting other updates from processes.
|
|
383
398
|
|
384
399
|
## State of Code, and To Be Done
|
385
400
|
|
386
|
-
|
401
|
+
The functionality that is here seems pretty solid, and is being used by jrochkind in a production app.
|
387
402
|
|
388
|
-
|
389
|
-
|
390
|
-
I do not yet use this myself in production, and may not for a while. I generally am reluctant to release something as 1.0 with implied suitable for production when I'm not yet using it in production myself, but may with enough feedback. A couple others are already using in production.
|
403
|
+
We are committed to [semantic versioning](https://semver.org/) and will endeavor to release no backwards breaking changes without a major version. We are also serious about minimizing backwards incompat releases altogether (ie minimiing major version releases).
|
391
404
|
|
392
405
|
Feedback of any kind of _very welcome_, please feel free to use the issue tracker.
|
393
406
|
|
394
407
|
Except for the jsonb_contains stuff using postgres jsonb contains operator, I don't believe any postgres-specific features are used. It ought to work with MySQL, testing and feedback welcome. (Or a PR to test on MySQL?). My own interest is postgres.
|
395
408
|
|
409
|
+
This is still mostly a single-maintainer operation, so has all the sustainability risks of that. Although there are other people using and contributing to it, check out the Github Issues and Pull Request tabs yourself to get a sense.
|
410
|
+
|
396
411
|
### Possible future features:
|
397
412
|
|
398
413
|
* partial updates for json hashes would be really nice: Using postgres jsonb merge operators to only overwrite what changed. In my initial attempts, AR doesn't make it easy to customize this.
|
@@ -450,3 +465,5 @@ There is a `./bin/console` that will give you a console in the context of attr_j
|
|
450
465
|
* Didn't actually notice existing [json_attributes](https://github.com/joel/json_attributes)
|
451
466
|
until I was well on my way here. I think it's not updated for Rails5 or type-aware,
|
452
467
|
haven't looked at it too much.
|
468
|
+
|
469
|
+
* [store_model](https://github.com/DmitryTsepelev/store_model) was created after `attr_json`, and has some overlapping functionality.
|
data/attr_json.gemspec
CHANGED
@@ -45,10 +45,10 @@ attributes use as much of the existing ActiveRecord architecture as we can.}
|
|
45
45
|
# Only to get CI to work on versions of Rails other than we release with,
|
46
46
|
# should never release a gem with RAILS_GEM set!
|
47
47
|
unless ENV['APPRAISAL_INITIALIZED'] || ENV["TRAVIS"]
|
48
|
-
spec.add_runtime_dependency "activerecord", ">= 5.0.0", "<
|
48
|
+
spec.add_runtime_dependency "activerecord", ">= 5.0.0", "< 6.1"
|
49
49
|
end
|
50
50
|
|
51
|
-
spec.add_development_dependency "bundler"
|
51
|
+
spec.add_development_dependency "bundler"
|
52
52
|
spec.add_development_dependency "rake", ">= 10.0"
|
53
53
|
spec.add_development_dependency "rspec", "~> 3.7"
|
54
54
|
spec.add_development_dependency "database_cleaner", "~> 1.5"
|
data/gemfiles/rails_5_0.gemfile
CHANGED
@@ -6,12 +6,12 @@ gem "combustion", "~> 0.9.0"
|
|
6
6
|
gem "rails", "~> 5.0.0"
|
7
7
|
gem "railties"
|
8
8
|
gem "pg", "~> 0.18"
|
9
|
-
gem "rspec-rails", "~>
|
9
|
+
gem "rspec-rails", "~> 4.0"
|
10
10
|
gem "simple_form", ">= 4.0"
|
11
11
|
gem "cocoon", ">= 1.2"
|
12
12
|
gem "jquery-rails"
|
13
13
|
gem "capybara", "~> 3.0"
|
14
|
-
gem "
|
14
|
+
gem "webdrivers", "~> 4.0"
|
15
15
|
gem "selenium-webdriver"
|
16
16
|
gem "byebug"
|
17
17
|
gem "rails-ujs", require: false
|
data/gemfiles/rails_5_1.gemfile
CHANGED
@@ -6,12 +6,12 @@ gem "combustion", "~> 0.9.0"
|
|
6
6
|
gem "rails", "~> 5.1.0"
|
7
7
|
gem "railties"
|
8
8
|
gem "pg", "~> 1.0"
|
9
|
-
gem "rspec-rails", "~>
|
9
|
+
gem "rspec-rails", "~> 4.0"
|
10
10
|
gem "simple_form", ">= 4.0"
|
11
11
|
gem "cocoon", ">= 1.2"
|
12
12
|
gem "jquery-rails"
|
13
13
|
gem "capybara", "~> 3.0"
|
14
|
-
gem "
|
14
|
+
gem "webdrivers", "~> 4.0"
|
15
15
|
gem "selenium-webdriver"
|
16
16
|
gem "byebug"
|
17
17
|
|
data/gemfiles/rails_5_2.gemfile
CHANGED
@@ -6,12 +6,12 @@ gem "combustion", "~> 0.9.0"
|
|
6
6
|
gem "rails", "~> 5.2.0"
|
7
7
|
gem "railties"
|
8
8
|
gem "pg", "~> 1.0"
|
9
|
-
gem "rspec-rails", "~>
|
9
|
+
gem "rspec-rails", "~> 4.0"
|
10
10
|
gem "simple_form", ">= 4.0"
|
11
11
|
gem "cocoon", ">= 1.2"
|
12
12
|
gem "jquery-rails"
|
13
13
|
gem "capybara", "~> 3.0"
|
14
|
-
gem "
|
14
|
+
gem "webdrivers", "~> 4.0"
|
15
15
|
gem "selenium-webdriver"
|
16
16
|
gem "byebug"
|
17
17
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "combustion", "~> 1.0"
|
6
|
+
gem "rails", ">= 6.0.0.beta1", "< 6.1"
|
7
|
+
gem "railties"
|
8
|
+
gem "pg", "~> 1.0"
|
9
|
+
gem "rspec-rails", "~> 4.0"
|
10
|
+
gem "simple_form", ">= 4.0"
|
11
|
+
gem "cocoon", ">= 1.2"
|
12
|
+
gem "jquery-rails"
|
13
|
+
gem "capybara", "~> 3.0"
|
14
|
+
gem "webdrivers", "~> 4.0"
|
15
|
+
gem "selenium-webdriver"
|
16
|
+
gem "byebug"
|
17
|
+
|
18
|
+
gemspec path: "../"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "combustion", "~> 1.0"
|
6
|
+
gem "rails", git: "https://github.com/rails/rails.git", branch: "master"
|
7
|
+
gem "railties"
|
8
|
+
gem "pg", "~> 1.0"
|
9
|
+
gem "rspec-rails", "~> 3.7"
|
10
|
+
gem "simple_form", ">= 4.0"
|
11
|
+
gem "cocoon", ">= 1.2"
|
12
|
+
gem "jquery-rails"
|
13
|
+
gem "capybara", "~> 3.0"
|
14
|
+
gem "webdrivers", "~> 4.0"
|
15
|
+
gem "selenium-webdriver"
|
16
|
+
gem "byebug"
|
17
|
+
gem "coffee-rails"
|
18
|
+
|
19
|
+
gemspec path: "../"
|
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "combustion",
|
5
|
+
gem "combustion", "~> 1.0"
|
6
6
|
gem "rails", git: "https://github.com/rails/rails.git", branch: "master"
|
7
7
|
gem "railties"
|
8
8
|
gem "pg", "~> 1.0"
|
9
|
-
gem "rspec-rails", "~>
|
9
|
+
gem "rspec-rails", "~> 4.0"
|
10
10
|
gem "simple_form", ">= 4.0"
|
11
11
|
gem "cocoon", ">= 1.2"
|
12
12
|
gem "jquery-rails"
|
13
13
|
gem "capybara", "~> 3.0"
|
14
|
-
gem "
|
14
|
+
gem "webdrivers", "~> 4.0"
|
15
15
|
gem "selenium-webdriver"
|
16
16
|
gem "byebug"
|
17
17
|
gem "coffee-rails"
|
data/lib/attr_json.rb
CHANGED
@@ -12,7 +12,9 @@
|
|
12
12
|
attr_reader :name, :type, :original_args, :container_attribute
|
13
13
|
|
14
14
|
# @param name [Symbol,String]
|
15
|
-
# @param type [Symbol,ActiveModel::Type::Value]
|
15
|
+
# @param type [Symbol,ActiveModel::Type::Value] Symbol is looked up in
|
16
|
+
# ActiveRecord::Type.lookup, but with `adapter: nil` for no custom
|
17
|
+
# adapter-specific lookup.
|
16
18
|
#
|
17
19
|
# @option options store_key [Symbol,String]
|
18
20
|
# @option options container_attribute [Symbol,ActiveModel::Type::Value]
|
@@ -40,7 +42,12 @@
|
|
40
42
|
# ActiveModel::Type.lookup may make more sense, but ActiveModel::Type::Date
|
41
43
|
# seems to have a bug with multi-param assignment. Mostly they return
|
42
44
|
# the same types, but ActiveRecord::Type::Date works with multi-param assignment.
|
43
|
-
|
45
|
+
#
|
46
|
+
# We pass `adapter: nil` to avoid triggering a db connection.
|
47
|
+
# See: https://github.com/jrochkind/attr_json/issues/41
|
48
|
+
# This is at the "cost" of not using any adapter-specific types... which
|
49
|
+
# maybe preferable anyway?
|
50
|
+
type = ActiveRecord::Type.lookup(type, adapter: nil)
|
44
51
|
elsif ! type.is_a? ActiveModel::Type::Value
|
45
52
|
raise ArgumentError, "Second argument (#{type}) must be a symbol or instance of an ActiveModel::Type::Value subclass"
|
46
53
|
end
|
@@ -54,6 +54,11 @@ module AttrJson
|
|
54
54
|
@name_to_definition.values
|
55
55
|
end
|
56
56
|
|
57
|
+
# Returns all registered attributes as an array of symbols
|
58
|
+
def attribute_names
|
59
|
+
@name_to_definition.keys
|
60
|
+
end
|
61
|
+
|
57
62
|
def container_attributes
|
58
63
|
@store_key_to_definition.keys.collect(&:to_s)
|
59
64
|
end
|
data/lib/attr_json/record.rb
CHANGED
@@ -18,7 +18,7 @@ module AttrJson
|
|
18
18
|
extend ActiveSupport::Concern
|
19
19
|
|
20
20
|
included do
|
21
|
-
unless self
|
21
|
+
unless self <= ActiveRecord::Base
|
22
22
|
raise TypeError, "AttrJson::Record can only be used with an ActiveRecord::Base model. #{self} does not appear to be one. Are you looking for ::AttrJson::Model?"
|
23
23
|
end
|
24
24
|
|
@@ -26,6 +26,37 @@ module AttrJson
|
|
26
26
|
self.attr_json_registry = AttrJson::AttributeDefinition::Registry.new
|
27
27
|
end
|
28
28
|
|
29
|
+
protected
|
30
|
+
|
31
|
+
# adapted from ActiveRecord query_attribute method
|
32
|
+
# https://github.com/rails/rails/blob/v5.2.3/activerecord/lib/active_record/attribute_methods/query.rb#L12
|
33
|
+
#
|
34
|
+
# Sadly we could not re-use Rails code here, becuase the built-in method assumes attribute
|
35
|
+
# can be obtained with `self[attr_name]`, which you can not with attr_json (is that bad?), as
|
36
|
+
# well as `self.class.columns_hash[attr_name]` which you definitely can not (which is probably not bad),
|
37
|
+
# and has no way to use the value-translation semantics independently of that. May be a problem if
|
38
|
+
# ActiveRecord changes it's query method semantics in the future, will have to be sync'd here.
|
39
|
+
#
|
40
|
+
# Used to implement query methods on attr_json attributes, like `attr_json :foo, :string`, method `#foo?`
|
41
|
+
def self.attr_json_query_method(record, attribute)
|
42
|
+
value = record.send(attribute)
|
43
|
+
|
44
|
+
case value
|
45
|
+
when true
|
46
|
+
true
|
47
|
+
when false, nil, ActiveModel::Type::Boolean::FALSE_VALUES
|
48
|
+
false
|
49
|
+
else
|
50
|
+
if value.respond_to?(:to_i) && ( Numeric === value || value.to_s !~ /[^0-9]/ )
|
51
|
+
!value.to_i.zero?
|
52
|
+
elsif value.respond_to?(:zero?)
|
53
|
+
!value.zero?
|
54
|
+
else
|
55
|
+
!value.blank?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
29
60
|
class_methods do
|
30
61
|
# Access or set class-wide json_attribute_config. Inherited by sub-classes,
|
31
62
|
# but setting on sub-classes is unique to subclass. Similar to how
|
@@ -133,30 +164,27 @@ module AttrJson
|
|
133
164
|
end
|
134
165
|
|
135
166
|
_attr_jsons_module.module_eval do
|
167
|
+
# For getter and setter, we used to use read_store_attribute/write_store_attribute
|
168
|
+
# copied from Rails store_accessor implementation.
|
169
|
+
# https://github.com/rails/rails/blob/74c3e43fba458b9b863d27f0c45fd2d8dc603cbc/activerecord/lib/active_record/store.rb#L90-L96
|
170
|
+
#
|
171
|
+
# But in fact just getting/setting in the hash provided to us by ActiveRecord json type
|
172
|
+
# container works BETTER for dirty tracking. We had a test that only passed doing it
|
173
|
+
# this simple way.
|
174
|
+
|
136
175
|
define_method("#{name}=") do |value|
|
137
176
|
attribute_def = self.class.attr_json_registry.fetch(name.to_sym)
|
138
|
-
|
139
|
-
# https://github.com/rails/rails/blob/74c3e43fba458b9b863d27f0c45fd2d8dc603cbc/activerecord/lib/active_record/store.rb#L90-L96
|
140
|
-
|
141
|
-
# special handling for nil, sorry, because if name key was previously
|
142
|
-
# not present, write_store_attribute by default will decide there was
|
143
|
-
# no change and refuse to make the change. TODO messy.
|
144
|
-
if value.nil? && !public_send(attribute_def.container_attribute).has_key?(attribute_def.store_key)
|
145
|
-
public_send :"#{attribute_def.container_attribute}_will_change!"
|
146
|
-
public_send(attribute_def.container_attribute)[attribute_def.store_key] = nil
|
147
|
-
else
|
148
|
-
# use of `write_store_attribute` is copied from Rails store_accessor implementation.
|
149
|
-
# https://github.com/rails/rails/blob/74c3e43fba458b9b863d27f0c45fd2d8dc603cbc/activerecord/lib/active_record/store.rb#L90-L96
|
150
|
-
write_store_attribute(attribute_def.container_attribute, attribute_def.store_key, attribute_def.cast(value))
|
151
|
-
end
|
177
|
+
public_send(attribute_def.container_attribute)[attribute_def.store_key] = attribute_def.cast(value)
|
152
178
|
end
|
153
179
|
|
154
180
|
define_method("#{name}") do
|
155
181
|
attribute_def = self.class.attr_json_registry.fetch(name.to_sym)
|
182
|
+
public_send(attribute_def.container_attribute)[attribute_def.store_key]
|
183
|
+
end
|
156
184
|
|
157
|
-
|
158
|
-
#
|
159
|
-
|
185
|
+
define_method("#{name}?") do
|
186
|
+
# implementation of `query_store_attribute` is based on Rails `query_attribute` implementation
|
187
|
+
AttrJson::Record.attr_json_query_method(self, name)
|
160
188
|
end
|
161
189
|
end
|
162
190
|
|
@@ -10,6 +10,20 @@ module AttrJson
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def contains_relation
|
13
|
+
contains_relation_impl do |relation, query, params|
|
14
|
+
relation.where(query, params)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def contains_not_relation
|
19
|
+
contains_relation_impl do |relation, query, params|
|
20
|
+
relation.where.not(query, params)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def contains_relation_impl
|
13
27
|
result_relation = relation
|
14
28
|
|
15
29
|
group_attributes_by_container.each do |container_attribute, attributes|
|
@@ -18,14 +32,12 @@ module AttrJson
|
|
18
32
|
attributes.each do |key, value|
|
19
33
|
add_to_param_hash!(param_hash, key, value)
|
20
34
|
end
|
21
|
-
result_relation = result_relation
|
35
|
+
result_relation = yield(result_relation, "#{relation.table_name}.#{container_attribute} @> (?)::jsonb", param_hash.to_json)
|
22
36
|
end
|
23
37
|
|
24
38
|
result_relation
|
25
39
|
end
|
26
40
|
|
27
|
-
protected
|
28
|
-
|
29
41
|
def merge_param_hash!(original, new)
|
30
42
|
original.deep_merge!(new) do |key, old_val, new_val|
|
31
43
|
if old_val.is_a?(Array) && old_val.first.is_a?(Hash) && new_val.is_a?(Array) && new_val.first.is_a?(Hash)
|
@@ -17,6 +17,8 @@ module AttrJson
|
|
17
17
|
#
|
18
18
|
# some_model.jsonb_contains(a_string: "foo").first
|
19
19
|
#
|
20
|
+
# some_model.not_jsonb_contains(a_string: "bar").first
|
21
|
+
#
|
20
22
|
# See more in {file:README} docs.
|
21
23
|
module QueryScopes
|
22
24
|
extend ActiveSupport::Concern
|
@@ -29,6 +31,10 @@ module AttrJson
|
|
29
31
|
scope(:jsonb_contains, lambda do |attributes|
|
30
32
|
QueryBuilder.new(self, attributes).contains_relation
|
31
33
|
end)
|
34
|
+
|
35
|
+
scope(:not_jsonb_contains, lambda do |attributes|
|
36
|
+
QueryBuilder.new(self, attributes).contains_not_relation
|
37
|
+
end)
|
32
38
|
end
|
33
39
|
end
|
34
40
|
end
|
data/lib/attr_json/type/model.rb
CHANGED
@@ -8,6 +8,8 @@ module AttrJson
|
|
8
8
|
# but normally that's only done in AttrJson::Model.to_type, there isn't
|
9
9
|
# an anticipated need to create from any other place.
|
10
10
|
class Model < ::ActiveModel::Type::Value
|
11
|
+
class BadCast < ArgumentError ; end
|
12
|
+
|
11
13
|
attr_accessor :model
|
12
14
|
def initialize(model)
|
13
15
|
#TODO type check, it really better be a AttrJson::Model. maybe?
|
@@ -34,10 +36,11 @@ module AttrJson
|
|
34
36
|
# TODO Maybe we ought not to do this on #to_h?
|
35
37
|
model.new_from_serializable(v.to_h)
|
36
38
|
else
|
37
|
-
# Bad input
|
38
|
-
#
|
39
|
-
#
|
40
|
-
|
39
|
+
# Bad input. Originally we were trying to return nil, to be like
|
40
|
+
# existing ActiveRecord which kind of silently does a basic value
|
41
|
+
# with null input. But that ended up making things confusing, let's
|
42
|
+
# just raise.
|
43
|
+
raise BadCast.new("Can not cast from #{v.inspect} to #{self.type}")
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
@@ -51,6 +51,8 @@ module AttrJson
|
|
51
51
|
# MyRecord.jsonb_contains(author: { name: "foo", type: "Corporation"})
|
52
52
|
# MyRecord.jsonb_contains(author: Corporation.new(name: "foo"))
|
53
53
|
#
|
54
|
+
# Additionally, there is not_jsonb_contains, which creates the same query terms like jsonb_contains, but negated.
|
55
|
+
#
|
54
56
|
class PolymorphicModel < ActiveModel::Type::Value
|
55
57
|
class TypeError < ::TypeError ; end
|
56
58
|
|
data/lib/attr_json/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attr_json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Rochkind
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 5.0.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '6.1'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,21 +29,21 @@ dependencies:
|
|
29
29
|
version: 5.0.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '6.1'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: bundler
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - "
|
37
|
+
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
39
|
+
version: '0'
|
40
40
|
type: :development
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- - "
|
44
|
+
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
46
|
+
version: '0'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,6 +133,7 @@ files:
|
|
133
133
|
- ".travis.yml"
|
134
134
|
- ".yardopts"
|
135
135
|
- Appraisals
|
136
|
+
- CHANGELOG.md
|
136
137
|
- Gemfile
|
137
138
|
- LICENSE.txt
|
138
139
|
- README.md
|
@@ -149,6 +150,8 @@ files:
|
|
149
150
|
- gemfiles/rails_5_0.gemfile
|
150
151
|
- gemfiles/rails_5_1.gemfile
|
151
152
|
- gemfiles/rails_5_2.gemfile
|
153
|
+
- gemfiles/rails_6_0.gemfile
|
154
|
+
- gemfiles/rails_edge.gemfile
|
152
155
|
- gemfiles/rails_edge_6.gemfile
|
153
156
|
- lib/attr_json.rb
|
154
157
|
- lib/attr_json/attribute_definition.rb
|
@@ -192,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
192
195
|
version: '0'
|
193
196
|
requirements: []
|
194
197
|
rubyforge_project:
|
195
|
-
rubygems_version: 2.7.
|
198
|
+
rubygems_version: 2.7.6
|
196
199
|
signing_key:
|
197
200
|
specification_version: 4
|
198
201
|
summary: ActiveRecord attributes stored serialized in a json column, super smooth.
|