Class: Sequence

Overview

A DNA, RNA, or Amino Acid, as defined by a string of letters. All other attributes are stored in related tables, the overal model is basically a graph with nodes having attributes.

Constant Summary collapse

ALTERNATE_VALUES_FOR =
[:name].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Shared::IsData

#errors_excepting, #full_error_messages_excepting, #identical, #is_community?, #is_destroyable?, #is_editable?, #is_in_use?, #is_in_users_projects?, #metamorphosize, #similar

Methods included from Shared::HasPapertrail

#attribute_updated, #attribute_updater

Methods included from Shared::Tags

#reject_tags, #tag_with, #tagged?, #tagged_with?

Methods included from Shared::ProtocolRelationships

#protocolled?, #reject_protocols

Methods included from Shared::OriginRelationship

#new_objects, #old_objects, #reject_origin_relationships, #set_origin

Methods included from Shared::Notes

#concatenated_notes_string, #reject_notes

Methods included from Shared::Identifiers

#dwc_occurrence_id, #identified?, #next_by_identifier, #previous_by_identifier, #reject_identifiers, #uri, #uuid

Methods included from Shared::Documentation

#document_array=, #documented?, #reject_documentation, #reject_documents

Methods included from Shared::Confidences

#reject_confidences

Methods included from Shared::DataAttributes

#import_attributes, #internal_attributes, #keyword_value_hash, #reject_data_attributes

Methods included from Shared::AlternateValues

#all_values_for, #alternate_valued?

Methods included from Housekeeping

#has_polymorphic_relationship?

Methods inherited from ApplicationRecord

transaction_with_retry

Instance Attribute Details

#describe_withObject

Pass a Gene::Descriptor instance to clone that description to this sequence



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

def describe_with
  @describe_with
end

#nameString

Returns the asserted name for this sequence, typically the target gene name like “CO1”. Important! The preferred mechanism for assinging this type of label to a sequence is assigning pertinent metadata (relationships to other sequences) and then inferrning that those sequences with particular metadata have a specific gene name (Descriptor::Gene#name).

Returns:

  • (String)

    the asserted name for this sequence, typically the target gene name like “CO1”. Important! The preferred mechanism for assinging this type of label to a sequence is assigning pertinent metadata (relationships to other sequences) and then inferrning that those sequences with particular metadata have a specific gene name (Descriptor::Gene#name).



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'app/models/sequence.rb', line 22

class Sequence < ApplicationRecord

  include Housekeeping

  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Confidences
  include Shared::Documentation
  include Shared::Identifiers
  include Shared::Notes
  include Shared::OriginRelationship
  include Shared::ProtocolRelationships
  include Shared::Tags
  include Shared::HasPapertrail
  include Shared::IsData

  is_origin_for 'Sequence'
  originates_from 'Extract', 'Specimen', 'Lot', 'RangedLot', 'Sequence'

  ALTERNATE_VALUES_FOR = [:name].freeze

  # Pass a Gene::Descriptor instance to clone that description to this sequence
  attr_accessor :describe_with

  has_many :sequence_relationships, foreign_key: :subject_sequence_id, inverse_of: :subject_sequence # this sequence describes others
  has_many :sequences, through: :sequence_relationships, source: :object_sequence

  has_many :related_sequence_relationships, class_name: 'SequenceRelationship', foreign_key: :object_sequence_id, inverse_of: :object_sequence # attributes of this sequence
  has_many :related_sequences, through: :related_sequence_relationships, source: :subject_sequence
  has_many :gene_attributes, inverse_of: :sequence

  # has_many :descriptors, through: :gene_attributes, inverse_of: :sequences, as: 'Descriptor::Gene'

  before_validation :build_relationships, if: -> {describe_with.present?}
  before_validation :normalize_sequence_type

  SequenceRelationship.descendants.each do |d|
    t = d.name.demodulize.tableize.singularize
    relationships = "#{t}_relationships".to_sym
    sequences = "#{t}_sequences".to_sym

    has_many relationships, class_name: d.name.to_s, foreign_key: :object_sequence_id, inverse_of: :object_sequence
    has_many sequences, class_name: 'Sequence', through: relationships, source: :subject_sequence, inverse_of: :sequences

    accepts_nested_attributes_for sequences
    accepts_nested_attributes_for relationships
  end

  validates_presence_of :sequence
  validates_inclusion_of :sequence_type, in: ['DNA', 'RNA', 'AA']

  # @param used_on [String] required, one of `GeneAttribute` or `SequenceRelationship`
  # @return [Scope]
  #   the max 10 most recently used otus, as `used_on`
  def self.used_recently(user_id, project_id, used_on = nil)
    return Sequence.none if used_on.nil?
    t = case used_on
        when 'GeneAttribute'
          GeneAttribute.arel_table
        when 'SequenceRelationship'
          SequenceRelationship.arel_table
        end

    p = Sequence.arel_table

    # i is a select manager
    i = t.project(t['sequence_id'], t['updated_at']).from(t)
      .where(t['updated_at'].gt( 1.weeks.ago ))
      .where(t['updated_by_id'].eq(user_id))
      .where(t['project_id'].eq(project_id))
      .order(t['updated_at'].desc)

    # i is a select manager
    i = case used_on
        when 'SequenceRelationship'
          t.project(t['object_sequence_id'], t['updated_at']).from(t)
            .where(
              t['updated_at'].gt(1.weeks.ago)
            )
              .where(t['created_by_id'].eq(user_id))
              .where(t['project_id'].eq(project_id))
              .order(t['updated_at'])
        else
          t.project(t['sequence_id'], t['updated_at']).from(t)
            .where(t['updated_at'].gt( 1.weeks.ago ))
            .where(t['created_by_id'].eq(user_id))
            .where(t['project_id'].eq(project_id))
            .order(t['updated_at'])
        end

    # z is a table alias
    z = i.as('recent_t')

    j = case used_on
        when 'SequenceRelationship'
          Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(
            z['object_sequence_id'].eq(p['id'])
          ))
        else
          Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(z['sequence_id'].eq(p['id'])))
        end

    Sequence.joins(j).pluck(:sequence_id).uniq
  end

  # @params target [String] one of nil, 'SequenceRelationship', 'GeneAttribute'
  # @return [Hash] otus optimized for user selection
  def self.select_optimized(user_id, project_id, target = nil)
    r = used_recently(user_id, project_id, target)
    h = {
      recent: [],
      quick: [],
      pinboard: Sequence.pinned_by(user_id).where(project_id: project_id).to_a
    }

    if r.empty?
      h[:quick] = Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a
    else
      h[:recent] = Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a
      h[:quick] = (Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a +
          Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a).uniq
    end

    h
  end

  protected

  def build_relationships
    describe_with.gene_attributes.each do |ga|
      related_sequence_relationships.build(subject_sequence: ga.sequence, type: ga.sequence_relationship_type)
    end
  end

  def normalize_sequence_type
    sequence_type.to_s.upcase! if sequence_type.present?
  end

end

#sequenceString

Returns the letters representing the sequence.

Returns:

  • (String)

    the letters representing the sequence



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'app/models/sequence.rb', line 22

class Sequence < ApplicationRecord

  include Housekeeping

  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Confidences
  include Shared::Documentation
  include Shared::Identifiers
  include Shared::Notes
  include Shared::OriginRelationship
  include Shared::ProtocolRelationships
  include Shared::Tags
  include Shared::HasPapertrail
  include Shared::IsData

  is_origin_for 'Sequence'
  originates_from 'Extract', 'Specimen', 'Lot', 'RangedLot', 'Sequence'

  ALTERNATE_VALUES_FOR = [:name].freeze

  # Pass a Gene::Descriptor instance to clone that description to this sequence
  attr_accessor :describe_with

  has_many :sequence_relationships, foreign_key: :subject_sequence_id, inverse_of: :subject_sequence # this sequence describes others
  has_many :sequences, through: :sequence_relationships, source: :object_sequence

  has_many :related_sequence_relationships, class_name: 'SequenceRelationship', foreign_key: :object_sequence_id, inverse_of: :object_sequence # attributes of this sequence
  has_many :related_sequences, through: :related_sequence_relationships, source: :subject_sequence
  has_many :gene_attributes, inverse_of: :sequence

  # has_many :descriptors, through: :gene_attributes, inverse_of: :sequences, as: 'Descriptor::Gene'

  before_validation :build_relationships, if: -> {describe_with.present?}
  before_validation :normalize_sequence_type

  SequenceRelationship.descendants.each do |d|
    t = d.name.demodulize.tableize.singularize
    relationships = "#{t}_relationships".to_sym
    sequences = "#{t}_sequences".to_sym

    has_many relationships, class_name: d.name.to_s, foreign_key: :object_sequence_id, inverse_of: :object_sequence
    has_many sequences, class_name: 'Sequence', through: relationships, source: :subject_sequence, inverse_of: :sequences

    accepts_nested_attributes_for sequences
    accepts_nested_attributes_for relationships
  end

  validates_presence_of :sequence
  validates_inclusion_of :sequence_type, in: ['DNA', 'RNA', 'AA']

  # @param used_on [String] required, one of `GeneAttribute` or `SequenceRelationship`
  # @return [Scope]
  #   the max 10 most recently used otus, as `used_on`
  def self.used_recently(user_id, project_id, used_on = nil)
    return Sequence.none if used_on.nil?
    t = case used_on
        when 'GeneAttribute'
          GeneAttribute.arel_table
        when 'SequenceRelationship'
          SequenceRelationship.arel_table
        end

    p = Sequence.arel_table

    # i is a select manager
    i = t.project(t['sequence_id'], t['updated_at']).from(t)
      .where(t['updated_at'].gt( 1.weeks.ago ))
      .where(t['updated_by_id'].eq(user_id))
      .where(t['project_id'].eq(project_id))
      .order(t['updated_at'].desc)

    # i is a select manager
    i = case used_on
        when 'SequenceRelationship'
          t.project(t['object_sequence_id'], t['updated_at']).from(t)
            .where(
              t['updated_at'].gt(1.weeks.ago)
            )
              .where(t['created_by_id'].eq(user_id))
              .where(t['project_id'].eq(project_id))
              .order(t['updated_at'])
        else
          t.project(t['sequence_id'], t['updated_at']).from(t)
            .where(t['updated_at'].gt( 1.weeks.ago ))
            .where(t['created_by_id'].eq(user_id))
            .where(t['project_id'].eq(project_id))
            .order(t['updated_at'])
        end

    # z is a table alias
    z = i.as('recent_t')

    j = case used_on
        when 'SequenceRelationship'
          Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(
            z['object_sequence_id'].eq(p['id'])
          ))
        else
          Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(z['sequence_id'].eq(p['id'])))
        end

    Sequence.joins(j).pluck(:sequence_id).uniq
  end

  # @params target [String] one of nil, 'SequenceRelationship', 'GeneAttribute'
  # @return [Hash] otus optimized for user selection
  def self.select_optimized(user_id, project_id, target = nil)
    r = used_recently(user_id, project_id, target)
    h = {
      recent: [],
      quick: [],
      pinboard: Sequence.pinned_by(user_id).where(project_id: project_id).to_a
    }

    if r.empty?
      h[:quick] = Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a
    else
      h[:recent] = Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a
      h[:quick] = (Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a +
          Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a).uniq
    end

    h
  end

  protected

  def build_relationships
    describe_with.gene_attributes.each do |ga|
      related_sequence_relationships.build(subject_sequence: ga.sequence, type: ga.sequence_relationship_type)
    end
  end

  def normalize_sequence_type
    sequence_type.to_s.upcase! if sequence_type.present?
  end

end

#sequence_typeString

Returns one of “DNA”, “RNA”, “AA”.

Returns:

  • (String)

    one of “DNA”, “RNA”, “AA”



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'app/models/sequence.rb', line 22

class Sequence < ApplicationRecord

  include Housekeeping

  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Confidences
  include Shared::Documentation
  include Shared::Identifiers
  include Shared::Notes
  include Shared::OriginRelationship
  include Shared::ProtocolRelationships
  include Shared::Tags
  include Shared::HasPapertrail
  include Shared::IsData

  is_origin_for 'Sequence'
  originates_from 'Extract', 'Specimen', 'Lot', 'RangedLot', 'Sequence'

  ALTERNATE_VALUES_FOR = [:name].freeze

  # Pass a Gene::Descriptor instance to clone that description to this sequence
  attr_accessor :describe_with

  has_many :sequence_relationships, foreign_key: :subject_sequence_id, inverse_of: :subject_sequence # this sequence describes others
  has_many :sequences, through: :sequence_relationships, source: :object_sequence

  has_many :related_sequence_relationships, class_name: 'SequenceRelationship', foreign_key: :object_sequence_id, inverse_of: :object_sequence # attributes of this sequence
  has_many :related_sequences, through: :related_sequence_relationships, source: :subject_sequence
  has_many :gene_attributes, inverse_of: :sequence

  # has_many :descriptors, through: :gene_attributes, inverse_of: :sequences, as: 'Descriptor::Gene'

  before_validation :build_relationships, if: -> {describe_with.present?}
  before_validation :normalize_sequence_type

  SequenceRelationship.descendants.each do |d|
    t = d.name.demodulize.tableize.singularize
    relationships = "#{t}_relationships".to_sym
    sequences = "#{t}_sequences".to_sym

    has_many relationships, class_name: d.name.to_s, foreign_key: :object_sequence_id, inverse_of: :object_sequence
    has_many sequences, class_name: 'Sequence', through: relationships, source: :subject_sequence, inverse_of: :sequences

    accepts_nested_attributes_for sequences
    accepts_nested_attributes_for relationships
  end

  validates_presence_of :sequence
  validates_inclusion_of :sequence_type, in: ['DNA', 'RNA', 'AA']

  # @param used_on [String] required, one of `GeneAttribute` or `SequenceRelationship`
  # @return [Scope]
  #   the max 10 most recently used otus, as `used_on`
  def self.used_recently(user_id, project_id, used_on = nil)
    return Sequence.none if used_on.nil?
    t = case used_on
        when 'GeneAttribute'
          GeneAttribute.arel_table
        when 'SequenceRelationship'
          SequenceRelationship.arel_table
        end

    p = Sequence.arel_table

    # i is a select manager
    i = t.project(t['sequence_id'], t['updated_at']).from(t)
      .where(t['updated_at'].gt( 1.weeks.ago ))
      .where(t['updated_by_id'].eq(user_id))
      .where(t['project_id'].eq(project_id))
      .order(t['updated_at'].desc)

    # i is a select manager
    i = case used_on
        when 'SequenceRelationship'
          t.project(t['object_sequence_id'], t['updated_at']).from(t)
            .where(
              t['updated_at'].gt(1.weeks.ago)
            )
              .where(t['created_by_id'].eq(user_id))
              .where(t['project_id'].eq(project_id))
              .order(t['updated_at'])
        else
          t.project(t['sequence_id'], t['updated_at']).from(t)
            .where(t['updated_at'].gt( 1.weeks.ago ))
            .where(t['created_by_id'].eq(user_id))
            .where(t['project_id'].eq(project_id))
            .order(t['updated_at'])
        end

    # z is a table alias
    z = i.as('recent_t')

    j = case used_on
        when 'SequenceRelationship'
          Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(
            z['object_sequence_id'].eq(p['id'])
          ))
        else
          Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(z['sequence_id'].eq(p['id'])))
        end

    Sequence.joins(j).pluck(:sequence_id).uniq
  end

  # @params target [String] one of nil, 'SequenceRelationship', 'GeneAttribute'
  # @return [Hash] otus optimized for user selection
  def self.select_optimized(user_id, project_id, target = nil)
    r = used_recently(user_id, project_id, target)
    h = {
      recent: [],
      quick: [],
      pinboard: Sequence.pinned_by(user_id).where(project_id: project_id).to_a
    }

    if r.empty?
      h[:quick] = Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a
    else
      h[:recent] = Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a
      h[:quick] = (Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a +
          Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a).uniq
    end

    h
  end

  protected

  def build_relationships
    describe_with.gene_attributes.each do |ga|
      related_sequence_relationships.build(subject_sequence: ga.sequence, type: ga.sequence_relationship_type)
    end
  end

  def normalize_sequence_type
    sequence_type.to_s.upcase! if sequence_type.present?
  end

end

Class Method Details

.select_optimized(user_id, project_id, target = nil) ⇒ Hash

Returns otus optimized for user selection.

Returns:

  • (Hash)

    otus optimized for user selection



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'app/models/sequence.rb', line 129

def self.select_optimized(user_id, project_id, target = nil)
  r = used_recently(user_id, project_id, target)
  h = {
    recent: [],
    quick: [],
    pinboard: Sequence.pinned_by(user_id).where(project_id: project_id).to_a
  }

  if r.empty?
    h[:quick] = Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a
  else
    h[:recent] = Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a
    h[:quick] = (Sequence.pinned_by(user_id).pinboard_inserted.where(project_id: project_id).to_a +
        Sequence.where('"sequences"."id" IN (?)', r.first(10) ).to_a).uniq
  end

  h
end

.used_recently(user_id, project_id, used_on = nil) ⇒ Scope

Returns the max 10 most recently used otus, as ‘used_on`.

Parameters:

  • used_on (String) (defaults to: nil)

    required, one of ‘GeneAttribute` or `SequenceRelationship`

Returns:

  • (Scope)

    the max 10 most recently used otus, as ‘used_on`



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'app/models/sequence.rb', line 76

def self.used_recently(user_id, project_id, used_on = nil)
  return Sequence.none if used_on.nil?
  t = case used_on
      when 'GeneAttribute'
        GeneAttribute.arel_table
      when 'SequenceRelationship'
        SequenceRelationship.arel_table
      end

  p = Sequence.arel_table

  # i is a select manager
  i = t.project(t['sequence_id'], t['updated_at']).from(t)
    .where(t['updated_at'].gt( 1.weeks.ago ))
    .where(t['updated_by_id'].eq(user_id))
    .where(t['project_id'].eq(project_id))
    .order(t['updated_at'].desc)

  # i is a select manager
  i = case used_on
      when 'SequenceRelationship'
        t.project(t['object_sequence_id'], t['updated_at']).from(t)
          .where(
            t['updated_at'].gt(1.weeks.ago)
          )
            .where(t['created_by_id'].eq(user_id))
            .where(t['project_id'].eq(project_id))
            .order(t['updated_at'])
      else
        t.project(t['sequence_id'], t['updated_at']).from(t)
          .where(t['updated_at'].gt( 1.weeks.ago ))
          .where(t['created_by_id'].eq(user_id))
          .where(t['project_id'].eq(project_id))
          .order(t['updated_at'])
      end

  # z is a table alias
  z = i.as('recent_t')

  j = case used_on
      when 'SequenceRelationship'
        Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(
          z['object_sequence_id'].eq(p['id'])
        ))
      else
        Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(z['sequence_id'].eq(p['id'])))
      end

  Sequence.joins(j).pluck(:sequence_id).uniq
end

Instance Method Details

#build_relationshipsObject (protected)



150
151
152
153
154
# File 'app/models/sequence.rb', line 150

def build_relationships
  describe_with.gene_attributes.each do |ga|
    related_sequence_relationships.build(subject_sequence: ga.sequence, type: ga.sequence_relationship_type)
  end
end

#normalize_sequence_typeObject (protected)



156
157
158
# File 'app/models/sequence.rb', line 156

def normalize_sequence_type
  sequence_type.to_s.upcase! if sequence_type.present?
end