nested_select 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4307dec9a6ddcdc24842d6c3f155b2c2d9e64cc6a1f66049134ad80ef2cde41
4
- data.tar.gz: 7c8fca2b94e90e6361d54c4dfe51d444a42fb60d0be48c487978a98ddf1eb1a0
3
+ metadata.gz: f7df4328a84a6701ef2081be1b647cd9f1c07442b6dfd48c580126daa369ef80
4
+ data.tar.gz: 17fd02a9b6f0bf767b55bae9243534030a4ccd7d524ff0c72cd3f62ab4e7b46c
5
5
  SHA512:
6
- metadata.gz: 40421aa19cf4f21d42326e9e350f83282fa51d82f49945367265864e2761af9d4c72499cabf82be93cdb2d80486c2593f5df3dd6d218b49c3868b72b8f13a701
7
- data.tar.gz: 4133532cf6a4884b0195212cb2f1eb36a0b326bda5defd5d2498def327d89692d9df86487df40e59c7becfceddde3124ca02db0babd930c5b4f19314a8c6f09e
6
+ metadata.gz: 413915e07ba1daa75689c3863f8b6084aaaacace89afe075aaf115a61b6c34245acee01c4eae87ec9509bf7ce0d0b38e9f4fa4a6e17d341177a71d1cb5e31d42
7
+ data.tar.gz: d955c8d791e58df7025998c69a43bf459c03897384c2c68658e03600ba63158678012c90fded55f35fb8acc64fa652d255381d7164077dbe9c01febddf23d1e8
data/.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/nested_select.iml" filepath="$PROJECT_DIR$/.idea/nested_select.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,125 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="ModuleRunConfigurationManager">
4
+ <shared />
5
+ </component>
6
+ <component name="NewModuleRootManager">
7
+ <content url="file://$MODULE_DIR$">
8
+ <sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
9
+ <sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
10
+ <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
11
+ </content>
12
+ <orderEntry type="jdk" jdkName="RVM: ruby-3.3.4 [ns1]" jdkType="RUBY_SDK" />
13
+ <orderEntry type="sourceFolder" forTests="false" />
14
+ <orderEntry type="library" scope="PROVIDED" name="actionpack (v8.0.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="actionview (v8.0.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="activemodel (v8.0.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="activerecord (v8.0.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
18
+ <orderEntry type="library" scope="PROVIDED" name="activesupport (v8.0.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="amazing_print (v1.7.2, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
20
+ <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="benchmark (v0.4.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="bigdecimal (v3.1.9, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="builder (v3.3.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
24
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v2.5.11, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
25
+ <orderEntry type="library" scope="PROVIDED" name="byebug (v11.1.3, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
26
+ <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.3.4, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
27
+ <orderEntry type="library" scope="PROVIDED" name="connection_pool (v2.5.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
28
+ <orderEntry type="library" scope="PROVIDED" name="crass (v1.0.6, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
29
+ <orderEntry type="library" scope="PROVIDED" name="date (v3.4.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
30
+ <orderEntry type="library" scope="PROVIDED" name="drb (v2.2.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
31
+ <orderEntry type="library" scope="PROVIDED" name="erubi (v1.13.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
32
+ <orderEntry type="library" scope="PROVIDED" name="i18n (v1.14.6, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
33
+ <orderEntry type="library" scope="PROVIDED" name="io-console (v0.8.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
34
+ <orderEntry type="library" scope="PROVIDED" name="irb (v1.14.3, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
35
+ <orderEntry type="library" scope="PROVIDED" name="json (v2.9.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
36
+ <orderEntry type="library" scope="PROVIDED" name="language_server-protocol (v3.17.0.3, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
37
+ <orderEntry type="library" scope="PROVIDED" name="logger (v1.6.5, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
38
+ <orderEntry type="library" scope="PROVIDED" name="loofah (v2.24.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
39
+ <orderEntry type="library" scope="PROVIDED" name="minitest (v5.25.4, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
40
+ <orderEntry type="library" scope="PROVIDED" name="niceql (v0.6.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
41
+ <orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.18.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
42
+ <orderEntry type="library" scope="PROVIDED" name="parallel (v1.26.3, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
43
+ <orderEntry type="library" scope="PROVIDED" name="parser (v3.3.6.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
44
+ <orderEntry type="library" scope="PROVIDED" name="psych (v5.2.3, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
45
+ <orderEntry type="library" scope="PROVIDED" name="racc (v1.8.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
46
+ <orderEntry type="library" scope="PROVIDED" name="rack (v3.1.8, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
47
+ <orderEntry type="library" scope="PROVIDED" name="rack-session (v2.1.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
48
+ <orderEntry type="library" scope="PROVIDED" name="rack-test (v2.2.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
49
+ <orderEntry type="library" scope="PROVIDED" name="rackup (v2.2.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
50
+ <orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v2.2.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
51
+ <orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.6.2, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
52
+ <orderEntry type="library" scope="PROVIDED" name="rails-i18n (v8.0.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
53
+ <orderEntry type="library" scope="PROVIDED" name="rails_sql_prettifier (v7.0.4, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
54
+ <orderEntry type="library" scope="PROVIDED" name="railties (v8.0.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
55
+ <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
56
+ <orderEntry type="library" scope="PROVIDED" name="rake (v13.2.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
57
+ <orderEntry type="library" scope="PROVIDED" name="rdoc (v6.11.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
58
+ <orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.10.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
59
+ <orderEntry type="library" scope="PROVIDED" name="reline (v0.6.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
60
+ <orderEntry type="library" scope="PROVIDED" name="rubocop (v1.70.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
61
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.37.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
62
+ <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.13.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
63
+ <orderEntry type="library" scope="PROVIDED" name="securerandom (v0.4.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
64
+ <orderEntry type="library" scope="PROVIDED" name="sqlite3 (v2.5.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
65
+ <orderEntry type="library" scope="PROVIDED" name="stringio (v3.1.2, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
66
+ <orderEntry type="library" scope="PROVIDED" name="stubberry (v0.3.0, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
67
+ <orderEntry type="library" scope="PROVIDED" name="thor (v1.3.2, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
68
+ <orderEntry type="library" scope="PROVIDED" name="timeout (v0.4.3, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
69
+ <orderEntry type="library" scope="PROVIDED" name="tzinfo (v2.0.6, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
70
+ <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v3.1.3, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
71
+ <orderEntry type="library" scope="PROVIDED" name="unicode-emoji (v4.0.4, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
72
+ <orderEntry type="library" scope="PROVIDED" name="uri (v1.0.2, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
73
+ <orderEntry type="library" scope="PROVIDED" name="useragent (v0.16.11, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
74
+ <orderEntry type="library" scope="PROVIDED" name="zeitwerk (v2.7.1, RVM: ruby-3.3.4 [ns1]) [gem]" level="application" />
75
+ </component>
76
+ <component name="RakeTasksCache-v2">
77
+ <option name="myRootTask">
78
+ <RakeTaskImpl id="rake">
79
+ <subtasks>
80
+ <RakeTaskImpl description="Build nested_select-0.2.0.gem into the pkg directory" fullCommand="build" id="build" />
81
+ <RakeTaskImpl id="build">
82
+ <subtasks>
83
+ <RakeTaskImpl description="Generate SHA512 checksum of nested_select-0.2.0.gem into the checksums directory" fullCommand="build:checksum" id="checksum" />
84
+ </subtasks>
85
+ </RakeTaskImpl>
86
+ <RakeTaskImpl description="Remove any temporary products" fullCommand="clean" id="clean" />
87
+ <RakeTaskImpl description="Remove any generated files" fullCommand="clobber" id="clobber" />
88
+ <RakeTaskImpl description="Build and install nested_select-0.2.0.gem into system gems" fullCommand="install" id="install" />
89
+ <RakeTaskImpl id="install">
90
+ <subtasks>
91
+ <RakeTaskImpl description="Build and install nested_select-0.2.0.gem into system gems without network access" fullCommand="install:local" id="local" />
92
+ </subtasks>
93
+ </RakeTaskImpl>
94
+ <RakeTaskImpl description="Create tag v0.2.0 and build and push nested_select-0.2.0.gem to https://rubygems.org" fullCommand="release[remote]" id="release[remote]" />
95
+ <RakeTaskImpl description="Run RuboCop" fullCommand="rubocop" id="rubocop" />
96
+ <RakeTaskImpl id="rubocop">
97
+ <subtasks>
98
+ <RakeTaskImpl description="Autocorrect RuboCop offenses (only when it's safe)" fullCommand="rubocop:autocorrect" id="autocorrect" />
99
+ <RakeTaskImpl description="Autocorrect RuboCop offenses (safe and unsafe)" fullCommand="rubocop:autocorrect_all" id="autocorrect_all" />
100
+ <RakeTaskImpl description="" fullCommand="rubocop:auto_correct" id="auto_correct" />
101
+ </subtasks>
102
+ </RakeTaskImpl>
103
+ <RakeTaskImpl description="Run the test suite" fullCommand="test" id="test" />
104
+ <RakeTaskImpl id="test">
105
+ <subtasks>
106
+ <RakeTaskImpl description="Print out the test command" fullCommand="test:cmd" id="cmd" />
107
+ <RakeTaskImpl description="Show which test files fail when run in isolation" fullCommand="test:isolated" id="isolated" />
108
+ <RakeTaskImpl description="Run the test suite and report the slowest 25 tests" fullCommand="test:slow" id="slow" />
109
+ <RakeTaskImpl description="" fullCommand="test:deps" id="deps" />
110
+ </subtasks>
111
+ </RakeTaskImpl>
112
+ <RakeTaskImpl description="" fullCommand="default" id="default" />
113
+ <RakeTaskImpl description="" fullCommand="release" id="release" />
114
+ <RakeTaskImpl id="release">
115
+ <subtasks>
116
+ <RakeTaskImpl description="" fullCommand="release:guard_clean" id="guard_clean" />
117
+ <RakeTaskImpl description="" fullCommand="release:rubygem_push" id="rubygem_push" />
118
+ <RakeTaskImpl description="" fullCommand="release:source_control_push" id="source_control_push" />
119
+ </subtasks>
120
+ </RakeTaskImpl>
121
+ </subtasks>
122
+ </RakeTaskImpl>
123
+ </option>
124
+ </component>
125
+ </module>
data/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
data/.rubocop.yml CHANGED
@@ -6,3 +6,86 @@ Style/StringLiterals:
6
6
 
7
7
  Style/StringLiteralsInInterpolation:
8
8
  EnforcedStyle: double_quotes
9
+
10
+ Style/SingleLineMethods:
11
+ Description: 'Avoid single-line methods.'
12
+ StyleGuide: '#no-single-line-methods'
13
+ Enabled: false
14
+ VersionAdded: '0.9'
15
+ VersionChanged: '1.8'
16
+ AllowIfMethodIsEmpty: true
17
+
18
+ Style/AsciiComments:
19
+ Description: 'Use only ascii symbols in comments.'
20
+ StyleGuide: '#english-comments'
21
+ Enabled: false
22
+ VersionAdded: '0.9'
23
+ VersionChanged: '1.21'
24
+ AllowedChars:
25
+ - ©
26
+
27
+ Layout/LineLength:
28
+ Description: 'Checks that line length does not exceed the configured limit.'
29
+ StyleGuide: '#max-line-length'
30
+ Enabled: true
31
+ VersionAdded: '0.25'
32
+ VersionChanged: '1.4'
33
+ Max: 120
34
+ # To make it possible to copy or click on URIs in the code, we allow lines
35
+ # containing a URI to be longer than Max.
36
+ AllowHeredoc: true
37
+ AllowURI: true
38
+ URISchemes:
39
+ - http
40
+ - https
41
+ # The IgnoreCopDirectives option causes the LineLength rule to ignore cop
42
+ # directives like '# rubocop: enable ...' when calculating a line's length.
43
+ IgnoreCopDirectives: true
44
+ # The AllowedPatterns option is a list of !ruby/regexp and/or string
45
+ # elements. Strings will be converted to Regexp objects. A line that matches
46
+ # any regular expression listed in this option will be ignored by LineLength.
47
+ AllowedPatterns: []
48
+ IgnoredPatterns: [] # deprecated
49
+ Exclude:
50
+ - "./test/**/*"
51
+
52
+ Metrics/ClassLength:
53
+ Description: 'Avoid classes longer than 100 lines of code.'
54
+ Enabled: false
55
+ VersionAdded: '0.25'
56
+ VersionChanged: '0.87'
57
+ CountComments: false # count full line comments?
58
+ Max: 100
59
+ CountAsOne: []
60
+
61
+ Lint/MissingCopEnableDirective:
62
+ Description: 'Checks for a `# rubocop:enable` after `# rubocop:disable`.'
63
+ Enabled: true
64
+ VersionAdded: '0.52'
65
+ # Maximum number of consecutive lines the cop can be disabled for.
66
+ # 0 allows only single-line disables
67
+ # 1 would mean the maximum allowed is the following:
68
+ # # rubocop:disable SomeCop
69
+ # a = 1
70
+ # # rubocop:enable SomeCop
71
+ # .inf for any size
72
+ MaximumRangeSize: .inf
73
+
74
+ Style/MethodCallWithArgsParentheses:
75
+ Enabled: true
76
+ IgnoredMethods:
77
+ - require
78
+ - require_relative
79
+ - require_dependency
80
+ - yield
81
+ - raise
82
+ - puts
83
+ Exclude:
84
+ - "/**/Gemfile"
85
+
86
+ Style/ClassAndModuleChildren:
87
+ Enabled: false
88
+
89
+ Lint/UnderscorePrefixedVariableName:
90
+ Exclude:
91
+ - "./test/**/**/*"
@@ -0,0 +1,88 @@
1
+ # A little bit of nested_select history
2
+ Awhile ago I've investigated the potential performance boost from partial instantiation
3
+ of database records in rails applications: [Rails nitro-fast collection rendering with PostgreSQL](https://medium.com/@leshchuk/rails-nitro-fast-collection-rendering-with-postgresql-a5fb07cc215f)
4
+
5
+ To be short among the others I've tested the idea of Partial instantiation:
6
+
7
+ > Sometimes different actions needs different set of columns per ORM object. You can speedup instantiation
8
+ > by creating sets of attributes specific for particular request.
9
+ > It can be done through the scopes and scoped relations inside your model.
10
+
11
+ **Pluses**
12
+ > It may be faster. How fast? Highly depends on data structure and ratio of used columns. I started from instantinating 75% of object columns and go to 1 or 2 columns being instantiated.
13
+ > In terms of instantiation results are: 1.3–4.2 times faster on simple type columns ( text, string, int, bool etc.), and 1.2–10 times faster when you exclude json/jsonb/store instantiation.
14
+ > Also all this numbers received without any instantiation callbacks like after_find.
15
+
16
+ Also during my investigations I've kinda missed to mention the other aspects of the problem: RAM, DB IOps, network throughput.
17
+ Requesting less columns improves¹ all that things.
18
+
19
+ [1] I have much less idea on how other than PotsgreSQL DB-engines are working with a disk in terms of partial tuples/records reading.
20
+ Postgres itself will read a whole page from a disk to retrieve the record, but then lesser columns could switch retrieval to an Index-Only scan decreasing IOps significantly
21
+
22
+ But that's a pretty obvious. There are lot of articles covering this problem and idea of a partial selection:
23
+
24
+ ActiveRecord select :id column over 1000 records in a different way:
25
+ https://samsaffron.com/archive/2018/06/01/an-analysis-of-memory-bloat-in-active-record-5-2
26
+
27
+ Just another simple and newbie technics on boosting ActiveRecord ( including partial selection ):
28
+ https://medium.com/@snapsheetclaims/11-ways-to-boost-your-activerecord-query-performance-32b9986f093f
29
+
30
+ Just partial selection article:
31
+ https://pawelurbanek.com/activerecord-memory-usage
32
+
33
+ And others.
34
+
35
+ But the real problem is: **in rails you can't do any selection on preloading models** (until nested_select of course :)) ).
36
+ Ths means that all that tree of preloaded object goes with ```SELECT table_name.*``` query.
37
+
38
+ Technically speaking you may solve this problem by defining custom scopes and defining custom tailored relation with scopes.
39
+ But that's a lot of a boilerplate code, creating scopes and nested relations for all kinds of requests looks like unreal solution,
40
+ no one will do such madness.
41
+
42
+ ## Nested Select patch
43
+
44
+ ### How preloading happens in rails and when is the best time to interfere
45
+
46
+ **Preloading** is a part of activerecord which tends to change pretty often.
47
+ Practically all major releases interfere preloader code, the majority of current implementation was introduced in the rails 7.0 version.
48
+ But if you get the idea of current implementation, you can traverse the earlier state and get the idea how to make them work with nested select:
49
+ Regardless of the major rails version and implementation, you will end up patching the `build_scope` method of
50
+ `ActiveRecord::Associations::Preloader::Association`!
51
+
52
+ So you just need to define a way to deliver select_values to instance of `ActiveRecord::Associations::Preloader::Association`
53
+
54
+ ### How preloading happens in rails >= 7.0
55
+ To be honest ( and opinionated :) ), current preloading implementation is messy,
56
+ and we need to adapt to this mess without delivering some more.
57
+
58
+ Let's look at the scopes example from a specs:
59
+ ```ruby
60
+ # user <-habtm-> bought_items
61
+ # user -> has_one -> user_profile -> has_many -> avatars
62
+ User.includes(:bought_items, user_profile: :avatars)
63
+ ```
64
+
65
+ Preloading will create instances of the `Preloader` class for:
66
+ - each isolated preloading `Branch` which started from the root, in this case: `:bought_items` and `user_profile: :avatars`
67
+ - each trough relation inside preloading tree, including hidden ones like habtm relation does.
68
+
69
+ Each `Preloader` object building it's own preloader tree from a set of `Branch` objects.
70
+ In a given case it might roughly look like this:
71
+ ```
72
+ Preloader(:bought_items) -> Branch(:root)
73
+ \__ Branch(:bought_items) -> Preloader::ThroughAssociation(:bought_items)
74
+
75
+ Preloader(user_profile: :avatars) -> Branch(:root)
76
+ \__ Branch(:user_profile) -> Preloader::Association(:user_profile)
77
+ \__Branch(:avatars) -> Preloader::Association(:avatars)
78
+ ```
79
+
80
+ Each `Branch` will create a set of loaders objects of `Preloader::Association` or `Preloader::ThroughAssociation`
81
+ Then running all of them will preload nested records and establish a connections between records.
82
+
83
+ To be able to select limited attributes sets, we need to deliver them to `Association` level objects, and patch `build_scope` method with it.
84
+
85
+ **_Rem:_** Each `Preloader::ThroughAssociation` object creates it's own `Preloader` and starts additional 'isolated' preloading process.
86
+
87
+ The implementation of nested_select adds a `nested_select_values` attributes into instances of `Preloader`, `Branch`, `Association` hierarchy
88
+ and some methods to populate corresponding select_values over the tree, trying to be as less invasive as it could be.
data/CHANGELOG.md CHANGED
@@ -1,4 +1,17 @@
1
- ## [Unreleased]
1
+ ## [0.3.0] - 2025-01-25
2
+
3
+ - nested_select belongs_to limitation now prevents accidental foreign_key absence
4
+ - primary keys are no longer need to be nested_selected
5
+ - nested selects will combine all selections on multiple select invocations like the usual select values does
6
+ - tests restructured
7
+ - test/README added
8
+ - removed biolerplates for basic selection ( you don't need to specify "table.*" in the root collection seletc )
9
+
10
+ ## [0.2.0] - 2025-01-25
11
+
12
+ - Tests are now a part of this repo
13
+ - Readme cleared out
14
+ - ABOUT_NESTED_SELECT md added.
2
15
 
3
16
  ## [0.1.0] - 2025-01-11
4
17
 
data/Dockerfile ADDED
@@ -0,0 +1,12 @@
1
+ FROM ruby:3.4
2
+
3
+ WORKDIR /app
4
+
5
+ RUN gem install bundler
6
+
7
+ COPY lib/nested_select/version.rb /app/lib/nested_select/version.rb
8
+ COPY nested_select.gemspec /app/
9
+ COPY Gemfile* /app/
10
+ COPY Rakefile /app/
11
+
12
+ RUN bundle install
data/README.md CHANGED
@@ -1,54 +1,71 @@
1
- ## Nested Select patch
1
+ # WIP disclaimer
2
+ The gem is under active development now.
3
+ Use in prod with caution only if you are properly covered by your CI. Read **Safety** and **Limitations** sections before.
2
4
 
3
- ### How preloading happens in rails and when is the best time to interfere
5
+ # Nested select -- 7 times faster and 33 times less RAM on preloading relations with heavy columns!
6
+ nested_select allows the partial selection of the relations attributes during preloading process, leading to less RAM and CPU usage.
7
+ Here is a benchmark output for a [gist I've created](https://gist.github.com/alekseyl/5d08782808a29df6813f16965f70228a) to emulate real-life example: displaying a course with its structure.
4
8
 
5
- **Preloading** is a part of activerecord which tends to change pretty often.
6
- Practically all major releases interfere preloader code, the current implementation was introduced starting rails 7.0 version.
7
- But if you get the idea of current implementation, you can traverse the earlier state and get the idea how to make them work with nested select:
8
- Regardless of the major rails version and implementation, you will end up patching the `build_scope` method of
9
- `ActiveRecord::Associations::Preloader::Association`!
9
+ Given:
10
+ - Models are Course, Topic, Lesson.
11
+ - Their relations has a following structure: course has_many topics, each topic has_many lessons.
12
+ - To display a single course you need its structure, minimum data needed: topic and lessons titles and ordering.
10
13
 
11
- So you just need to define a way to deliver select_values to instance of `ActiveRecord::Associations::Preloader::Association`
14
+ **Single course**, a real prod set of data used by current UI (~ x33 times less RAM):
12
15
 
13
- ### How preloading happens in rails >= 7.0
14
- To be honest ( and opinionated :) ), current preloading implementation is a kinda mess, and we need to adapt to this mess without delivering some more.
15
-
16
- Let's look at the scopes example:
17
- ```ruby
18
- # user <-habtm-> bought_items
19
- # user -> has_one -> user_profile -> has_many -> avatars
20
- User.includes( :bought_items, user_profile: :avatars)
16
+ ```
17
+ irb(main):216:0>compare_nested_select(ids, 1, silence_ar_logger_for_memory_profiling: false)
18
+
19
+ ------- CPU comparison, for root_collection_size: 1 ----
20
+ user system total real
21
+ nested_select 0.096008 0.002876 0.098884 ( 0.466985)
22
+ simple includes 0.209188 0.058340 0.267528 ( 0.903893)
23
+
24
+ ----------------- Memory comparison, for root_collection_size: 1 ---------
25
+
26
+ D, [2025-01-12T19:08:36.163282 #503] DEBUG -- : Topic Load (4.1ms) SELECT "topics"."id", "topics"."position", "topics"."title", "topics"."course_id" FROM "topics" WHERE "topics"."deleted_at" IS NULL AND "topics"."course_id" = $1 [["course_id", 1624]]
27
+ D, [2025-01-12T19:08:36.168803 #503] DEBUG -- : Lesson Load (3.9ms) SELECT "lessons"."id", "lessons"."title", "lessons"."topic_id", "lessons"."position", "lessons"."topic_id" FROM "lessons" WHERE "lessons"."deleted_at" IS NULL AND "lessons"."topic_id" = $1 [["topic_id", 7297]]
28
+ D, [2025-01-12T19:08:37.220379 #503] DEBUG -- : Topic Load (4.2ms) SELECT "topics"."id", "topics"."position", "topics"."title", "topics"."course_id" FROM "topics" WHERE "topics"."deleted_at" IS NULL AND "topics"."course_id" = $1 [["course_id", 1624]]
29
+ D, [2025-01-12T19:08:37.247484 #503] DEBUG -- : Lesson Load (25.7ms) SELECT "lessons".* FROM "lessons" WHERE "lessons"."deleted_at" IS NULL AND "lessons"."topic_id" = $1 [["topic_id", 7297]]
30
+
31
+ ------ Nested Select memory consumption for root_collection_size: 1 ------
32
+ Total allocated: 80.84 kB (972 objects)
33
+ Total retained: 34.67 kB (288 objects)
34
+
35
+ ------ Full preloading memory consumption for root_collection_size: 1 ----
36
+ Total allocated: 1.21 MB (1105 objects)
37
+ Total retained: 1.16 MB (432 objects)
38
+ RAM ratio improvements x33.54678126442086 on retain objects
39
+ RAM ratio improvements x15.002820281285949 on total_allocated objects
21
40
  ```
22
41
 
23
- Preloading will create instances `Preloader` objects for:
24
- - each isolated preloading `Branch` which started from the root, in this case: `:bought_items` and `user_profile: :avatars`
25
- - each trough relation inside preloading tree, including hidden ones like habtm relation does.
42
+ **100 courses**, this is kinda a synthetic example (there is no UI for multiple courses display with their structure)
43
+ on the real prod data, but the bigger than needed collection (x7 faster):
26
44
 
27
- Each `Preloader` object building it's own preloader tree from a set of `Branch` objects.
28
- In a given case it might roughly look like this:
29
- ```
30
- Preloader(:bought_items) -> Branch(:root)
31
- \__ Branch(:bought_items) -> Preloader::ThroughAssociation(:bought_items)
32
-
33
- Preloader(user_profile: :avatars) -> Branch(:root)
34
- \__ Branch(:user_profile) -> Preloader::Association(:user_profile)
35
- \__Branch(:avatars) -> Preloader::Association(:avatars)
36
45
  ```
46
+ irb(main):280:0> compare_nested_select(ids, 100)
37
47
 
38
- Each `Branch` will create a set of loaders objects of `Preloader::Association` or `Preloader::ThroughAssociation`
39
- Then running all of them will preload nested records and establish a connections between records.
48
+ ------- CPU comparison, for root_collection_size: 100 ----
49
+ user system total real
50
+ nested_select 1.571095 0.021778 1.592873 ( 2.263369)
51
+ simple includes 5.374909 1.704284 7.079193 ( 15.488579)
52
+
53
+ ----------------- Memory comparison, for root_collection_size: 100 ---------
54
+ ------ Nested Select memory consumption for root_collection_size: 100 ------
40
55
 
41
- To be able to select limited attributes sets, we need to deliver them to `Association` level objects, and patch `build_scope` method with it.
56
+ Total allocated: 2.79 MB (30702 objects)
57
+ Total retained: 2.05 MB (16431 objects)
42
58
 
43
- **_Rem:_** Each `Preloader::ThroughAssociation` object creates it's own `Preloader` and starts additional 'isolated' preloading process.
59
+ ------ Full preloading memory consumption for root_collection_size: 100 ----
44
60
 
45
- So implementation adds a `nested_select_values` attributes into instances of `Preloader`, `Branch`, `Association` hierarchy and some methods to populate corresponding select_values over the tree.
61
+ Total allocated: 33.05 MB (38332 objects)
62
+ Total retained: 32.00 MB (24057 objects)
63
+ RAM ratio improvements x15.57707431190517 on retain objects
64
+ RAM ratio improvements x11.836000856510193 on total_allocated objects
46
65
 
47
- ## Installation
66
+ ```
48
67
 
49
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org.
50
- Please do not do it earlier due to security reasons.
51
- Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
68
+ ## Installation
52
69
 
53
70
  Install the gem and add to the application's Gemfile by executing:
54
71
 
@@ -56,21 +73,85 @@ Install the gem and add to the application's Gemfile by executing:
56
73
 
57
74
  If bundler is not being used to manage dependencies, install the gem by executing:
58
75
 
59
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
76
+ $ gem install nested_select
60
77
 
61
78
  ## Usage
79
+ Assume you have a relation users <- profile, and you want to preview users in a paginated feed,
80
+ and you need only :photo_url attribute of a profile, with nested_select you can do it like this:
81
+
82
+ ```ruby
83
+ class User
84
+ has_one :profile
85
+ end
86
+
87
+ class Profile
88
+ belongs_to :user
89
+ end
90
+
91
+ # this will preload profile with exact attributes:
92
+ # :id -- since its a primary key,
93
+ # :user_id -- since its a foreign_key
94
+ # and the :photo_url as requested
95
+ User.includes(:profile).select(profile: :photo_url).limit(10)
96
+ ```
62
97
 
63
- TODO: Write usage instructions here
98
+ ## Safety
99
+ How safe is the partial model loading? Earlier version of rails and activerecord would return nil in the case,
100
+ when attribute wasn't selected from a DB, but rails 6 started to raise a ActiveModel::MissingAttributeError.
101
+ So the major problem is already solved -- your code will not operate based on falsy blank values, it will raise an exception.
64
102
 
65
- ## Development
103
+ ## belongs_to foreign keys limitations
104
+ Rails preloading happens from loaded record to their reflection step by step.
105
+ That's makes pretty easy to include foreign keys for has_* relations, and very hard for belongs_to,
106
+ to work this out you need to analyze includes based on the already loaded records, analyze and traverse their relations.
107
+ This needs a lot of monkey patching, and for now I decided not to gow this way.
108
+ That means in case when nesting selects based on belongs_to reflections,
109
+ you'll need to select their foreign keys **EXPLICITLY!**
110
+
111
+ ```ruby
112
+ class Avatar < ApplicationRecord
113
+ belongs_to user
114
+ has_one :image
115
+ end
116
+
117
+ class Image < ApplicationRecord
118
+ belongs_to :avatar
119
+ end
120
+
121
+ Image.includes(avatar: :user).select(avatar: [:id, :size, { user: [:email] }]).load # <--- will raise a Missing Attribute exception
122
+
123
+ #> ActiveModel::MissingAttributeError: Parent reflection avatar was missing foreign key user_id in nested selection
124
+ #> while trying to preload belongs_to reflection named user.
125
+ #> Hint: didn't you forgot to add user_id inside [:id, :size]?
126
+
127
+ Image.includes(avatar: :user).select(avatar: [:id, :size, :user_id, { user: [:email] }]).load
128
+ ```
66
129
 
67
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
68
130
 
69
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
131
+ ## Testing
132
+
133
+ ```bash
134
+ docker compose run test
135
+ ```
136
+
137
+ ## TODO
138
+ - [ ] Cover all relation combinations and add missing functionality
139
+ - [x] Ensure relations foreign keys are present on the selection
140
+ - [x] Ensure primary key will be added
141
+ - [-] Ensure belongs_to will add a foreign_key column
142
+ - [ ] Optimize through relations ( since they loading a whole set of attributes )
143
+ - [ ] Separated rails version testing
144
+ - [x] Merge multiple nested selections
145
+ - [x] Don't apply any selection if blank ( allows to limit only part of subselection tree)
146
+ - [x] Allows to use custom attributes
147
+
148
+ ## Development
149
+
70
150
 
71
151
  ## Contributing
72
152
 
73
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/nested_select. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/nested_select/blob/master/CODE_OF_CONDUCT.md).
153
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alekseyl/nested_select. This project is intended to be a safe,
154
+ welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/nested_select/blob/master/CODE_OF_CONDUCT.md).
74
155
 
75
156
  ## License
76
157
 
@@ -0,0 +1,13 @@
1
+ version: "3.7"
2
+
3
+ services:
4
+ test:
5
+ build: .
6
+ image: nested_select
7
+ command: rake test
8
+ volumes:
9
+ - './lib:/app/lib'
10
+ - './test:/app/test'
11
+ - './Gemfile:/app/Gemfile'
12
+ - './Gemfile.lock:/app/Gemfile.lock'
13
+
@@ -0,0 +1,18 @@
1
+ module NestedSelect
2
+ module DeepMerger
3
+
4
+ # {user_profile: [:zip_code]} + {user_profile: [:bio]} -> { user_profile: [:zip_code, :bio] }
5
+ refine Hash do
6
+ def deep_combine(other)
7
+ merge!(other.except(*keys))
8
+ merge!(other.slice(*keys).map{ |key, value| [key, [self[key], value].flatten.deep_combine_elements]}.to_h )
9
+ end
10
+ end
11
+
12
+ refine Array do
13
+ def deep_combine_elements
14
+ [*grep_v(Hash), grep(Hash).inject(&:deep_combine)].uniq.compact
15
+ end
16
+ end
17
+ end
18
+ end
@@ -4,12 +4,12 @@ module NestedSelect
4
4
  attr_reader :nested_select_values
5
5
 
6
6
  def build_scope
7
- nested_select_values.blank? ? super
8
- : super.select(*nested_select_values)
7
+ nested_select_values.blank? ? super : super.select(*nested_select_values)
9
8
  end
10
9
 
11
- def apply_nested_select_values( partial_select_values )
12
- @nested_select_values = [*partial_select_values, reflection.foreign_key].uniq
10
+ def apply_nested_select_values(partial_select_values)
11
+ foreign_key = reflection.foreign_key unless reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection)
12
+ @nested_select_values = [*partial_select_values, *foreign_key, *reflection.klass.primary_key].uniq
13
13
  end
14
14
  end
15
15
  end
@@ -4,11 +4,29 @@ module NestedSelect
4
4
  module Branch
5
5
  attr_accessor :nested_select_values
6
6
  def preloaders_for_reflection(reflection, reflection_records)
7
+ prevent_belongs_to_foreign_key_absence!(reflection)
8
+
7
9
  super.tap do |ldrs|
8
10
  ldrs.each{ _1.apply_nested_select_values(nested_select_values) } if nested_select_values.present?
9
11
  end
10
12
  end
11
13
 
14
+ private
15
+ def prevent_belongs_to_foreign_key_absence!(reflection)
16
+ return unless reflection.is_a?(ActiveRecord::Reflection::BelongsToReflection)
17
+
18
+ # ActiveRecord will not raise in case its missing, so we should prevent silent error here
19
+ if parent.nested_select_values.present? &&
20
+ !parent.nested_select_values.map(&:to_sym).include?( reflection.foreign_key.to_sym )
21
+
22
+ raise ActiveModel::MissingAttributeError, <<~ERR
23
+ Parent reflection #{parent.association} was missing foreign key #{reflection.foreign_key} in nested selection,
24
+ while trying to preload belongs_to reflection named #{reflection.name}.
25
+ Hint: didn't you forgot to add #{reflection.foreign_key} inside #{parent.nested_select_values}?
26
+ ERR
27
+ end
28
+ end
29
+
12
30
  end
13
31
  end
14
32
  end
@@ -11,7 +11,7 @@ module NestedSelect
11
11
  end
12
12
 
13
13
  def apply_nested_select_values( partial_select_values )
14
- return super unless reflection.parent_reflection.is_a?( ActiveRecord::Reflection::HasAndBelongsToManyReflection )
14
+ return super unless reflection.parent_reflection.is_a?( ActiveRecord::Reflection::HasAndBelongsToManyReflection)
15
15
 
16
16
  # when parent reflection is a HasAndBelongsToManyReflection,
17
17
  # then we don't need foreign_key to be included, as it does in super
@@ -3,14 +3,14 @@ module NestedSelect
3
3
  extend ActiveSupport::Autoload
4
4
  extend ActiveSupport::Concern
5
5
 
6
- autoload :Branch, "brest/nested_select/preloader/branch"
7
- autoload :ThroughAssociation, "brest/nested_select/preloader/through_association"
8
- autoload :Association, "brest/nested_select/preloader/association"
6
+ autoload :Branch, "nested_select/preloader/branch"
7
+ autoload :ThroughAssociation, "nested_select/preloader/through_association"
8
+ autoload :Association, "nested_select/preloader/association"
9
9
 
10
10
  included do
11
11
  ActiveRecord::Associations::Preloader::Branch.prepend(Branch)
12
- ActiveRecord::Associations::Preloader::ThroughAssociation.prepend( ThroughAssociation )
13
- ActiveRecord::Associations::Preloader::Association.prepend( Association )
12
+ ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(ThroughAssociation)
13
+ ActiveRecord::Associations::Preloader::Association.prepend(Association)
14
14
  end
15
15
  def apply_nested_select_values(nested_select_values)
16
16
  distribute_nested_select_over_loading_tree(@tree, nested_select_values)
@@ -26,8 +26,8 @@ module NestedSelect
26
26
  # it could be a case when selection tree is not that deep than Branch tree.
27
27
  return if sub_nested_select_values.blank?
28
28
 
29
- sub_tree.children.each do
30
- distribute_nested_select_over_loading_tree( _1, sub_nested_select_values[_1.association])
29
+ sub_tree.children.each do |chld_brnch|
30
+ distribute_nested_select_over_loading_tree(chld_brnch, sub_nested_select_values[chld_brnch.association])
31
31
  end
32
32
  end
33
33
  end
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
+ require_relative "deep_merger"
2
3
 
3
4
  module NestedSelect
4
5
  module Relation
6
+ using ::NestedSelect::DeepMerger
5
7
 
6
8
  attr_accessor :nested_select_values
7
9
  def select(*fields)
8
- @nested_select_values = fields.grep(Hash)
9
- super(*fields.grep_v(Hash))
10
+ # {user_profile: [:zip_code]} + {user_profile: [:bio]} -> { user_profile: [:zip_code, :bio] }
11
+ @nested_select_values = [*@nested_select_values, *fields.grep(Hash)].deep_combine_elements
12
+ fields.grep_v(Hash).present? ? super(*fields.grep_v(Hash)) : self
10
13
  end
11
14
 
12
15
  def preload_associations(records) # :nodoc:
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NestedSelect
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/nested_select.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  require_relative "nested_select/version"
4
3
 
5
4
  module NestedSelect
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nested_select
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - alekseyl
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-01-11 00:00:00.000000000 Z
11
+ date: 2025-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -38,6 +38,146 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rails-i18n
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
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
+ - !ruby/object:Gem::Dependency
112
+ name: byebug
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: stubberry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rails_sql_prettifier
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: amazing_print
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rubocop-shopify
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
41
181
  description: ActiveRecord improved select on nested models, allows partial instantiation
42
182
  on nested models, easy one step improvements on performance and memory
43
183
  email:
@@ -49,13 +189,20 @@ files:
49
189
  - ".idea/.gitignore"
50
190
  - ".idea/inspectionProfiles/profiles_settings.xml"
51
191
  - ".idea/misc.xml"
192
+ - ".idea/modules.xml"
193
+ - ".idea/nested_select.iml"
194
+ - ".idea/vcs.xml"
52
195
  - ".rubocop.yml"
196
+ - ABOUT_NESTED_SELECT.md
53
197
  - CHANGELOG.md
54
198
  - CODE_OF_CONDUCT.md
199
+ - Dockerfile
55
200
  - LICENSE.txt
56
201
  - README.md
57
202
  - Rakefile
203
+ - docker-compose.yml
58
204
  - lib/nested_select.rb
205
+ - lib/nested_select/deep_merger.rb
59
206
  - lib/nested_select/preloader.rb
60
207
  - lib/nested_select/preloader/association.rb
61
208
  - lib/nested_select/preloader/branch.rb