Skip to content

Commit 687215e

Browse files
committed
Use efficient queries in Tag#delete_old_manifests
Replace object loading and individual destroy calls with pluck and delete_all to match the Repository version. The old implementation loaded all manifest objects into memory and called destroy on each one, which is wasteful for tags with many manifests.
1 parent 3554789 commit 687215e

File tree

2 files changed

+49
-6
lines changed

2 files changed

+49
-6
lines changed

app/models/tag.rb

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,13 @@ def sync_manifest(m)
179179
end
180180

181181
def delete_old_manifests(new_manifests)
182-
existing_manifests = manifests.map{|m| [m.ecosystem, m.filepath] }
183-
to_be_removed = existing_manifests - new_manifests.map{|m| [(m[:platform] || m[:ecosystem]), m[:path]] }
184-
to_be_removed.each do |m|
185-
manifests.where(ecosystem: m[0], filepath: m[1]).each(&:destroy)
186-
end
187-
manifests.where.not(id: manifests.latest.map(&:id)).each(&:destroy)
182+
new_keys = new_manifests.map { |m| [m[:platform] || m[:ecosystem], m[:path]] }
183+
keep_ids = manifests.latest.select { |m| new_keys.include?([m.ecosystem, m.filepath]) }.map(&:id)
184+
delete_ids = manifests.where.not(id: keep_ids).pluck(:id)
185+
return if delete_ids.empty?
186+
187+
Dependency.where(manifest_id: delete_ids).delete_all
188+
Manifest.where(id: delete_ids).delete_all
188189
end
189190

190191
def purl

test/models/tag_test.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,48 @@ class TagTest < ActiveSupport::TestCase
2929
end
3030
end
3131

32+
context 'delete_old_manifests' do
33+
setup do
34+
@host = FactoryBot.create(:github_host)
35+
@repository = FactoryBot.create(:repository, host: @host, full_name: 'test/delmanifests', owner: 'test')
36+
@tag = FactoryBot.create(:tag, repository: @repository, name: 'v2.0.0', sha: 'def456')
37+
end
38+
39+
should 'delete manifests not present in new list' do
40+
old_manifest = Manifest.create!(tag: @tag, ecosystem: 'npm', filepath: 'package.json', kind: 'manifest')
41+
keep_manifest = Manifest.create!(tag: @tag, ecosystem: 'rubygems', filepath: 'Gemfile', kind: 'manifest')
42+
43+
new_manifests = [{ platform: 'rubygems', path: 'Gemfile' }]
44+
45+
@tag.delete_old_manifests(new_manifests)
46+
47+
assert_not Manifest.exists?(old_manifest.id)
48+
assert Manifest.exists?(keep_manifest.id)
49+
end
50+
51+
should 'delete dependencies belonging to removed manifests' do
52+
old_manifest = Manifest.create!(tag: @tag, ecosystem: 'npm', filepath: 'package.json', kind: 'manifest')
53+
dep = Dependency.create!(manifest: old_manifest, repository: @repository, ecosystem: 'npm', package_name: 'lodash', requirements: '^4.0', kind: 'runtime')
54+
55+
new_manifests = []
56+
57+
@tag.delete_old_manifests(new_manifests)
58+
59+
assert_not Manifest.exists?(old_manifest.id)
60+
assert_not Dependency.exists?(dep.id)
61+
end
62+
63+
should 'do nothing when all manifests match' do
64+
keep = Manifest.create!(tag: @tag, ecosystem: 'npm', filepath: 'package.json', kind: 'manifest')
65+
66+
new_manifests = [{ platform: 'npm', path: 'package.json' }]
67+
68+
@tag.delete_old_manifests(new_manifests)
69+
70+
assert Manifest.exists?(keep.id)
71+
end
72+
end
73+
3274
context 'parse_dependencies method' do
3375
setup do
3476
@host = FactoryBot.create(:github_host)

0 commit comments

Comments
 (0)