Skip to content

Commit 6d8e19c

Browse files
committed
schema support for regulatory fusions
1 parent 0a66cd3 commit 6d8e19c

16 files changed

+216
-39
lines changed

server/app/graphql/mutations/create_fusion_feature.rb

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,22 @@ def ready?(organization_id: nil, five_prime_gene:, three_prime_gene:,**kwargs)
3636

3737
#check that partner status matches gene_id presence
3838
[five_prime_gene, three_prime_gene].each do |gene_input|
39-
if gene_input.gene_id.present? && gene_input.partner_status != 'known'
40-
raise GraphQL::ExecutionError, "Partner status needs to be 'known' if a gene_id is set"
39+
if gene_input.gene_id.present? && (gene_input.partner_status != 'known' || gene_input.partner_status != 'regulatory')
40+
raise GraphQL::ExecutionError, "Partner status needs to be 'known' or 'regulatory' if a gene_id is set"
4141
end
42-
if gene_input.gene_id.blank? && gene_input.partner_status == 'known'
43-
raise GraphQL::ExecutionError, "Partner status can't be 'known' if a gene_id is not set"
42+
if gene_input.gene_id.blank? && (gene_input.partner_status == 'known' && gene_input.partner_status != 'regulatory')
43+
raise GraphQL::ExecutionError, "Partner status can't be 'known' or 'regulatory' if a gene_id is not set"
4444
end
4545
end
4646

47+
#check that maximuim one gene has regulatory_fusion_type set
48+
if five_prime_gene.partner_status == 'regulatory' && three_prime_gene.partner_status == 'regulatory'
49+
raise GraphQL::ExecutionError, "Only one Fusion partner can be marked 'regulatory'"
50+
end
51+
if five_prime_gene.regulatory_fusion_type.present? && three_prime_gene.regulatory_fusion_type.present?
52+
raise GraphQL::ExecutionError, "Only one Fusion partner can have a regulatory fusion type set."
53+
end
54+
4755
return true
4856
end
4957

@@ -54,12 +62,16 @@ def authorized?(organization_id: nil, **kwargs)
5462

5563
def resolve(five_prime_gene:, three_prime_gene:, organization_id: nil)
5664

65+
#only one can be set
66+
regulatory_fusion_type = five_prime_partner_status.regulatory_fusion_type || three_prime_partner_status.regulatory_fusion_type
67+
5768
existing_feature_instance = Features::Fusion
5869
.find_by(
5970
five_prime_gene_id: five_prime_gene.gene_id,
6071
three_prime_gene_id: three_prime_gene.gene_id,
6172
five_prime_partner_status: five_prime_gene.partner_status,
6273
three_prime_partner_status: three_prime_gene.partner_status,
74+
regulatory_fusion_type: regulatory_fusion_type
6375
)
6476

6577
if existing_feature_instance.present?
@@ -74,6 +86,7 @@ def resolve(five_prime_gene:, three_prime_gene:, organization_id: nil)
7486
three_prime_gene_id: three_prime_gene.gene_id,
7587
five_prime_partner_status: five_prime_gene.partner_status,
7688
three_prime_partner_status: three_prime_gene.partner_status,
89+
regulatory_fusion_type: regulatory_fusion_type,
7790
originating_user: context[:current_user],
7891
organization_id: organization_id,
7992
)

server/app/graphql/types/entities/fusion_type.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class FusionType < Types::Entities::FeatureType
77
field :five_prime_partner_status, Types::Fusion::FusionPartnerStatus, null: false
88
field :three_prime_partner_status, Types::Fusion::FusionPartnerStatus, null: false
99

10+
field :regulatory_fusion_type, Types::Fusion::RegulatoryFusionTypeType, null: true
11+
1012
def five_prime_gene
1113
Loaders::AssociationLoader.for(Features::Fusion, :five_prime_gene).load(object)
1214
end

server/app/graphql/types/fusion/fusion_partner_input_type.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ class FusionPartnerInputType < Types::BaseInputObject
66
description: 'The status of the fusion partner'
77
argument :gene_id, Int, required: false,
88
description: 'The CIViC gene ID of the partner, if known'
9+
argument :regulatory_fusion_type, Types::Fusion::RegulatoryFusionTypeType, required: false,
10+
description: "If the fusion partner status is set to regulatory, what type of regulatory fusion is it?"
911
end
1012
end

server/app/graphql/types/fusion/fusion_partner_status.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ class FusionPartnerStatus < Types::BaseEnum
33
value 'KNOWN', value: 'known'
44
value 'UNKNOWN', value: 'unknown'
55
value 'MULTIPLE', value: 'multiple'
6+
value 'REGULATORY', value: 'regulatory'
67
end
78
end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module Types::Fusion
2+
class RegulatoryFusionTypeType < Types::BaseEnum
3+
Constants::REGULATORY_FUSION_ENUM_TYPES.each do |(name, _)|
4+
value name.upcase, value: name
5+
end
6+
end
7+
end

server/app/models/actions/create_fusion_feature.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ module Actions
22
class CreateFusionFeature
33
include Actions::Transactional
44

5-
attr_reader :feature, :originating_user, :organization_id, :create_variant, :five_prime_partner_status, :three_prime_partner_status
5+
attr_reader :feature, :originating_user, :organization_id, :create_variant, :five_prime_partner_status, :three_prime_partner_status, :regulatory_fusion_type
66

7-
def initialize(originating_user:, five_prime_gene_id:, three_prime_gene_id:, five_prime_partner_status:, three_prime_partner_status:, organization_id: nil, create_variant: true)
7+
def initialize(originating_user:, five_prime_gene_id:, three_prime_gene_id:, five_prime_partner_status:, three_prime_partner_status:, regulatory_fusion_type:, organization_id: nil, create_variant: true)
88
feature_name = "#{construct_fusion_partner_name(five_prime_gene_id, five_prime_partner_status)}::#{construct_fusion_partner_name(three_prime_gene_id, three_prime_partner_status)}"
99
@feature = Feature.new(
1010
name: feature_name,
@@ -14,10 +14,12 @@ def initialize(originating_user:, five_prime_gene_id:, three_prime_gene_id:, fiv
1414
three_prime_gene_id: three_prime_gene_id,
1515
five_prime_partner_status: five_prime_partner_status,
1616
three_prime_partner_status: three_prime_partner_status,
17+
regulatory_fusion_type: regulatory_fusion_type,
1718
feature: feature,
1819
)
1920
@five_prime_partner_status = five_prime_partner_status
2021
@three_prime_partner_status = three_prime_partner_status
22+
@regulatory_fusion_type = regulatory_fusion_type
2123
@originating_user = originating_user
2224
@organization_id = organization_id
2325
@create_variant = create_variant
@@ -26,6 +28,10 @@ def initialize(originating_user:, five_prime_gene_id:, three_prime_gene_id:, fiv
2628
def construct_fusion_partner_name(gene_id, partner_status)
2729
if partner_status == 'known'
2830
Features::Gene.find(gene_id).name
31+
elsif partner_status == 'regulatory'
32+
gene_name = Features::Gene.find(gene_id).name
33+
rft = Features::Fusion.format_regulatory_fusion_type(regulatory_fusion_type)
34+
"#{rft}@#{gene_name}"
2935
elsif partner_status == 'unknown'
3036
'?'
3137
elsif partner_status == 'multiple'

server/app/models/activities/create_fusion_feature.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
module Activities
22
class CreateFusionFeature < Base
3-
attr_reader :feature, :five_prime_gene_id, :three_prime_gene_id, :five_prime_partner_status, :three_prime_partner_status, :create_variant
3+
attr_reader :feature, :five_prime_gene_id, :three_prime_gene_id, :five_prime_partner_status, :three_prime_partner_status, :create_variant, :regulatory_fusion_type
44

5-
def initialize(originating_user:, organization_id:, five_prime_gene_id:, three_prime_gene_id:, five_prime_partner_status:, three_prime_partner_status:, create_variant: true)
5+
def initialize(originating_user:, organization_id:, five_prime_gene_id:, three_prime_gene_id:, five_prime_partner_status:, three_prime_partner_status:, regulatory_fusion_type:, create_variant: true)
66
super(organization_id: organization_id, user: originating_user)
77
@five_prime_gene_id = five_prime_gene_id
88
@three_prime_gene_id = three_prime_gene_id
99
@five_prime_partner_status = five_prime_partner_status
1010
@three_prime_partner_status = three_prime_partner_status
11+
@regulatory_fusion_type = regulatory_fusion_type
1112
@create_variant = create_variant
1213
end
1314

@@ -25,6 +26,7 @@ def call_actions
2526
three_prime_gene_id: three_prime_gene_id,
2627
five_prime_partner_status: five_prime_partner_status,
2728
three_prime_partner_status: three_prime_partner_status,
29+
regulatory_fusion_type: regulatory_fusion_type,
2830
originating_user: user,
2931
organization_id: organization&.id,
3032
create_variant: create_variant

server/app/models/constants.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,38 @@ module Constants
138138
ENSEMBL_TRANSCRIPT_ID_FORMAT = /\AENST\d{11}\.\d{1,2}\z/
139139

140140
REPRESENTATIVE_FUSION_VARIANT_NAME = 'Fusion'
141+
142+
# INSDC regulatory class vocabulary as required here: https://fusions.cancervariants.org/en/latest/nomenclature.html#regulatory-nomenclature
143+
REGULATORY_FUSION_TYPES = [
144+
["attenuator", "SO:0000140"],
145+
["CAAT_signal", "SO:0000172"],
146+
["DNase_I_hypersensitive_site", "SO:0000685"],
147+
["enhancer", "SO:0000165"],
148+
["enhancer_blocking_element", nil],
149+
["GC_signal", "SO:0000173"],
150+
["imprinting_control_region", nil],
151+
["insulator", "SO:0000627"],
152+
["locus_control_region", "SO:0000037"],
153+
["matrix_attachment_region", "SO:0000036"],
154+
["minus_35_signal", "SO:0000176"],
155+
["minus_10_signal", "SO:0000175"],
156+
["polyA_signal_sequence", "SO:0000551"],
157+
["promoter", "SO:0000167"],
158+
["recoding_stimulatory_region", "SO:1001268"],
159+
["recombination_enhancer", "SO:0002059"],
160+
["replication_regulatory_region", "SO:0001682"],
161+
["response_element", nil],
162+
["ribosome_binding_site", "SO:0000552"],
163+
["riboswitch", "SO:0000035"],
164+
["silencer", "SO:0000625"],
165+
["TATA_box", "SO:0000174"],
166+
["terminator", "SO:0000141"],
167+
["transcriptional_cis_regulatory_region", "SO:0001055"],
168+
["uORF", "SO:0002027"],
169+
["other", nil]
170+
].map { |(type, soid)| ["reg_#{type}", soid] }
171+
172+
REGULATORY_FUSION_ENUM_TYPES = REGULATORY_FUSION_TYPES.map { |(type, _)| [type, type] }.to_h
173+
174+
FUSION_PARTNER_STATUSES = [ 'known', 'unknown', 'multiple', 'regulatory' ].map { [_1, _1] }.to_h
141175
end

server/app/models/features/fusion.rb

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,33 @@ class Fusion < ActiveRecord::Base
66
belongs_to :five_prime_gene, class_name: 'Features::Gene', optional: true
77
belongs_to :three_prime_gene, class_name: 'Features::Gene', optional: true
88

9-
enum five_prime_partner_status: {
10-
known: 'known',
11-
unknown: 'unknown',
12-
multiple: 'multiple',
13-
}, _prefix: true
9+
enum five_prime_partner_status: Constants::FUSION_PARTNER_STATUSES, _prefix: true
10+
enum three_prime_partner_status: Constants::FUSION_PARTNER_STATUSES, _prefix: true
1411

15-
enum three_prime_partner_status: {
16-
known: 'known',
17-
unknown: 'unknown',
18-
multiple: 'multiple',
19-
}, _prefix: true
12+
enum regulatory_fusion_type: Constants::REGULATORY_FUSION_ENUM_TYPES
2013

2114
has_many :variant_groups
2215
has_many :source_suggestions
2316

2417
#TODO - move to feature?
2518
has_many :comment_mentions, foreign_key: :comment_id, class_name: 'EntityMention'
2619

27-
validate :partner_status_valid_for_gene_ids
28-
validate :at_least_one_gene_id
20+
validates_with FusionFeatureValidator
2921

30-
def partner_status_valid_for_gene_ids
31-
if !self.in_revision_validation_context
32-
[self.five_prime_gene, self.three_prime_gene].zip([self.five_prime_partner_status, self.three_prime_partner_status], [:five_prime_gene, :three_prime_gene]).each do |gene, status, fk|
33-
if gene.nil? && status == 'known'
34-
errors.add(fk, "Partner status cannot be 'known' if the gene isn't set")
35-
elsif !gene.nil? && status != 'known'
36-
errors.add(fk, "Partner status has to be 'known' if gene is set")
37-
end
38-
end
39-
end
22+
def display_name
23+
name
4024
end
4125

42-
def at_least_one_gene_id
43-
if !self.in_revision_validation_context && self.five_prime_gene_id.nil? && self.three_prime_gene_id.nil?
44-
errors.add(:base, "One or both of the genes need to be set")
26+
def self.format_regulatory_fusion_type(rft)
27+
if rft == 'reg_enhancer'
28+
'reg_e'
29+
elsif rft == 'reg_promoter'
30+
'reg_p'
31+
else
32+
rft
4533
end
4634
end
4735

48-
def display_name
49-
name
50-
end
51-
5236
def editable_fields
5337
[
5438
:description,

server/app/models/variant_type.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class VariantType < ActiveRecord::Base
33

44
has_and_belongs_to_many :variants
55
has_and_belongs_to_many :pipeline_types
6+
enum regulatory_fusion_type: Constants::REGULATORY_FUSION_ENUM_TYPES
67

78
def url
89
if self.soid != "N/A"

0 commit comments

Comments
 (0)