better_pluck 1.0.0 → 1.0.1
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 +4 -4
- data/README.md +5 -18
- data/lib/better_pluck/{pluck_with_methods.rb → struct_pluck.rb} +29 -27
- data/lib/better_pluck/version.rb +1 -1
- data/lib/better_pluck.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30cec08ad4a30c45757e0c5cc9043c5748f092b7657faae3610f17888404bb80
|
|
4
|
+
data.tar.gz: 9309acc55f803205de2fb2e0a2055df8d6b56e1d45f13ee2f0884265b67b17bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 524eaeb0e4f7d7c4677cf5a8fdb42a8fc5bfc6768a963c7212d6cc74aa1a61b86f144f45545d10cff6f74c61f3b12f17bd0acae7e939001b81ae7574b0c38537
|
|
7
|
+
data.tar.gz: d2c359630bfcbe6f1b71cc3115f7df5f72b2a29e72cc317bfa76753431aef46b6f001214dbca87afd82e8bf2341d88c9ef7c9eeffdab7b1fdec70b96aee16266
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
Main purpose is to reduce loading into memory expensive ActiveRecord objects, where it is not needed (for read-only operations).
|
|
5
5
|
|
|
6
|
-
`better_pluck` adds `
|
|
6
|
+
`better_pluck` adds `struct_pluck`, `struct_pluck_with_display_name` to ActiveRecord. These methods allow you to pluck not only database columns but also virtual methods and association data, returning lightweight `Struct` objects instead of heavy ActiveRecord instances.
|
|
7
7
|
|
|
8
8
|
This approach can reduce memory usage by up to 3-20x compared to loading full ActiveRecord objects.
|
|
9
9
|
|
|
@@ -17,10 +17,6 @@ Add this line to your application's Gemfile:
|
|
|
17
17
|
gem 'better_pluck'
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
And then execute:
|
|
21
|
-
|
|
22
|
-
$ bundle install
|
|
23
|
-
|
|
24
20
|
## Usage
|
|
25
21
|
|
|
26
22
|
### Basic usage
|
|
@@ -29,7 +25,7 @@ You can pluck database columns and instance methods:
|
|
|
29
25
|
|
|
30
26
|
```ruby
|
|
31
27
|
# Assuming Article has a method :name_on_site
|
|
32
|
-
articles = Article.
|
|
28
|
+
articles = Article.struct_pluck(:id, :name, :email, :name_on_site)
|
|
33
29
|
|
|
34
30
|
articles.first.id # => 1
|
|
35
31
|
articles.first.name_on_site # => "My Article" (virtual method)
|
|
@@ -40,7 +36,7 @@ articles.first.name_on_site # => "My Article" (virtual method)
|
|
|
40
36
|
You can also pluck data from nested associations:
|
|
41
37
|
|
|
42
38
|
```ruby
|
|
43
|
-
articles = Article.
|
|
39
|
+
articles = Article.struct_pluck(
|
|
44
40
|
:id,
|
|
45
41
|
:name,
|
|
46
42
|
author: [:name, :email, :display_name]
|
|
@@ -56,24 +52,15 @@ A convenience method specifically for dropdown lists and collections:
|
|
|
56
52
|
|
|
57
53
|
```ruby
|
|
58
54
|
# Automatically includes :display_name for the model and associations
|
|
59
|
-
articles = Article.
|
|
55
|
+
articles = Article.struct_pluck_with_display_name(:id, :name, author: [:name, :email])
|
|
60
56
|
|
|
61
57
|
articles.first.display_name # => "Article Name"
|
|
62
58
|
articles.first.author.display_name # => "Author Name <author@example.com>"
|
|
63
59
|
```
|
|
64
60
|
|
|
65
|
-
## How it works
|
|
66
|
-
|
|
67
|
-
1. **Parsing**: It parses the requested fields to distinguish between database columns, methods, and associations.
|
|
68
|
-
2. **Joining**: It automatically applies `left_joins` for requested associations.
|
|
69
|
-
3. **Plucking**: It uses the standard ActiveRecord `pluck` to fetch only the required database columns.
|
|
70
|
-
4. **Struct Generation**: It creates a `Struct` class (cached for performance) and injects the source code of requested instance methods into it.
|
|
71
|
-
5. **Instantiation**: It maps the raw data into these `Struct` objects.
|
|
72
|
-
|
|
73
|
-
|
|
74
61
|
### select_with_joins method
|
|
75
62
|
|
|
76
|
-
You can use the `select_with_joins` method which will create field aliases for associations instead of fully fetching activerecord objects for them. The main model can be selected with specific columns or fully fetched.
|
|
63
|
+
You can use the `select_with_joins` method which will create field aliases for associations instead of fully fetching activerecord objects for them. The main model can be selected with specific columns or fully fetched. Main model is kept as ActiveRecord object.
|
|
77
64
|
|
|
78
65
|
```ruby
|
|
79
66
|
# Example with positional arguments for base model
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# this module is supposed to be included in ActiveRecord descendants
|
|
2
2
|
# to reduce ram usage by converting arrays of AR objects to Struct objects
|
|
3
|
-
# in particular for dropdown lists (in f.input collection: Article.
|
|
3
|
+
# in particular for dropdown lists (in f.input collection: Article.struct_pluck(:id,:name,:email), as: :select)
|
|
4
4
|
# also takes associations display_name from their ActiveRecord class
|
|
5
|
-
# usage: zones = Zone.
|
|
5
|
+
# usage: zones = Zone.struct_pluck_with_display_name(:id,:name, partner: [:имя,:email], location: [:name])
|
|
6
6
|
# zones.first.display_name, zones.first.partner.display_name
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
#example: articles = Article.
|
|
8
|
+
#struct_pluck method also available where you can list any fields and methods
|
|
9
|
+
#example: articles = Article.struct_pluck(:id, :name, :email, :name_on_site, author: [:name, :email,:display_name])
|
|
10
10
|
#
|
|
11
11
|
#in returned result you can use:
|
|
12
12
|
#article.first.name_on_site, article.first.author.email, articles.first.author.display_name etc.
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
#NK 2026-10-13, done with Gemini AI
|
|
17
17
|
|
|
18
|
-
module BetterPluck::
|
|
18
|
+
module BetterPluck::StructPluck
|
|
19
19
|
extend ActiveSupport::Concern
|
|
20
20
|
|
|
21
21
|
# Use Concurrent::Map for thread-safe caching across multiple Puma threads
|
|
@@ -23,33 +23,33 @@ module BetterPluck::PluckWithMethods
|
|
|
23
23
|
|
|
24
24
|
class_methods do
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# usage: zones = Zone.pluck_with_methods(:id, :name, :display_name, partner: [:имя, :email, :display_name], location: [:name, :display_name])
|
|
29
|
-
def pluck_with_methods(*fields_and_methods)
|
|
26
|
+
# usage: zones = Zone.struct_pluck(:id, :name, :display_name, partner: [:имя, :email, :display_name], location: [:name, :display_name])
|
|
27
|
+
def struct_pluck(*fields_and_methods)
|
|
30
28
|
require "method_source" unless defined?(MethodSource)
|
|
31
29
|
|
|
32
|
-
metadata =
|
|
30
|
+
metadata = _struct_pluck_parse_fields(self, fields_and_methods)
|
|
33
31
|
pluck_columns = []
|
|
34
|
-
|
|
32
|
+
_struct_pluck_build_columns(self, metadata, pluck_columns, self.table_name)
|
|
35
33
|
|
|
36
|
-
joins_arg =
|
|
34
|
+
joins_arg = _struct_pluck_build_joins(metadata)
|
|
37
35
|
|
|
38
36
|
query = joins_arg.present? ? left_joins(joins_arg) : all
|
|
39
37
|
raw_rows = query.pluck(*pluck_columns)
|
|
40
38
|
|
|
41
39
|
# Root struct class
|
|
42
|
-
root_struct_klass =
|
|
40
|
+
root_struct_klass = _struct_pluck_get_struct(metadata)
|
|
43
41
|
|
|
44
42
|
raw_rows.map do |row|
|
|
45
43
|
row_data = row.is_a?(Array) ? row.dup : [row]
|
|
46
|
-
|
|
44
|
+
_struct_pluck_instantiate(root_struct_klass, metadata, row_data)
|
|
47
45
|
end
|
|
48
46
|
end
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
alias_method :pluck_with_methods, :struct_pluck
|
|
49
|
+
|
|
50
|
+
# usage: zones = Zone.struct_pluck_with_display_name(:id,:name, partner: [:имя,:email], location: [:name])
|
|
51
51
|
# zones.first.display_name, zones.first.partner.display_name
|
|
52
|
-
def
|
|
52
|
+
def struct_pluck_with_display_name(*fields_and_methods)
|
|
53
53
|
fields_and_methods << :display_name unless fields_and_methods.include?(:display_name)
|
|
54
54
|
|
|
55
55
|
processed_params = fields_and_methods.map do |arg|
|
|
@@ -64,12 +64,14 @@ module BetterPluck::PluckWithMethods
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
struct_pluck(*processed_params)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
alias_method :pluck_with_display_name, :struct_pluck_with_display_name
|
|
71
|
+
|
|
70
72
|
private
|
|
71
73
|
|
|
72
|
-
def
|
|
74
|
+
def _struct_pluck_parse_fields(klass, fields)
|
|
73
75
|
db_columns = []
|
|
74
76
|
methods = {}
|
|
75
77
|
associations = {}
|
|
@@ -88,7 +90,7 @@ module BetterPluck::PluckWithMethods
|
|
|
88
90
|
assoc_fields = item[assoc_name]
|
|
89
91
|
assoc_reflection = klass.reflect_on_association(assoc_name)
|
|
90
92
|
if assoc_reflection
|
|
91
|
-
associations[assoc_name.to_sym] =
|
|
93
|
+
associations[assoc_name.to_sym] = _struct_pluck_parse_fields(assoc_reflection.klass, Array(assoc_fields))
|
|
92
94
|
all_fields << assoc_name.to_sym
|
|
93
95
|
end
|
|
94
96
|
end
|
|
@@ -119,7 +121,7 @@ module BetterPluck::PluckWithMethods
|
|
|
119
121
|
}
|
|
120
122
|
end
|
|
121
123
|
|
|
122
|
-
def
|
|
124
|
+
def _struct_pluck_build_columns(klass, metadata, list, table_alias)
|
|
123
125
|
metadata[:db_columns].each do |col|
|
|
124
126
|
list << Arel.sql("#{klass.connection.quote_table_name(table_alias)}.#{col}")
|
|
125
127
|
end
|
|
@@ -127,15 +129,15 @@ module BetterPluck::PluckWithMethods
|
|
|
127
129
|
metadata[:associations].each do |assoc_name, sub_metadata|
|
|
128
130
|
assoc_reflection = klass.reflect_on_association(assoc_name)
|
|
129
131
|
# AR's left_joins usually uses the table name for the join alias unless there's a collision
|
|
130
|
-
|
|
132
|
+
_struct_pluck_build_columns(assoc_reflection.klass, sub_metadata, list, assoc_reflection.table_name)
|
|
131
133
|
end
|
|
132
134
|
end
|
|
133
135
|
|
|
134
|
-
def
|
|
136
|
+
def _struct_pluck_build_joins(metadata)
|
|
135
137
|
return nil if metadata[:associations].empty?
|
|
136
138
|
|
|
137
139
|
joins = metadata[:associations].map do |assoc_name, sub_metadata|
|
|
138
|
-
sub_joins =
|
|
140
|
+
sub_joins = _struct_pluck_build_joins(sub_metadata)
|
|
139
141
|
if sub_joins
|
|
140
142
|
{ assoc_name => sub_joins }
|
|
141
143
|
else
|
|
@@ -146,7 +148,7 @@ module BetterPluck::PluckWithMethods
|
|
|
146
148
|
joins.size == 1 ? joins.first : joins
|
|
147
149
|
end
|
|
148
150
|
|
|
149
|
-
def
|
|
151
|
+
def _struct_pluck_get_struct(metadata)
|
|
150
152
|
metadata[:struct_klass] ||= begin
|
|
151
153
|
# 1st list: database fields and associations
|
|
152
154
|
# 2nd list: virtual methods (copied from ActiveRecord)
|
|
@@ -163,19 +165,19 @@ module BetterPluck::PluckWithMethods
|
|
|
163
165
|
end
|
|
164
166
|
end
|
|
165
167
|
|
|
166
|
-
def
|
|
168
|
+
def _struct_pluck_instantiate(struct_klass, metadata, row_data)
|
|
167
169
|
args = metadata[:all_fields].map do |field|
|
|
168
170
|
if metadata[:db_columns].include?(field)
|
|
169
171
|
row_data.shift
|
|
170
172
|
elsif (sub_metadata = metadata[:associations][field])
|
|
171
|
-
sub_struct_klass =
|
|
173
|
+
sub_struct_klass = _struct_pluck_get_struct(sub_metadata)
|
|
172
174
|
sub_col_count = sub_metadata[:total_db_columns]
|
|
173
175
|
|
|
174
176
|
if row_data[0...sub_col_count].all?(&:nil?)
|
|
175
177
|
row_data.shift(sub_col_count)
|
|
176
178
|
nil
|
|
177
179
|
else
|
|
178
|
-
|
|
180
|
+
_struct_pluck_instantiate(sub_struct_klass, sub_metadata, row_data)
|
|
179
181
|
end
|
|
180
182
|
else
|
|
181
183
|
nil # Method field
|
data/lib/better_pluck/version.rb
CHANGED
data/lib/better_pluck.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
require "better_pluck/version"
|
|
2
|
-
require "better_pluck/
|
|
2
|
+
require "better_pluck/struct_pluck"
|
|
3
3
|
require "better_pluck/select_with_joins"
|
|
4
4
|
|
|
5
5
|
module BetterPluck
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
ActiveSupport.on_load(:active_record) do
|
|
9
|
-
include BetterPluck::
|
|
9
|
+
include BetterPluck::StructPluck
|
|
10
10
|
include BetterPluck::SelectWithJoins
|
|
11
11
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: better_pluck
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- NazarK
|
|
@@ -117,8 +117,8 @@ files:
|
|
|
117
117
|
- README.md
|
|
118
118
|
- better_pluck.gemspec
|
|
119
119
|
- lib/better_pluck.rb
|
|
120
|
-
- lib/better_pluck/pluck_with_methods.rb
|
|
121
120
|
- lib/better_pluck/select_with_joins.rb
|
|
121
|
+
- lib/better_pluck/struct_pluck.rb
|
|
122
122
|
- lib/better_pluck/version.rb
|
|
123
123
|
homepage: https://github.com/NazarK/better_pluck
|
|
124
124
|
licenses:
|