Skip to content

Commit

Permalink
Merge pull request #1617 from seek4science/related-sample-datafile-at…
Browse files Browse the repository at this point in the history
…tribute

Datafile attribute relates samples and datafiles
  • Loading branch information
fherreazcue authored Oct 19, 2023
2 parents b8e43ec + 1fffe06 commit a883c7f
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 3 deletions.
4 changes: 3 additions & 1 deletion app/models/data_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class DataFile < ApplicationRecord

belongs_to :file_template
has_many :extracted_samples, class_name: 'Sample', foreign_key: :originating_data_file_id
has_many :sample_resource_links, -> { where(resource_type: 'DataFile') }, class_name: 'SampleResourceLink', foreign_key: :resource_id
has_many :linked_samples, through: :sample_resource_links, source: :sample

has_many :workflow_data_files, dependent: :destroy, autosave: true
has_many :workflows, ->{ distinct }, through: :workflow_data_files
Expand Down Expand Up @@ -122,7 +124,7 @@ def possible_sample_types(user = User.current_user)
end

def related_samples
extracted_samples
extracted_samples + linked_samples
end

# Extracts samples using the given sample_type
Expand Down
11 changes: 9 additions & 2 deletions app/models/sample.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class Sample < ApplicationRecord
has_many :linked_samples, through: :sample_resource_links, source: :resource, source_type: 'Sample'
has_many :linking_samples, through: :reverse_sample_resource_links, source: :sample

has_many :linked_data_files, through: :sample_resource_links, source: :resource, source_type: 'DataFile'

validates :projects, presence: true, projects: { self: true }
validates :title, :sample_type, presence: true

Expand Down Expand Up @@ -60,8 +62,8 @@ def self.can_create?
User.logged_in_and_member? && Seek::Config.samples_enabled
end

def related_data_file
originating_data_file
def related_data_files
[originating_data_file].compact + linked_data_files
end

def related_samples
Expand All @@ -81,6 +83,10 @@ def referenced_resources
end.flatten.compact
end

def referenced_data_files
referenced_resources.select { |r| r.is_a?(DataFile) }
end

def referenced_strains
referenced_resources.select { |r| r.is_a?(Strain) }
end
Expand Down Expand Up @@ -198,6 +204,7 @@ def update_sample_resource_links
return unless sample_type.present?
self.strains = referenced_strains
self.linked_samples = referenced_samples
self.linked_data_files = referenced_data_files
end

def attribute_class
Expand Down
17 changes: 17 additions & 0 deletions lib/tasks/seek_upgrades.rake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace :seek do
environment
decouple_extracted_samples_policies
decouple_extracted_samples_projects
link_sample_datafile_attributes
]

# these are the tasks that are executes for each upgrade as standard, and rarely change
Expand Down Expand Up @@ -84,6 +85,22 @@ namespace :seek do
puts " ... finished copying project ids of #{decoupled.to_s} extracted samples"
end

task(link_sample_datafile_attributes: [:environment]) do
puts '... updating sample_resource_links for samples with data_file attributes...'
samples_updated = 0
disable_authorization_checks do
df_attrs = SampleAttribute.joins(:sample_attribute_type).where('sample_attribute_types.base_type' => Seek::Samples::BaseType::SEEK_DATA_FILE).pluck(:id)
samples = Sample.joins(sample_type: :sample_attributes).where('sample_attributes.id' => df_attrs)
samples.each do |sample|
if sample.sample_resource_links.where(resource_type: 'DataFile').empty?
sample.send(:update_sample_resource_links)
samples_updated += 1
end
end
end
puts " ... finished updating sample_resource_links of #{samples_updated.to_s} samples with data_file attributes"
end

private

##
Expand Down
21 changes: 21 additions & 0 deletions test/unit/data_file_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -489,4 +489,25 @@ class DataFileTest < ActiveSupport::TestCase
assert data_file.respond_to?(:data_format_annotations)
assert data_file.respond_to?(:data_type_annotations)
end

test 'related samples include extracted samples and samples linked in attributes' do
project = FactoryBot.create(:project)
df_no_samples = FactoryBot.create(:data_file) # No samples
df_extracted = FactoryBot.create(:data_file) # Extracted samples
df_attributes = FactoryBot.create(:data_file) # Linked in sample's attributes only
df_ext_attr = FactoryBot.create(:data_file) # Extracted samples and linked in sample's attributes
type = FactoryBot.create(:data_file_sample_type, project_ids: [project.id])
sample1 = Sample.new(sample_type: type, project_ids: [project.id], originating_data_file: df_extracted)
sample1.update(data: { 'data file': df_ext_attr.id })
sample1.save!
sample2 = Sample.new(sample_type: type, project_ids: [project.id], originating_data_file: df_ext_attr)
sample2.update(data: { 'data file': df_attributes.id })
sample2.save!

assert_equal [], df_no_samples.related_samples
assert_equal [sample1], df_extracted.related_samples
assert_equal [sample2].sort_by(&:id), df_attributes.related_samples
assert_equal [sample1, sample2].sort_by(&:id), df_ext_attr.related_samples.sort_by(&:id)
end

end
30 changes: 30 additions & 0 deletions test/unit/sample_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1352,4 +1352,34 @@ class SampleTest < ActiveSupport::TestCase

end

test 'related datafiles include datafiles in attributes and originating datafile' do
project = FactoryBot.create(:project)
simple_type = FactoryBot.create(:simple_sample_type, project_ids: [project.id])
type_with_df_attr = FactoryBot.create(:data_file_sample_type, project_ids: [project.id])
df_attr = FactoryBot.build(:data_file_sample_attribute, title: 'data file 2', sample_type: type_with_df_attr)
type_with_df_attr.sample_attributes << df_attr
df1 = FactoryBot.create(:data_file)
df2 = FactoryBot.create(:data_file)
df3 = FactoryBot.create(:data_file)
# Sample with no data files linked as attribute nor originating data file
sample_no_df = Sample.new(sample_type: simple_type, project_ids: [project.id])
# Sample with originating data file only
sample_extracted = Sample.new(sample_type: simple_type, project_ids: [project.id], originating_data_file: df3)
# Sample with data files linked as attributes
sample_attributes = Sample.new(sample_type: type_with_df_attr, project_ids: [project.id])
sample_attributes.update(data: { 'data file': df1.id })
sample_attributes.update(data: { 'data file 2': df2.id })
sample_attributes.save!
# Sample with data files linked as attributes and originating data file
sample_ext_attr = Sample.new(sample_type: type_with_df_attr, project_ids: [project.id], originating_data_file: df3)
sample_ext_attr.update(data: { 'data file': df1.id })
sample_ext_attr.update(data: { 'data file 2': df2.id })
sample_ext_attr.save!

assert_equal [], sample_no_df.related_data_files
assert_equal [df3], sample_extracted.related_data_files
assert_equal [df1, df2].sort_by(&:id), sample_attributes.related_data_files.sort_by(&:id)
assert_equal [df1, df2, df3].sort_by(&:id), sample_ext_attr.related_data_files.sort_by(&:id)
end

end

0 comments on commit a883c7f

Please sign in to comment.