attr_json-associations 0.1.0
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 +7 -0
- data/.github/workflows/ci.yml +45 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +132 -0
- data/Rakefile +6 -0
- data/attr_json-associations.gemspec +28 -0
- data/gemfiles/rails60.gemfile +6 -0
- data/gemfiles/rails61.gemfile +6 -0
- data/lib/attr_json-associations.rb +1 -0
- data/lib/attr_json/associations.rb +38 -0
- data/lib/attr_json/associations/association/base.rb +50 -0
- data/lib/attr_json/associations/association/belongs_to.rb +21 -0
- data/lib/attr_json/associations/association/has_collection.rb +17 -0
- data/lib/attr_json/associations/association/has_many.rb +10 -0
- data/lib/attr_json/associations/association/has_one.rb +10 -0
- data/lib/attr_json/associations/definer.rb +29 -0
- data/lib/attr_json/associations/loader/base.rb +47 -0
- data/lib/attr_json/associations/loader/belongs_to.rb +29 -0
- data/lib/attr_json/associations/loader/has_collection.rb +19 -0
- data/lib/attr_json/associations/loader/has_many.rb +13 -0
- data/lib/attr_json/associations/loader/has_one.rb +13 -0
- data/lib/attr_json/associations/loader/order_by_case.rb +48 -0
- data/lib/attr_json/associations/model.rb +12 -0
- data/lib/attr_json/associations/record.rb +18 -0
- data/lib/attr_json/associations/version.rb +7 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5d91c1b0627083b5a3816fa808b874446f8515f251da3ce69cedae471e86266f
|
4
|
+
data.tar.gz: d530189cb1b47a5e205578b3050407ee0cb5f98e30fd3d723a3e7d1f11098b62
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8a294004ad2dbb48587c53dc2a123cacf85387cca2ccbe7019a2bdbe0873dbf6b407c91d1a75f40910e2ef533d3afe06df9ee9413308f522bec978b4ec10f8dc
|
7
|
+
data.tar.gz: da2d5f95b3604d9fca46dbb326b163133e4f464ae7607d4d9fa7cb035474db9f5ef73f8b37269ee78fc46176c702b5b1762ddc0356882643142e2da246d9010a
|
@@ -0,0 +1,45 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ubuntu-20.04
|
8
|
+
services:
|
9
|
+
postgres:
|
10
|
+
image: postgres:9.5
|
11
|
+
env:
|
12
|
+
POSTGRES_USER: postgres
|
13
|
+
POSTGRES_PASSWORD: postgres
|
14
|
+
ports:
|
15
|
+
- 5432:5432
|
16
|
+
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
17
|
+
strategy:
|
18
|
+
fail-fast: false
|
19
|
+
matrix:
|
20
|
+
ruby: [2.7, 3.0]
|
21
|
+
attr_json: [1.3]
|
22
|
+
gemfile: ['rails60', 'rails61']
|
23
|
+
|
24
|
+
name: ruby ${{ matrix.ruby }}, attr_json ${{ matrix.attr_json }}, ${{ matrix.gemfile }}
|
25
|
+
|
26
|
+
env:
|
27
|
+
POSTGRES_USER: postgres
|
28
|
+
POSTGRES_PASSWORD: postgres
|
29
|
+
ATTR_JSON_VERSION: ${{ matrix.attr_json }}
|
30
|
+
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
|
31
|
+
|
32
|
+
steps:
|
33
|
+
- uses: actions/checkout@v2
|
34
|
+
- uses: ruby/setup-ruby@v1
|
35
|
+
with:
|
36
|
+
ruby-version: ${{ matrix.ruby }}
|
37
|
+
bundler-cache: true
|
38
|
+
- name: Prepare test
|
39
|
+
run: |
|
40
|
+
cd spec/dummy
|
41
|
+
BUNDLE_GEMFILE=../../${{ env.BUNDLE_GEMFILE }} RAILS_ENV=test bundle exec rake db:create db:migrate db:seed
|
42
|
+
cd ../..
|
43
|
+
- name: Run test
|
44
|
+
run: |
|
45
|
+
DEBUG=1 bundle exec rspec
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Yoshikazu Kaneta
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# AttrJson::Associations
|
2
|
+
|
3
|
+
A simple association extension for [attr_json](https://github.com/jrochkind/attr_json).
|
4
|
+
|
5
|
+
## Dependencies
|
6
|
+
|
7
|
+
* ruby 2.7+
|
8
|
+
* attr_json 1.3
|
9
|
+
* activerecord 6.0+
|
10
|
+
* activesupport 6.0+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'attr_json-associations'
|
18
|
+
```
|
19
|
+
|
20
|
+
Then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
Include `AttrJson::Associations`, and define associations using `attr_json_belongs_to` and `attr_json_has_many`.
|
27
|
+
You may specify attributes defined with `attr_json` as a primary key or a foreign key.
|
28
|
+
For example:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
class Group < ActiveRecord::Base
|
32
|
+
include AttrJson::Record
|
33
|
+
include AttrJson::Record::QueryScopes
|
34
|
+
include AttrJson::Associations
|
35
|
+
|
36
|
+
attr_json_has_many :users
|
37
|
+
end
|
38
|
+
|
39
|
+
class User < ActiveRecord::Base
|
40
|
+
include AttrJson::Record
|
41
|
+
include AttrJson::Record::QueryScopes
|
42
|
+
include AttrJson::Associations
|
43
|
+
|
44
|
+
attr_json_config(default_container_attribute: :data)
|
45
|
+
|
46
|
+
attr_json :group_id, :integer
|
47
|
+
attr_json_belongs_to :group
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
These associations generates queries as follows:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
Group.new(id: 1).users
|
55
|
+
#=> SELECT "users".* FROM "users" WHERE ("users"."data"->'group_id' = '1')
|
56
|
+
|
57
|
+
User.new(group_id: 1).group
|
58
|
+
#=> SELECT "groups".* FROM "groups" WHERE "groups"."id" = 1
|
59
|
+
```
|
60
|
+
|
61
|
+
### Options
|
62
|
+
|
63
|
+
You can speficy the following options for association definitions:
|
64
|
+
|
65
|
+
* `class_name`
|
66
|
+
* `primary_key`
|
67
|
+
* `foreign_key`
|
68
|
+
|
69
|
+
These options are same as ActiveRecord. For example:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
class Group < ActiveRecord::Base
|
73
|
+
include AttrJson::Record
|
74
|
+
include AttrJson::Record::QueryScopes
|
75
|
+
include AttrJson::Associations
|
76
|
+
|
77
|
+
attr_json_has_many :users, class_name: 'User', primary_key: :id, foreign_key: :group_id
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
You can also specify an additional scope for each association:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
class Group < ActiveRecord::Base
|
85
|
+
include AttrJson::Record
|
86
|
+
include AttrJson::Record::QueryScopes
|
87
|
+
include AttrJson::Associations
|
88
|
+
|
89
|
+
attr_json_has_many :users, -> { order(:id) }
|
90
|
+
end
|
91
|
+
|
92
|
+
Group.new(id: 1).users
|
93
|
+
#=> SELECT "users".* FROM "users" WHERE ("users"."data"->'group_id' = '1') ORDER BY "users"."id" ASC
|
94
|
+
```
|
95
|
+
|
96
|
+
### Array type
|
97
|
+
|
98
|
+
You can define `attr_json_belongs_to` for an array attribute. For example:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
class Array::User < ActiveRecord::Base
|
102
|
+
include AttrJson::Record
|
103
|
+
include AttrJson::Record::QueryScopes
|
104
|
+
include AttrJson::Associations
|
105
|
+
|
106
|
+
attr_json_config(default_container_attribute: :data)
|
107
|
+
|
108
|
+
attr_json :group_ids, :integer, array: true
|
109
|
+
attr_json_belongs_to :groups
|
110
|
+
end
|
111
|
+
|
112
|
+
Array::User.new(group_ids: [1, 2]).groups
|
113
|
+
#=> SELECT "groups".* FROM "groups" WHERE "groups"."id" IN (1, 2) ORDER BY CASE "groups"."id" WHEN 1 THEN 0 WHEN 2 THEN 1 ELSE 2 END
|
114
|
+
|
115
|
+
Array::User.new(group_ids: [2, 1]).groups
|
116
|
+
#=> SELECT "groups".* FROM "groups" WHERE "groups"."id" IN (2, 1) ORDER BY CASE "groups"."id" WHEN 2 THEN 0 WHEN 1 THEN 1 ELSE 2 END
|
117
|
+
```
|
118
|
+
|
119
|
+
Note that the returned records are ordered by the index of the array,
|
120
|
+
so the order of records in first example is different from the one in second example.
|
121
|
+
|
122
|
+
## Limitations
|
123
|
+
|
124
|
+
This gem is experimental so the various options like ActiveRecord's things are not supported.
|
125
|
+
|
126
|
+
## Contributing
|
127
|
+
|
128
|
+
Bug reports and pull requests are welcome at https://github.com/kanety/attr_json-associations.
|
129
|
+
|
130
|
+
## License
|
131
|
+
|
132
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'attr_json/associations/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "attr_json-associations"
|
8
|
+
spec.version = AttrJson::Associations::VERSION
|
9
|
+
spec.authors = ["Yoshikazu Kaneta"]
|
10
|
+
spec.email = ["kaneta@sitebridge.co.jp"]
|
11
|
+
spec.summary = %q{An association extension for attr_json}
|
12
|
+
spec.description = %q{An association extension for attr_json}
|
13
|
+
spec.homepage = "https://github.com/kanety/attr_json-associations"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = "exe"
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "attr_json", ">= 1.3"
|
21
|
+
spec.add_dependency "activerecord", ">= 6.0"
|
22
|
+
spec.add_dependency "activesupport", ">= 6.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "rails", ">= 6.0"
|
25
|
+
spec.add_development_dependency "pg"
|
26
|
+
spec.add_development_dependency "rspec-rails"
|
27
|
+
spec.add_development_dependency "simplecov"
|
28
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'attr_json/associations'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'attr_json'
|
5
|
+
|
6
|
+
require_relative 'associations/version'
|
7
|
+
require_relative 'associations/record'
|
8
|
+
require_relative 'associations/model'
|
9
|
+
require_relative 'associations/definer'
|
10
|
+
|
11
|
+
module AttrJson::Associations
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
included do
|
15
|
+
class_attribute :attr_json_associations
|
16
|
+
self.attr_json_associations = {}
|
17
|
+
|
18
|
+
if self < ActiveRecord::Base
|
19
|
+
include AttrJson::Associations::Record
|
20
|
+
else
|
21
|
+
include AttrJson::Associations::Model
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class_methods do
|
26
|
+
def attr_json_belongs_to(*args, **options)
|
27
|
+
AttrJson::Associations::Definer.new(:belongs_to, self, args, options).call
|
28
|
+
end
|
29
|
+
|
30
|
+
def attr_json_has_many(*args, **options)
|
31
|
+
AttrJson::Associations::Definer.new(:has_many, self, args, options).call
|
32
|
+
end
|
33
|
+
|
34
|
+
def attr_json_has_one(*args, **options)
|
35
|
+
AttrJson::Associations::Definer.new(:has_one, self, args, options).call
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AttrJson::Associations
|
4
|
+
module Association
|
5
|
+
class Base
|
6
|
+
attr_accessor :owner, :name, :scope, :options
|
7
|
+
attr_accessor :class_name, :klass, :primary_key, :foreign_key
|
8
|
+
|
9
|
+
def initialize(owner, args, options = {})
|
10
|
+
@owner = owner
|
11
|
+
@name = args[0]
|
12
|
+
@scope = args[1]
|
13
|
+
@options = options
|
14
|
+
|
15
|
+
@class_name = resolve(:class_name)
|
16
|
+
@klass = @class_name.constantize
|
17
|
+
@primary_key = resolve(:primary_key)
|
18
|
+
@foreign_key = resolve(:foreign_key)
|
19
|
+
end
|
20
|
+
|
21
|
+
def scoped
|
22
|
+
if @scope
|
23
|
+
@klass.all.instance_exec(&@scope)
|
24
|
+
else
|
25
|
+
@klass.all
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def resolve(key)
|
32
|
+
if @options.key?(key)
|
33
|
+
@options[key].to_s
|
34
|
+
else
|
35
|
+
send("resolve_#{key}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def resolve_class_name
|
40
|
+
[@owner.name.deconstantize, @name.to_s.demodulize.classify].select(&:present?).join('::')
|
41
|
+
end
|
42
|
+
|
43
|
+
def resolve_primary_key
|
44
|
+
end
|
45
|
+
|
46
|
+
def resolve_foreign_key
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module AttrJson::Associations
|
6
|
+
module Association
|
7
|
+
class BelongsTo < Base
|
8
|
+
def resolve_primary_key
|
9
|
+
@klass.primary_key.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def resolve_foreign_key
|
13
|
+
if @name.to_s == @name.to_s.pluralize
|
14
|
+
"#{@name.to_s.singularize}_ids"
|
15
|
+
else
|
16
|
+
"#{@name}_id"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module AttrJson::Associations
|
6
|
+
module Association
|
7
|
+
class HasCollection < Base
|
8
|
+
def resolve_primary_key
|
9
|
+
@owner.primary_key.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def resolve_foreign_key
|
13
|
+
"#{@owner.name.demodulize.underscore}_id"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'association/belongs_to'
|
4
|
+
require_relative 'association/has_many'
|
5
|
+
require_relative 'association/has_one'
|
6
|
+
require_relative 'loader/belongs_to'
|
7
|
+
require_relative 'loader/has_many'
|
8
|
+
require_relative 'loader/has_one'
|
9
|
+
|
10
|
+
module AttrJson::Associations
|
11
|
+
class Definer
|
12
|
+
def initialize(type, klass, args, options)
|
13
|
+
@type = type
|
14
|
+
@klass = klass
|
15
|
+
@assoc = Association.const_get(@type.to_s.classify).new(klass, args, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
@klass.attr_json_associations = @klass.attr_json_associations.merge(@assoc.name => @assoc)
|
20
|
+
@klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
21
|
+
def #{@assoc.name}
|
22
|
+
assoc = self.class.attr_json_associations[:#{@assoc.name}]
|
23
|
+
@attr_json_associations_cache[:#{@assoc.name}] ||=
|
24
|
+
AttrJson::Associations::Loader::#{@type.to_s.classify}.new(assoc, self).call
|
25
|
+
end
|
26
|
+
RUBY
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'order_by_case'
|
4
|
+
|
5
|
+
module AttrJson::Associations
|
6
|
+
module Loader
|
7
|
+
class Base
|
8
|
+
def initialize(assoc, record)
|
9
|
+
@assoc = assoc
|
10
|
+
@record = record
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def attr_json_definition(klass, key)
|
16
|
+
klass.respond_to?(:attr_json_registry) && klass.attr_json_registry[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
def target_scope(key, value)
|
20
|
+
if (definition = attr_json_definition(@assoc.klass, key))
|
21
|
+
if definition.array_type?
|
22
|
+
@assoc.klass.jsonb_contains(key => value)
|
23
|
+
else
|
24
|
+
column = @assoc.klass.connection.quote_table_name("#{@assoc.klass.table_name}.#{definition.container_attribute}") + "->'#{key}'"
|
25
|
+
if value.is_a?(Array)
|
26
|
+
value = value.map { |v| "'" + @assoc.klass.connection.quote(v) + "'" }.join(', ')
|
27
|
+
@assoc.klass.where(%Q|#{column} IN (#{value})|)
|
28
|
+
else
|
29
|
+
value = @assoc.klass.connection.quote(value)
|
30
|
+
@assoc.klass.where(%Q|#{column} = '#{value}'|)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
@assoc.klass.where(key => value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def target_order(key, value)
|
39
|
+
if value.is_a?(Array)
|
40
|
+
@assoc.klass.order(OrderByCase.new(@assoc.klass, key, value).call)
|
41
|
+
else
|
42
|
+
@assoc.klass.all
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module AttrJson::Associations
|
6
|
+
module Loader
|
7
|
+
class BelongsTo < Base
|
8
|
+
def call
|
9
|
+
if attr_json_definition(@record.class, @assoc.foreign_key)&.array_type?
|
10
|
+
load
|
11
|
+
else
|
12
|
+
load[0]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def load
|
19
|
+
value = @record.public_send(@assoc.foreign_key)
|
20
|
+
if value.present?
|
21
|
+
@assoc.scoped.merge(target_scope(@assoc.primary_key, value))
|
22
|
+
.merge(target_order(@assoc.primary_key, value))
|
23
|
+
else
|
24
|
+
@assoc.klass.none
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module AttrJson::Associations
|
6
|
+
module Loader
|
7
|
+
class HasCollection < Base
|
8
|
+
def load
|
9
|
+
value = @record.public_send(@assoc.primary_key)
|
10
|
+
if value.present?
|
11
|
+
@assoc.scoped.merge(target_scope(@assoc.foreign_key, value))
|
12
|
+
.merge(target_order(@assoc.foreign_key, value))
|
13
|
+
else
|
14
|
+
@assoc.klass.none
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AttrJson::Associations
|
4
|
+
module Loader
|
5
|
+
class OrderByCase
|
6
|
+
def initialize(klass, key, values)
|
7
|
+
@klass = klass
|
8
|
+
@key = key
|
9
|
+
@values = values
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
order = if (definition = attr_json_definition)
|
14
|
+
jsonb_column_order(definition)
|
15
|
+
else
|
16
|
+
normal_column_order
|
17
|
+
end
|
18
|
+
Arel.sql(order)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def attr_json_definition
|
24
|
+
@klass.attr_json_registry[@key] if @klass.respond_to?(:attr_json_registry)
|
25
|
+
end
|
26
|
+
|
27
|
+
def normal_column_order
|
28
|
+
column = @klass.connection.quote_table_name("#{@klass.table_name}.#{@key}")
|
29
|
+
orders = ["CASE #{column}"]
|
30
|
+
@values.each.with_index do |value, i|
|
31
|
+
orders << "WHEN #{@klass.connection.quote(value)} THEN #{i}"
|
32
|
+
end
|
33
|
+
orders << "ELSE #{@values.size} END"
|
34
|
+
orders.join(' ')
|
35
|
+
end
|
36
|
+
|
37
|
+
def jsonb_column_order(definition)
|
38
|
+
column = @klass.connection.quote_table_name("#{@klass.table_name}.#{definition.container_attribute}") + "->'#{@key}'"
|
39
|
+
orders = ["CASE #{column}"]
|
40
|
+
@values.each.with_index do |value, i|
|
41
|
+
orders << "WHEN '#{@klass.connection.quote(value)}' THEN #{i}"
|
42
|
+
end
|
43
|
+
orders << "ELSE #{@values.size} END"
|
44
|
+
orders.join(' ')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AttrJson::Associations
|
4
|
+
module Record
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
after_initialize do
|
9
|
+
@attr_json_associations_cache = {}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def reload(...)
|
14
|
+
@attr_json_associations_cache = {}
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attr_json-associations
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yoshikazu Kaneta
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-07-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: attr_json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '6.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '6.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '6.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '6.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '6.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '6.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pg
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: An association extension for attr_json
|
112
|
+
email:
|
113
|
+
- kaneta@sitebridge.co.jp
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".github/workflows/ci.yml"
|
119
|
+
- ".gitignore"
|
120
|
+
- ".rspec"
|
121
|
+
- CHANGELOG.md
|
122
|
+
- Gemfile
|
123
|
+
- LICENSE
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- attr_json-associations.gemspec
|
127
|
+
- gemfiles/rails60.gemfile
|
128
|
+
- gemfiles/rails61.gemfile
|
129
|
+
- lib/attr_json-associations.rb
|
130
|
+
- lib/attr_json/associations.rb
|
131
|
+
- lib/attr_json/associations/association/base.rb
|
132
|
+
- lib/attr_json/associations/association/belongs_to.rb
|
133
|
+
- lib/attr_json/associations/association/has_collection.rb
|
134
|
+
- lib/attr_json/associations/association/has_many.rb
|
135
|
+
- lib/attr_json/associations/association/has_one.rb
|
136
|
+
- lib/attr_json/associations/definer.rb
|
137
|
+
- lib/attr_json/associations/loader/base.rb
|
138
|
+
- lib/attr_json/associations/loader/belongs_to.rb
|
139
|
+
- lib/attr_json/associations/loader/has_collection.rb
|
140
|
+
- lib/attr_json/associations/loader/has_many.rb
|
141
|
+
- lib/attr_json/associations/loader/has_one.rb
|
142
|
+
- lib/attr_json/associations/loader/order_by_case.rb
|
143
|
+
- lib/attr_json/associations/model.rb
|
144
|
+
- lib/attr_json/associations/record.rb
|
145
|
+
- lib/attr_json/associations/version.rb
|
146
|
+
homepage: https://github.com/kanety/attr_json-associations
|
147
|
+
licenses: []
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubygems_version: 3.1.2
|
165
|
+
signing_key:
|
166
|
+
specification_version: 4
|
167
|
+
summary: An association extension for attr_json
|
168
|
+
test_files: []
|