Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions app/models/api/messages/eseq_flowcell_io.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true
# Generates warehouse messages describing an Element Aviti flowcell.
# This is a subset of FlowcellIo containing only fields required by Eseq.
class Api::Messages::EseqFlowcellIo < Api::Base
self.includes = {
requests: [
{
target_asset: {
aliquots: [
:library,
:bait_library,
:primer_panel,
{ tag: :tag_group, tag2: :tag_group, sample: :uuid_object, study: :uuid_object }
]
}
},
:batch_request
]
}

# The following modules add methods onto the relevant models, which are used below in generation of the
# eseq flowcel MLWH message.
# Included in SequencingRequest model
module LaneExtensions
def self.included(base)
base.class_eval do
def quant_method_used
detect_descriptor('Quant method used')
end

def custom_primer_kit_used
detect_descriptor('Custom primer kit used')
end
end
end
end

renders_model(::Batch)

map_attribute_to_json_attribute(:id, 'flowcell_id')
map_attribute_to_json_attribute(:updated_at)

with_nested_has_many_association(:requests, as: :lanes) do
map_attribute_to_json_attribute(:position, 'lane')
map_attribute_to_json_attribute(:mx_library, 'id_pool_lims')
map_attribute_to_json_attribute(:lane_identifier, 'entity_id_lims')
map_attribute_to_json_attribute(:request_purpose, 'purpose')
map_attribute_to_json_attribute(:quant_method_used)
map_attribute_to_json_attribute(:custom_primer_kit_used)

with_nested_has_many_association(:lane_samples, as: :samples) do
with_association(:tag) { map_attribute_to_json_attribute(:oligo, 'tag_sequence') }
with_association(:tag2) { map_attribute_to_json_attribute(:oligo, 'tag2_sequence') }
map_attribute_to_json_attribute(:library_type, 'pipeline_id_lims')
with_association(:bait_library) { map_attribute_to_json_attribute(:name, 'bait_name') }
map_attribute_to_json_attribute(:insert_size_from, 'requested_insert_size_from')
map_attribute_to_json_attribute(:insert_size_to, 'requested_insert_size_to')
with_association(:sample) { map_attribute_to_json_attribute(:uuid, 'sample_uuid') }
with_association(:study) { map_attribute_to_json_attribute(:uuid, 'study_uuid') }
with_association(:primer_panel) { map_attribute_to_json_attribute(:name, 'primer_panel') }
with_association(:library) { map_attribute_to_json_attribute(:external_identifier, 'id_library_lims') }
map_attribute_to_json_attribute(:aliquot_type, 'entity_type')
end

# The following methods come from the Aliquot model or the relevant module above.
# They are included in the MLWH message under 'controls'.
with_nested_has_many_association(:controls) do
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im unsure if element aviti actually has controls? I didnt want to cause regression as the previous flowcell_io template does but I cant see a way to add phix on batch creation for aviti.

with_association(:tag) { map_attribute_to_json_attribute(:oligo, 'tag_sequence') }
with_association(:tag2) { map_attribute_to_json_attribute(:oligo, 'tag2_sequence') }
map_attribute_to_json_attribute(:library_type, 'pipeline_id_lims')
with_association(:sample) { map_attribute_to_json_attribute(:uuid, 'sample_uuid') }
with_association(:study) { map_attribute_to_json_attribute(:uuid, 'study_uuid') }
with_association(:library) { map_attribute_to_json_attribute(:external_identifier, 'id_library_lims') }
map_attribute_to_json_attribute(:control_aliquot_type, 'entity_type')
end
end
end
2 changes: 1 addition & 1 deletion app/models/element_aviti_sequencing_pipeline.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ class ElementAvitiSequencingPipeline < SequencingPipeline
def post_release_batch(batch, _user)
# Same logic as the superclass, but with a different Messenger root
batch.assets.compact.uniq.each(&:index_aliquots)
Messenger.create!(target: batch, template: 'FlowcellIo', root: 'eseq_flowcell')
Messenger.create!(target: batch, template: 'EseqFlowcellIo', root: 'eseq_flowcell')
end
end
1 change: 1 addition & 0 deletions app/models/sequencing_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class SequencingRequest < CustomerRequest
include Api::Messages::FlowcellIo::LaneExtensions
include Api::Messages::EseqFlowcellIo::LaneExtensions

class_attribute :flowcell_identifier

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
Quant method used:
name: Quant method used
task: Loading
workflow: Element Aviti
kind: Selection
value: Tapestation
selection:
Tapestation: Tapestation
Tapestation & qPCR: Tapestation & qPCR
required: true
sorter: -1
Pipette Carousel:
name: Pipette Carousel
task: Loading
Expand All @@ -12,6 +23,17 @@ Final Loading Concentration (pM):
kind: Text
required: false
sorter: 1
Custom primer kit used:
name: Custom primer kit used
task: Loading
workflow: Element Aviti
kind: Selection
value: Yes
selection:
Yes: Yes
No: No
required: true
sorter: 1
"200mM Tris PH7 lot#":
name: "200mM Tris PH7 lot#"
task: Loading
Expand Down
158 changes: 158 additions & 0 deletions spec/models/api/messages/eseq_flowcell_io_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Api::Messages::EseqFlowcellIo do
let(:message) { described_class.to_hash(sequencing_batch.reload) }

context 'with a batch' do
let(:sequencing_pipeline) { create(:element_aviti_sequencing_pipeline) }
let(:sequencing_batch) { create(:sequencing_batch, pipeline: sequencing_pipeline) }

let!(:request) do
create(
:complete_sequencing_request,
asset: mx_tube1,
batch: sequencing_batch,
target_asset: lane1,
request_type: request_type,
event_descriptors: request_data
)
end

let(:mx_tube1) { create(:multiplexed_library_tube, sample_count: 1) }
let(:request_type) { sequencing_pipeline.request_types.first }

let(:lane1) do
create(:lane, aliquots: mx_tube1.aliquots.map(&:dup)).tap do |lane|
lane.labware.parents << phix
lane.index_aliquots
end
end

let(:phix) { create(:spiked_buffer, :tube_barcode, tag_option: 'Dual') }

let(:tags) { lane1.aliquots.map(&:tag) }
let(:tag2s) { lane1.aliquots.map(&:tag2) }
let(:aliquots) { lane1.aliquots }

let(:expected_json) do
{
'flowcell_id' => sequencing_batch.id,
'lanes' => [
{
'lane' => 1,
'id_pool_lims' => mx_tube1.human_barcode,
'entity_id_lims' => lane1.id,
'purpose' => 'standard',
'quant_method_used' => 'Tapestation',
'custom_primer_kit_used' => 'No',
'samples' => [
{
'tag_sequence' => tags[0].oligo,
'tag2_sequence' => tag2s[0].oligo,
'pipeline_id_lims' => 'Standard',
'bait_name' => aliquots[0].bait_library.name,
'requested_insert_size_from' => 100,
'requested_insert_size_to' => 200,
'sample_uuid' => aliquots[0].sample.uuid,
'study_uuid' => aliquots[0].study.uuid,
'primer_panel' => aliquots[0].primer_panel.name,
'id_library_lims' => aliquots[0].library.human_barcode,
'entity_type' => 'library_indexed'
}
],
'controls' => [
{
'tag_sequence' => 'TGTGCAGC',
'tag2_sequence' => 'ACTGATGT',
'pipeline_id_lims' => nil,
'sample_uuid' => phix.aliquots[0].sample.uuid,
'id_library_lims' => phix.human_barcode,
'entity_type' => 'library_indexed_spike'
}
]
}
]
}
end

let(:request_data) do
{
'Quant method used' => 'Tapestation',
'Custom primer kit used' => 'No'
}
end

context 'with all request data' do
it 'generates valid json' do
expect(message.as_json).to include_json(expected_json)
end
end

context 'with some missing request data' do
let(:request_data) do
{
'Quant method used' => 'Tapestation',
'Custom primer kit used' => nil
}
end

it 'generates valid json' do
# Should have an empty primer kit used
expected_json['lanes'][0]['custom_primer_kit_used'] = nil

expect(message.as_json).to include_json(expected_json)
end
end

context 'with updated events' do
before do
create(
:lab_event,
eventful: request,
batch: request.batch,
descriptors: {
'Quant method used' => 'Tapestation & qPCR',
'Custom primer kit used' => 'Yes'
}
)
end

let(:expected_json) do
{
'flowcell_id' => sequencing_batch.id,
'lanes' => [
{
'lane' => 1,
'id_pool_lims' => mx_tube1.human_barcode,
'entity_id_lims' => lane1.id,
'purpose' => 'standard',
'quant_method_used' => 'Tapestation & qPCR',
'custom_primer_kit_used' => 'Yes',
'samples' => [
{
'tag_sequence' => tags[0].oligo,
'tag2_sequence' => tag2s[0].oligo,
'pipeline_id_lims' => 'Standard',
'bait_name' => aliquots[0].bait_library.name,
'requested_insert_size_from' => 100,
'requested_insert_size_to' => 200,
'sample_uuid' => aliquots[0].sample.uuid,
'study_uuid' => aliquots[0].study.uuid,
'primer_panel' => aliquots[0].primer_panel.name,
'id_library_lims' => aliquots[0].library.human_barcode,
'entity_type' => 'library_indexed'
}
]
}
]
}
end

it 'generates valid json' do
expect(message.as_json).to include_json(expected_json)
end
end
end
end
2 changes: 1 addition & 1 deletion spec/models/element_aviti_sequencing_pipeline_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
pipeline.post_release_batch(batch, create(:user))

expect(Messenger).to have_received(:create!).with(
hash_including(target: batch, template: 'FlowcellIo', root: 'eseq_flowcell')
hash_including(target: batch, template: 'EseqFlowcellIo', root: 'eseq_flowcell')
)
end
end
Expand Down
Loading