association_selection 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +100 -0
- data/Rakefile +11 -0
- data/lib/association_selection/querying.rb +15 -0
- data/lib/association_selection/v5/preloader.rb +34 -0
- data/lib/association_selection/v5/relation.rb +14 -0
- data/lib/association_selection/v6/relation.rb +28 -0
- data/lib/association_selection/v7/relation.rb +21 -0
- data/lib/association_selection/version.rb +5 -0
- data/lib/association_selection.rb +28 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6fb7c7317ba8cf62a11d85ff6774f3ae5880069cfe57982d1b2acc2b091bce28
|
4
|
+
data.tar.gz: aba4e0ec50f24443a17f4a2a06a78722e29da8c2dad11f840a0297ff73184177
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 47c5217acea4a685025595c0a8181b3f877a0c842ae06e342132390cb2a3e3131c2dcb86ba52ba7c4a929dbf9b35d6250d0cfd2ee11931da840a31731b98f587
|
7
|
+
data.tar.gz: ea5017c30fcd1faee3a680f390f01b755a066d74a4875ddf0409a6646434d68de6e797d99c8eeec1f8324993e38c1ba95e89bf28665d89f9f9b0fe93409a16a5
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# AssociationSelection
|
2
|
+
|
3
|
+
`AssociationSelection` is a gem that allows you to specify which fields to select when preloading associations. It offers finer control over database queries, optimizing memory usage and enhancing performance by fetching only the necessary fields.
|
4
|
+
|
5
|
+
Features
|
6
|
+
---
|
7
|
+
|
8
|
+
- Select specific fields for associated records when using `includes` or `preload`.
|
9
|
+
- Seamlessly integrates with ActiveRecord.
|
10
|
+
- Reduces memory overhead and improves query efficiency.
|
11
|
+
|
12
|
+
Installation
|
13
|
+
---
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'association_selection'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
bundle install
|
25
|
+
```
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
```
|
30
|
+
gem install association_selection
|
31
|
+
```
|
32
|
+
|
33
|
+
Usage
|
34
|
+
===
|
35
|
+
|
36
|
+
|
37
|
+
Quick Start
|
38
|
+
---
|
39
|
+
|
40
|
+
1. Include the gem in your Rails application.
|
41
|
+
2. Use the `assoc_select` method to specify the fields to fetch for associated records.
|
42
|
+
|
43
|
+
Example
|
44
|
+
---
|
45
|
+
#### Schema
|
46
|
+
```ruby
|
47
|
+
ActiveRecord::Schema.define do
|
48
|
+
create_table :departments do |t|
|
49
|
+
t.string :name
|
50
|
+
end
|
51
|
+
|
52
|
+
create_table :employees do |t|
|
53
|
+
t.integer :department_id
|
54
|
+
t.string :name
|
55
|
+
t.string :email
|
56
|
+
t.integer :gender
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
#### Models
|
62
|
+
```ruby
|
63
|
+
class Department < ActiveRecord::Base
|
64
|
+
has_many :employees
|
65
|
+
end
|
66
|
+
|
67
|
+
class Employee < ActiveRecord::Base
|
68
|
+
belongs_to :department
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
#### Query
|
74
|
+
```ruby
|
75
|
+
# Preload employees with only selected fields
|
76
|
+
departments = Department.assoc_select(:employees, :id, :name).includes(:employees)
|
77
|
+
|
78
|
+
departments.each do |department|
|
79
|
+
department.employees.each do |employee|
|
80
|
+
puts employee.name # Only `id` and `name` are fetched from the database.
|
81
|
+
end
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
How It Works
|
86
|
+
---
|
87
|
+
The assoc_select method modifies the query to include only the specified fields for the given association. It works seamlessly with ActiveRecord's includes, preload, and eager_load methods.
|
88
|
+
|
89
|
+
Compatibility
|
90
|
+
---
|
91
|
+
This gem is tested with ActiveRecord versions 5, 6, 7, and newer
|
92
|
+
|
93
|
+
Bug reports & suggested improvements
|
94
|
+
---
|
95
|
+
If you have found a bug or want to suggest an improvement, please use our issue tracked at:
|
96
|
+
|
97
|
+
https://github.com/vuong-khai-ha/association_selection
|
98
|
+
|
99
|
+
If you want to contribute, fork the project, code your improvements and make a pull request on Github. Please don't forget to add tests.
|
100
|
+
If your contribution is fixing a bug it would be better if you could submit a failing test, illustrating the issue.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssociationSelection
|
4
|
+
module Querying
|
5
|
+
attr_accessor :assoc_select_fields
|
6
|
+
|
7
|
+
def assoc_select(**fields)
|
8
|
+
spawn.tap { |s| s.assoc_select_fields = fields }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Delegations
|
13
|
+
delegate :assoc_select, to: :all
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssociationSelection
|
4
|
+
module V5
|
5
|
+
module Preloader
|
6
|
+
attr_accessor :relation_klass, :assoc_select_fields
|
7
|
+
|
8
|
+
NULL_RELATION = Struct.new(:values, :where_clause, :joins_values)
|
9
|
+
.new({}, ::ActiveRecord::Relation::WhereClause.empty, [])
|
10
|
+
|
11
|
+
def preload(records, associations, preload_scope = nil)
|
12
|
+
records = Array.wrap(records).compact.uniq
|
13
|
+
associations = Array.wrap(associations)
|
14
|
+
preload_scope ||= nil
|
15
|
+
|
16
|
+
return [] if records.empty?
|
17
|
+
|
18
|
+
any_specified_fields = relation_klass.present? && assoc_select_fields.is_a?(Hash)
|
19
|
+
indexed_reflections = relation_klass.reflections.map { |k, r| [k, r.class_name] }.to_h if any_specified_fields
|
20
|
+
associations.flat_map do |association|
|
21
|
+
if any_specified_fields && indexed_reflections.key?(association.to_s)
|
22
|
+
preloaders_on(
|
23
|
+
association,
|
24
|
+
records,
|
25
|
+
indexed_reflections[association.to_s].constantize.select(assoc_select_fields[association])
|
26
|
+
)
|
27
|
+
else
|
28
|
+
preloaders_on association, records, preload_scope
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssociationSelection
|
4
|
+
module V5
|
5
|
+
module Relation
|
6
|
+
def build_preloader
|
7
|
+
ActiveRecord::Associations::Preloader.new.tap do |new_preloader|
|
8
|
+
new_preloader.assoc_select_fields = assoc_select_fields
|
9
|
+
new_preloader.relation_klass = model
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssociationSelection
|
4
|
+
module V6
|
5
|
+
module Relation
|
6
|
+
def preload_associations(records) # :nodoc:
|
7
|
+
preload = preload_values
|
8
|
+
preload += includes_values unless eager_loading?
|
9
|
+
preloader = nil
|
10
|
+
|
11
|
+
any_specified_fields = assoc_select_fields.is_a?(Hash)
|
12
|
+
indexed_reflections = model.reflections.map { |k, r| [k, r.class_name] }.to_h if any_specified_fields
|
13
|
+
preload.each do |associations|
|
14
|
+
preloader ||= build_preloader
|
15
|
+
if any_specified_fields && indexed_reflections.key?(associations.to_s)
|
16
|
+
preloader.preload(
|
17
|
+
records,
|
18
|
+
associations,
|
19
|
+
indexed_reflections[associations.to_s].constantize.select(assoc_select_fields[associations])
|
20
|
+
)
|
21
|
+
else
|
22
|
+
preloader.preload records, associations
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AssociationSelection
|
4
|
+
module V7
|
5
|
+
module Relation
|
6
|
+
def preload_associations(records) # :nodoc:
|
7
|
+
preload = preload_values
|
8
|
+
preload += includes_values unless eager_loading?
|
9
|
+
scope = strict_loading_value ? StrictLoadingScope : nil
|
10
|
+
any_specified_fields = scope.nil? && assoc_select_fields.is_a?(Hash)
|
11
|
+
indexed_reflections = model.reflections.map { |k, r| [k, r.class_name] }.to_h if any_specified_fields
|
12
|
+
preload.each do |associations|
|
13
|
+
if any_specified_fields && indexed_reflections.key?(associations.to_s)
|
14
|
+
scope = indexed_reflections[associations.to_s].constantize.select(assoc_select_fields[associations])
|
15
|
+
end
|
16
|
+
ActiveRecord::Associations::Preloader.new(records: records, associations: associations, scope: scope).call
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'association_selection/version'
|
4
|
+
require_relative 'association_selection/querying'
|
5
|
+
|
6
|
+
module AssociationSelection
|
7
|
+
def self.setup
|
8
|
+
ActiveSupport.on_load(:active_record) do |base|
|
9
|
+
base.extend AssociationSelection::Delegations
|
10
|
+
ActiveRecord::Relation.include AssociationSelection::Querying
|
11
|
+
|
12
|
+
if ActiveRecord.version >= Gem::Version.new('7.0')
|
13
|
+
require_relative 'association_selection/v7/relation'
|
14
|
+
ActiveRecord::Relation.prepend AssociationSelection::V7::Relation
|
15
|
+
elsif ActiveRecord.version >= Gem::Version.new('6.0')
|
16
|
+
require_relative 'association_selection/v6/relation'
|
17
|
+
ActiveRecord::Relation.prepend AssociationSelection::V6::Relation
|
18
|
+
else
|
19
|
+
require_relative 'association_selection/v5/relation'
|
20
|
+
require_relative 'association_selection/v5/preloader'
|
21
|
+
ActiveRecord::Associations::Preloader.prepend AssociationSelection::V5::Preloader
|
22
|
+
ActiveRecord::Relation.prepend AssociationSelection::V5::Relation
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
AssociationSelection.setup
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: association_selection
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vương Khải Hà
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-11-21 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Provides functionality to specify fields to preload for ActiveRecord
|
14
|
+
associations.
|
15
|
+
email:
|
16
|
+
- inki.personal@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- README.md
|
22
|
+
- Rakefile
|
23
|
+
- lib/association_selection.rb
|
24
|
+
- lib/association_selection/querying.rb
|
25
|
+
- lib/association_selection/v5/preloader.rb
|
26
|
+
- lib/association_selection/v5/relation.rb
|
27
|
+
- lib/association_selection/v6/relation.rb
|
28
|
+
- lib/association_selection/v7/relation.rb
|
29
|
+
- lib/association_selection/version.rb
|
30
|
+
homepage: https://github.com/vuong-khai-ha/association_selection
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata:
|
34
|
+
rubygems_mfa_required: 'true'
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '2.0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubygems_version: 3.5.22
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: Select fields for ActiveRecord associations
|
54
|
+
test_files: []
|