Class: Reception::ResourceFactory

Inherits:
Object
  • Object
show all
Extended by:
NestedValidation
Includes:
ActiveModel::Model
Defined in:
app/models/reception/resource_factory.rb

Overview

Acts on behalf of a Reception to construct all associated requests, as well as any necessary samples, plates, wells and tubes. In order to improve performance, the ResourceFactory implements caching of samples and library and data types. This allows up to retrieve all records in a single query upfront, avoiding N+1 query problems. It also ensures we can centralize the registration of new plates and tubes, making it easier to prevent registration of duplicate records.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from NestedValidation

validates_nested

Instance Attribute Details

#receptionObject

Returns the value of attribute reception.



14
15
16
# File 'app/models/reception/resource_factory.rb', line 14

def reception
  @reception
end

Instance Method Details

#construct_resources!Object



52
53
54
55
# File 'app/models/reception/resource_factory.rb', line 52

def construct_resources!
  requests.each(&:save!) # Note this also saves associated records we generate
  labware_status
end

#containersObject



40
41
42
# File 'app/models/reception/resource_factory.rb', line 40

def containers
  @containers ||= []
end

#create_plates(plates_attributes) ⇒ Object

Populates containers and requests from plates_attributes



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'app/models/reception/resource_factory.rb', line 58

def create_plates(plates_attributes)
  plates_attributes.each do |plate_attr|
    # Gets the existing plate or creates a new one
    plate = find_or_create_labware(plate_attr[:barcode], Plate)
    containers << plate
    plate_attr[:wells_attributes].each do |well_attr|
      # Gets the existing well or creates a new one
      well = plate.wells.located_at(well_attr[:position])
      # If a well already exists with records, we want to add an error
      if well.existing_records.present?
        update_labware_status(plate.barcode, 'partial', "#{well.position} already has a sample")
        next
      end

      # Creates a request for the well
      create_request_for_container(well_attr, well)
    end
  end
end

#create_pool(pool_attributes) ⇒ Object

Creates a pool from pool_attributes and uses the imported libraries



95
96
97
98
99
100
101
102
103
104
105
106
# File 'app/models/reception/resource_factory.rb', line 95

def create_pool(pool_attributes)
  return if pool_attributes.blank?

  # Currently only supports Ont
  @pool = Ont::Pool.new(pool_attributes)
  begin
    @pool.libraries = libraries
    update_labware_status(pool_attributes['barcode'], 'success', nil)
  rescue StandardError => e
    update_labware_status(pool_attributes['barcode'], 'failed', e.message)
  end
end

#create_tubes(tubes_attributes) ⇒ Object

Populates containers and requests from tubes_attributes



79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/models/reception/resource_factory.rb', line 79

def create_tubes(tubes_attributes)
  tubes_attributes.each do |tube_attr|
    # Gets the existing tube or creates a new one
    tube = find_or_create_labware(tube_attr[:barcode], Tube)
    # If a tube already exists with records, we want to add an error
    if tube.existing_records.present?
      update_labware_status(tube.barcode, 'failed', 'Tube already has a sample')
      next
    end

    # Creates a request for the tube
    create_request_for_container(tube_attr, tube)
  end
end

#data_type_for(attributes) ⇒ Object



118
119
120
# File 'app/models/reception/resource_factory.rb', line 118

def data_type_for(attributes)
  data_type_cache.fetch(attributes[:data_type], nil)
end

#labware_statusObject



48
49
50
# File 'app/models/reception/resource_factory.rb', line 48

def labware_status
  @labware_status ||= {}
end

#librariesObject



36
37
38
# File 'app/models/reception/resource_factory.rb', line 36

def libraries
  @libraries ||= []
end

#library_type_for(request_attributes) ⇒ Object



108
109
110
111
112
113
114
115
116
# File 'app/models/reception/resource_factory.rb', line 108

def library_type_for(request_attributes)
  # Gets a library type from the cache or returns an unknown type
  library_type = request_attributes[:library_type]
  library_type_cache.fetch(
    library_type,
    UnknownLibraryType.new(library_type:,
                           permitted: library_type_cache.keys)
  )
end

#plates_attributes=(plates_attributes) ⇒ Object



20
21
22
# File 'app/models/reception/resource_factory.rb', line 20

def plates_attributes=(plates_attributes)
  create_plates(plates_attributes)
end

#poolObject



32
33
34
# File 'app/models/reception/resource_factory.rb', line 32

def pool
  @pool ||= nil
end

#pool_attributes=(pool_attributes) ⇒ Object



28
29
30
# File 'app/models/reception/resource_factory.rb', line 28

def pool_attributes=(pool_attributes)
  create_pool(pool_attributes)
end

#requestsObject



44
45
46
# File 'app/models/reception/resource_factory.rb', line 44

def requests
  @requests ||= []
end

#sample_for(attributes) ⇒ Object



122
123
124
125
126
127
128
# File 'app/models/reception/resource_factory.rb', line 122

def sample_for(attributes)
  # Used to reduce database queries.
  # It gets a sample from the cache, if it doesn't exist it searches the database
  # or creates a new one
  sample_cache[attributes[:external_id]] ||=
    Sample.find_by(external_id: attributes[:external_id]) || Sample.new(attributes)
end

#tubes_attributes=(tubes_attributes) ⇒ Object



24
25
26
# File 'app/models/reception/resource_factory.rb', line 24

def tubes_attributes=(tubes_attributes)
  create_tubes(tubes_attributes)
end