deep_preloader 1.0.1 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92fe99d9c1c0a4b426c9827491057c3604e5b511c61c749701de5c65da7d4825
4
- data.tar.gz: efab30b69e968a8a6f45e000da724189808a91dfedb6279930daeb0058ab3557
3
+ metadata.gz: a4d52fcac4fc5b9b0768ecb6dd0c9db5e8ddee7f0ae8d9475ca3364fceb38b9b
4
+ data.tar.gz: a41e279ad07e928fdb36a55c3ba33cacc0e3d4137bc09863b234f5b6ca7be256
5
5
  SHA512:
6
- metadata.gz: 4fed23d8d1df1c47f8665298594adf7741243551f207462eabd74e64e86ead26a977ec39df17d791c0c88f09b22e1958d6120b65820c14b51b313b0cc29e0d7c
7
- data.tar.gz: a94f34a7290e83b7f26cbbcdba8ad51445bfd9f1474e2d9ba8f01449196b51a8e44789c8d81114c91a7e647af194331002fe1a1e48c9dedcfab1999ef9fdfc16
6
+ metadata.gz: 400bfd0eb4d794f3d1b1074e422788a27114dfd8d606dbc8334a08c8cfb31e02e39e55bc02cd13132419238c2d09921a73f8f8ad989b40244d4504dccc3a00c7
7
+ data.tar.gz: 1eb00d062a73b0d5d8ae94451ee638db04f616f9c535c5154f4db855d048d16604ea129620f0f81708980933c83b845a309bc0a1eb7df1aa54ea74c8f001a9a9
@@ -0,0 +1,31 @@
1
+ name: Publish Ruby Gem
2
+
3
+ on:
4
+ push:
5
+ branches: [ "master" ]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ packages: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v3
17
+ - name: Set up Ruby 2.7
18
+ uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: 2.7
21
+
22
+ - name: Publish to RubyGems
23
+ run: |
24
+ mkdir -p $HOME/.gem
25
+ touch $HOME/.gem/credentials
26
+ chmod 0600 $HOME/.gem/credentials
27
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
28
+ gem build *.gemspec
29
+ gem push *.gem
30
+ env:
31
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
@@ -0,0 +1,50 @@
1
+ name: Run Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches: "**"
6
+
7
+ permissions:
8
+ contents: read
9
+ checks: write
10
+ pull-requests: write
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ ruby-version: ['2.7', '3.1', '3.2']
20
+ include:
21
+ - ruby-version: '2.7'
22
+ bundle-gemfile: gemfiles/activerecord_5_2.gemfile
23
+ - ruby-version: '3.1'
24
+ bundle-gemfile: gemfiles/activerecord_6_1.gemfile
25
+ - ruby-version: '3.2'
26
+ bundle-gemfile: gemfiles/activerecord_7_0.gemfile
27
+ env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
28
+ BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.bundle-gemfile }}
29
+ steps:
30
+ - uses: actions/checkout@v3
31
+ - name: Set up Ruby
32
+ uses: ruby/setup-ruby@v1
33
+ with:
34
+ ruby-version: ${{ matrix.ruby-version }}
35
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
36
+ - name: Run tests
37
+ run: bundle exec rspec --profile 10 --format RspecJunitFormatter --out test_results/rspec.xml --format progress
38
+ - name: Upload result
39
+ uses: actions/upload-artifact@v3
40
+ if: always()
41
+ with:
42
+ name: rspec_${{ matrix.ruby-version }}.xml
43
+ path: test_results/rspec.xml
44
+ - name: Test Report
45
+ uses: dorny/test-reporter@v1
46
+ if: always()
47
+ with:
48
+ name: Rspec Tests - ${{ matrix.ruby-version }}
49
+ path: test_results/rspec.xml
50
+ reporter: java-junit
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  gemfiles/*.gemfile.lock
11
+ /nix/gem
@@ -3,6 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "rspec_junit_formatter"
6
- gem "activerecord", "~> 6.0.0.beta"
6
+ gem "activerecord", "~> 6.1.0"
7
7
 
8
8
  gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec_junit_formatter"
6
+ gem "activerecord", "~> 7.0.0"
7
+
8
+ gemspec path: "../"
@@ -2,4 +2,8 @@ class DeepPreloader::AbstractSpec
2
2
  def for_type(clazz)
3
3
  raise ArgumentError.new("Cannot type dispatch on non-polymorphic preload spec #{self.inspect}")
4
4
  end
5
+
6
+ def polymorphic?
7
+ false
8
+ end
5
9
  end
@@ -15,7 +15,11 @@ class DeepPreloader::PolymorphicSpec < DeepPreloader::AbstractSpec
15
15
  end
16
16
 
17
17
  def initialize(specs_by_type = {})
18
- @specs_by_type = specs_by_type
18
+ @specs_by_type = specs_by_type.transform_keys(&:to_s)
19
+ end
20
+
21
+ def polymorphic?
22
+ true
19
23
  end
20
24
 
21
25
  def for_type(clazz)
@@ -11,11 +11,11 @@ class DeepPreloader::Spec < DeepPreloader::AbstractSpec
11
11
  end
12
12
  when Hash
13
13
  assoc_specs = data.each_with_object({}) do |(k, v), h|
14
- h[k.to_sym] = parse(v)
14
+ h[k.to_s] = parse(v)
15
15
  end
16
16
  self.new(assoc_specs)
17
17
  when String, Symbol
18
- self.new({ data.to_sym => nil })
18
+ self.new({ data.to_s => nil })
19
19
  when DeepPreloader::AbstractSpec
20
20
  data
21
21
  when nil
@@ -26,7 +26,7 @@ class DeepPreloader::Spec < DeepPreloader::AbstractSpec
26
26
  end
27
27
 
28
28
  def initialize(association_specs = {})
29
- @association_specs = association_specs
29
+ @association_specs = association_specs.transform_keys(&:to_s)
30
30
  end
31
31
 
32
32
  def merge!(other)
@@ -1,3 +1,3 @@
1
1
  class DeepPreloader
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -12,23 +12,7 @@ class DeepPreloader
12
12
  worker = PreloadWorker.new(lock: lock)
13
13
  spec = Spec.parse(spec) unless spec.is_a?(AbstractSpec)
14
14
 
15
- models_by_class = Array.wrap(models).group_by(&:class)
16
-
17
- case spec
18
- when Spec
19
- unless models_by_class.size == 1
20
- raise ArgumentError.new("Provided multiple model types to non-polymorphic preload spec")
21
- end
22
-
23
- model_class, models = models_by_class.first
24
- worker.add_associations_from_spec(models, model_class, spec)
25
- when PolymorphicSpec
26
- models_by_class.each do |model_class, models|
27
- model_spec = spec.for_type(model_class)
28
- next unless model_spec
29
- worker.add_associations_from_spec(models, model_class, model_spec)
30
- end
31
- end
15
+ worker.add_associations_from_spec(models, spec)
32
16
 
33
17
  worker.run!
34
18
  models
@@ -40,23 +24,49 @@ class DeepPreloader
40
24
  @worklist = {}
41
25
  end
42
26
 
43
- def add_associations_from_spec(models, model_class, spec)
44
- spec.association_specs.each do |association_name, child_spec|
45
- association_reflection = model_class.reflect_on_association(association_name)
46
- if association_reflection.nil?
47
- raise ArgumentError.new("Preloading error: couldn't find association #{association_name} on model class #{model_class.name}")
27
+ def add_associations_from_spec(models, spec)
28
+ models = Array.wrap(models)
29
+
30
+ # A polymorphic spec expects models of several types, and defines which
31
+ # associations to preload for each of them.
32
+ if spec.polymorphic?
33
+ # We expect models to be of different types, and to have different subspecs for each.
34
+ models_by_class = models.group_by(&:class)
35
+
36
+ models_by_class.each do |model_class, class_models|
37
+ model_spec = spec.for_type(model_class)
38
+ next unless model_spec
39
+
40
+ add_associations_from_spec(class_models, model_spec)
48
41
  end
42
+ else
43
+ # A non-polymorphic spec implies that the models are all of the same type
44
+ model_class = models.first.class
49
45
 
50
- if association_reflection.polymorphic?
51
- add_polymorphic_association(models, association_reflection, child_spec)
52
- else
53
- add_association(models, association_reflection, child_spec)
46
+ unless models.all? { |m| m.is_a?(model_class) }
47
+ raise ArgumentError.new('Provided multiple model types to a non-polymorphic preload spec')
48
+ end
49
+
50
+ spec.association_specs.each do |association_name, child_spec|
51
+ association_reflection = model_class.reflect_on_association(association_name)
52
+ if association_reflection.nil?
53
+ raise ArgumentError.new("Preloading error: couldn't find association #{association_name} on model class #{model_class.name}")
54
+ end
55
+
56
+ # A polymorphic association links to many different model types
57
+ # (discriminated in the referrer), so must be loaded separately per
58
+ # target model type.
59
+ if association_reflection.polymorphic?
60
+ add_polymorphic_association(models, association_reflection, child_spec)
61
+ else
62
+ add_association(models, association_reflection, child_spec)
63
+ end
54
64
  end
55
65
  end
56
66
  end
57
67
 
58
68
  def run!
59
- while(@worklist.present?)
69
+ while @worklist.present?
60
70
  context, entries = @worklist.shift
61
71
  ActiveRecord::Base.logger&.debug("Preloading children in context #{context}") if DEBUG
62
72
 
@@ -96,12 +106,10 @@ class DeepPreloader
96
106
  children = entry.children
97
107
  child_spec = entry.child_spec
98
108
  next unless child_spec && children.present?
99
- child_class = children.first.class # children of a given parent are all of the same type
100
- add_associations_from_spec(children, child_class, child_spec)
101
- end
102
109
 
110
+ add_associations_from_spec(children, child_spec)
111
+ end
103
112
  end
104
-
105
113
  end
106
114
 
107
115
  private
@@ -242,8 +250,9 @@ class DeepPreloader
242
250
  target = targets
243
251
  else
244
252
  if targets.size > 1
245
- raise RuntimeError.new("Internal preloader error: attempted to attach multiple children to a singular association")
253
+ raise RuntimeError.new('Internal preloader error: attempted to attach multiple children to a singular association')
246
254
  end
255
+
247
256
  target = targets.first
248
257
  end
249
258
 
@@ -253,7 +262,6 @@ class DeepPreloader
253
262
  association.loaded!
254
263
  association.target = target
255
264
  targets.each { |t| association.set_inverse_instance(t) }
256
- targets
257
265
  end
258
266
 
259
267
  def parent_key_column
@@ -267,5 +275,4 @@ class DeepPreloader
267
275
  end
268
276
  end
269
277
  end
270
-
271
278
  end
data/nix/generate.rb ADDED
@@ -0,0 +1,42 @@
1
+ #! /usr/bin/env nix-shell
2
+ #! nix-shell -i ruby -p ruby -p bundler -p bundix
3
+ # frozen_string_literal: true
4
+
5
+ # Bundix doesn't support `gemspec` directive in Gemfiles, as it doesn't copy the
6
+ # gemspec (and its dependencies) into the store.
7
+ # This workaround is from https://github.com/manveru/bundix/issues/10#issuecomment-405879379
8
+
9
+ require 'shellwords'
10
+ require 'uri'
11
+
12
+ def sh(*args)
13
+ warn args.shelljoin
14
+ system(*args) || raise
15
+ end
16
+
17
+ sh 'bundle', 'lock'
18
+
19
+ require 'fileutils'
20
+ require 'bundler'
21
+
22
+ lockfile = Bundler::LockfileParser.new(File.read('Gemfile.lock'))
23
+ gems = lockfile.specs.select { |spec| spec.source.is_a?(Bundler::Source::Rubygems) }
24
+ sources = [URI('https://rubygems.org/')] | gems.map(&:source).flat_map(&:remotes)
25
+
26
+ FileUtils.mkdir_p 'nix/gem'
27
+ Dir.chdir 'nix/gem' do
28
+ ['Gemfile', 'Gemfile.lock', 'gemset.nix'].each do |f|
29
+ File.delete(f) if File.exist?(f)
30
+ end
31
+
32
+ File.open('Gemfile', 'w') do |gemfile|
33
+ sources.each { |source| gemfile.puts "source #{source.to_s.inspect}" }
34
+ gemfile.puts
35
+
36
+ gems.each do |gem|
37
+ gemfile.puts "gem #{gem.name.inspect}, #{gem.version.to_s.inspect}"
38
+ end
39
+ end
40
+
41
+ sh 'bundix', '-l'
42
+ end
data/shell.nix ADDED
@@ -0,0 +1,11 @@
1
+ with (import <nixpkgs> {});
2
+ let
3
+ env = bundlerEnv {
4
+ name = "bundler-env";
5
+ gemdir = ./nix/gem;
6
+ ruby = ruby_3_0;
7
+ };
8
+ in stdenv.mkDerivation {
9
+ name = "shell";
10
+ buildInputs = [ env ];
11
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deep_preloader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iKnow Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-21 00:00:00.000000000 Z
11
+ date: 2023-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -171,7 +171,8 @@ executables: []
171
171
  extensions: []
172
172
  extra_rdoc_files: []
173
173
  files:
174
- - ".circleci/config.yml"
174
+ - ".github/workflows/gem-push.yml"
175
+ - ".github/workflows/test.yml"
175
176
  - ".gitignore"
176
177
  - ".rspec"
177
178
  - ".travis.yml"
@@ -184,12 +185,15 @@ files:
184
185
  - bin/setup
185
186
  - deep_preloader.gemspec
186
187
  - gemfiles/activerecord_5_2.gemfile
187
- - gemfiles/activerecord_6_0_beta.gemfile
188
+ - gemfiles/activerecord_6_1.gemfile
189
+ - gemfiles/activerecord_7_0.gemfile
188
190
  - lib/deep_preloader.rb
189
191
  - lib/deep_preloader/abstract_spec.rb
190
192
  - lib/deep_preloader/polymorphic_spec.rb
191
193
  - lib/deep_preloader/spec.rb
192
194
  - lib/deep_preloader/version.rb
195
+ - nix/generate.rb
196
+ - shell.nix
193
197
  homepage: http://github.com/iknow/deep_preloader
194
198
  licenses:
195
199
  - MIT
@@ -209,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
213
  - !ruby/object:Gem::Version
210
214
  version: '0'
211
215
  requirements: []
212
- rubygems_version: 3.0.3
216
+ rubygems_version: 3.1.6
213
217
  signing_key:
214
218
  specification_version: 4
215
219
  summary: Explicit preloader for ActiveRecord
data/.circleci/config.yml DELETED
@@ -1,103 +0,0 @@
1
- version: 2.1
2
-
3
- executors:
4
- ruby:
5
- parameters:
6
- ruby-version:
7
- type: string
8
- default: "2.6"
9
- gemfile:
10
- type: string
11
- default: "Gemfile"
12
- docker:
13
- - image: circleci/ruby:<< parameters.ruby-version >>
14
- environment:
15
- BUNDLE_JOBS: 3
16
- BUNDLE_RETRY: 3
17
- BUNDLE_PATH: vendor/bundle
18
- RAILS_ENV: test
19
- BUNDLE_GEMFILE: << parameters.gemfile >>
20
-
21
- jobs:
22
- test:
23
- parameters:
24
- ruby-version:
25
- type: string
26
- gemfile:
27
- type: string
28
- executor:
29
- name: ruby
30
- ruby-version: << parameters.ruby-version >>
31
- gemfile: << parameters.gemfile >>
32
- parallelism: 1
33
- steps:
34
- - checkout
35
-
36
- - run:
37
- # Remove the non-appraisal gemfile for safety: we never want to use it.
38
- name: Prepare bundler
39
- command: bundle -v
40
-
41
- - run:
42
- name: Compute a gemfile lock
43
- command: bundle lock && cp "${BUNDLE_GEMFILE}.lock" /tmp/gem-lock
44
-
45
- - restore_cache:
46
- keys:
47
- - deep_preloader-<< parameters.ruby-version >>-{{ checksum "/tmp/gem-lock" }}
48
- - deep_preloader-
49
-
50
- - run:
51
- name: Bundle Install
52
- command: bundle check || bundle install
53
-
54
- - save_cache:
55
- key: deep_preloader-<< parameters.ruby-version >>-{{ checksum "/tmp/gem-lock" }}
56
- paths:
57
- - vendor/bundle
58
-
59
- - run:
60
- name: Run rspec
61
- command: bundle exec rspec --profile 10 --format RspecJunitFormatter --out test_results/rspec.xml --format progress
62
-
63
- - store_test_results:
64
- path: test_results
65
-
66
- publish:
67
- executor: ruby
68
- steps:
69
- - checkout
70
- - run:
71
- name: Setup Rubygems
72
- command: |
73
- mkdir ~/.gem &&
74
- echo -e "---\r\n:rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials &&
75
- chmod 0600 ~/.gem/credentials
76
- - run:
77
- name: Publish to Rubygems
78
- command: |
79
- gem build deep_preloader.gemspec
80
- gem push deep_preloader-*.gem
81
-
82
- workflows:
83
- version: 2.1
84
- build:
85
- jobs:
86
- - test:
87
- name: 'ruby 2.5 ActiveRecord 5.2'
88
- ruby-version: "2.5"
89
- gemfile: gemfiles/activerecord_5_2.gemfile
90
- - test:
91
- name: 'ruby 2.6 ActiveRecord 5.2'
92
- ruby-version: "2.6"
93
- gemfile: gemfiles/activerecord_5_2.gemfile
94
- - test:
95
- name: 'ruby 2.6 ActiveRecord 6.0-beta'
96
- ruby-version: "2.6"
97
- gemfile: gemfiles/activerecord_6_0_beta.gemfile
98
- - publish:
99
- filters:
100
- branches:
101
- only: master
102
- tags:
103
- ignore: /.*/