diff --git a/ddl/templates/versions/8/fixtures.sql b/ddl/templates/versions/8/fixtures.sql index 3c1b7a37a6..ba88dc4a87 100644 --- a/ddl/templates/versions/8/fixtures.sql +++ b/ddl/templates/versions/8/fixtures.sql @@ -9,19 +9,21 @@ VALUES ('Core', 'Homozygous - Core'), ('Cre BAC', 'EUCOMMTools-Cre BAC'), ('Human','Homozygous - Human'); -INSERT INTO mutation_type(mutation_type) +INSERT INTO mutation_types(mutation_type) VALUES ('conditional'), ('deletion'), ('insertion'); -INSERT INTO targeting_type(targeting_type) +INSERT INTO targeting_types(targeting_type) VALUES ('single_targeting'), ('double_targeting'), ('modified_bac_insertion'); -INSERT INTO final_cassette_function(final_cassette_function) +INSERT INTO cassette_functions(final_cassette_function) VALUES ('knockout_first'), ('reporter_only'), ('conditional_only'), ('cre_expressor'), ('promoterless_cre_expressor'); + +[% FOR cassette IN diff --git a/ddl/templates/versions/8/up.sql b/ddl/templates/versions/8/up.sql index 280961be2b..0f19b39abc 100644 --- a/ddl/templates/versions/8/up.sql +++ b/ddl/templates/versions/8/up.sql @@ -9,23 +9,34 @@ CREATE TABLE sponsors ( GRANT SELECT ON sponsors TO "[% ro_role %]"; GRANT SELECT, INSERT, UPDATE, DELETE ON sponsors TO "[% rw_role %]"; -CREATE TABLE mutation_type ( +-- XXX at the very least, need unique key on mutation_type, targeting_type, cassette_function +-- Should we dispense with the SERIAL id column on these tables? + +CREATE TABLE mutation_types ( id SERIAL PRIMARY KEY, mutation_type TEXT NOT NULL ); -GRANT SELECT ON mutation_type TO "[% ro_role %]"; -GRANT SELECT, INSERT, UPDATE, DELETE ON mutation_type TO "[% rw_role %]"; +GRANT SELECT ON mutation_types TO "[% ro_role %]"; +GRANT SELECT, INSERT, UPDATE, DELETE ON mutation_types TO "[% rw_role %]"; -CREATE TABLE targeting_type ( +CREATE TABLE targeting_types ( id SERIAL PRIMARY KEY, targeting_type TEXT NOT NULL ); -GRANT SELECT ON targeting_type TO "[% ro_role %]"; -GRANT SELECT, INSERT, UPDATE, DELETE ON targeting_type TO "[% rw_role %]"; +GRANT SELECT ON targeting_types TO "[% ro_role %]"; +GRANT SELECT, INSERT, UPDATE, DELETE ON targeting_types TO "[% rw_role %]"; + +CREATE TABLE cassette_functions ( + id SERIAL PRIMARY KEY, + cassette_function TEXT NOT NULL +); +GRANT SELECT ON cassette_functions TO "[% ro_role %]"; +GRANT SELECT, INSERT, UPDATE, DELETE ON cassette_functions TO "[% rw_role %]"; -CREATE TABLE final_cassette_function ( - id SERIAL PRIMARY KEY, - final_cassette_function TEXT NOT NULL +CREATE TABLE cassette_cassette_functions ( + cassette_id INTEGER NOT NULL REFERENCES cassettes(id), + function_id INTEGER NOT NULL REFERENCES cassette_functions(id), + PRIMARY KEY(cassette_id,function_id) ); -GRANT SELECT ON final_cassette_function TO "[% ro_role %]"; -GRANT SELECT, INSERT, UPDATE, DELETE ON final_cassette_function TO "[% rw_role %]"; +GRANT SELECT ON cassette_cassette_functions TO "[% ro_role %]"; +GRANT SELECT, INSERT, UPDATE, DELETE ON cassette_cassette_functions TO "[% rw_role %]"; diff --git a/lib/LIMS2/AlleleRequest.pm b/lib/LIMS2/AlleleRequest.pm new file mode 100644 index 0000000000..1c0f70e339 --- /dev/null +++ b/lib/LIMS2/AlleleRequest.pm @@ -0,0 +1,89 @@ +package LIMS2::AlleleRequest; + +use strict; +use warnings FATAL => 'all'; + +use Moose; +use MooseX::ClassAttribute; +use List::MoreUtils qw( any ); +use namespace::autoclean; + +class_has handled_targeting_types => ( + is => 'ro', + isa => 'ArrayRef[Str]', + default => sub { [] } +); + +sub handles { + my ( $class, $targeting_type ) = @_; + + return any { $_ eq $targeting_type } @{ $class->handled_targeting_types }; +} + +has model => ( + is => 'ro', + isa => 'LIMS2::Model', + required => 1 +); + +has [ qw( species gene_id ) ] => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub _build_designs { + my ( $self, $mutation_type ) = @_; + + return $self->model->list_assigned_designs_for_gene( + { + species => $self->species, + gene_id => $self->gene_id, + type => $self->design_types_for( $mutation_type ) + } + ); +} + +## no critic(RequireFinalReturn) +sub design_types_for { + my ( $self, $mutation_type ) = @_; + + if ( $mutation_type eq 'ko first' ) { + return [ 'conditional', 'artificial-intron', 'intron-replacement' ]; + } + + $self->model->throw( Implementation => "Unrecognized mutation type: $mutation_type" ); +} +## use critic + +sub design_wells { + my ( $self, $design ) = @_; + return map { $_->output_wells } $design->process_designs_rs->search_related( process => { type_id => 'create_di' } ); +} + + + +# Input: +# +# gene_id: Snf8 ( MGI:1343161 ) +# targeting type: double targeting +# first allele Mutation type: ko first +# first allele cassette function: ko first +# second allele mutation type: conditional +# second allele cassette function: reporter only (conditional + cre) + +# Output: +# +# Designs +# Design wells +# Final vector wells for 1st allele +# Final vector wells for 2nd allele +# First EP +# Second EP + +__PACKAGE__->meta->make_immutable; + +1; + +__END__ + diff --git a/lib/LIMS2/AlleleRequest/DoubleTargeted.pm b/lib/LIMS2/AlleleRequest/DoubleTargeted.pm new file mode 100644 index 0000000000..64a07ac76a --- /dev/null +++ b/lib/LIMS2/AlleleRequest/DoubleTargeted.pm @@ -0,0 +1,69 @@ +package LIMS2::AlleleRequest::DoubleTargeted; + +use strict; +use warnings FATAL => 'all'; + +use Moose; +use MooseX::ClassAttribute; +use namespace::autoclean; + +extends qw( LIMS2::AlleleRequest ); + +class_has '+handled_targeting_types' => ( + default => sub { [ 'double_targeted' ] } +); + +has [ qw( first_allele_mutation_type first_allele_cassette_function second_allele_mutation_type second_allele_cassette_function ) ] => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +has [ qw( first_allele_designs second_allele_designs ) ] => ( + is => 'ro', + isa => 'ArrayRef[LIMS2::Model::Schema::Result::Design]', + init_arg => undef, + lazy_build => 1 +); + +sub _build_first_allele_designs { + my $self = shift; + return $self->_build_designs( $self->first_allele_mutation_type ); +} + +sub _build_second_allele_designs { + my $self = shift; + return $self->_build_designs( $self->second_allele_mutation_type ); +} + +has [ + qw( first_allele_design_wells second_allele_design_wells + first_allele_final_vector_wells second_allele_final_vector_wells + ) +] => ( + is => 'ro', + isa => 'ArrayRef[LIMS2::Model::Schema::Result::Well]', + init_arg => undef, + lazy_build => 1 +); + +sub _build_first_allele_design_wells { + my $self = shift; + [ map { $self->design_wells($_) } @{$self->first_allele_designs} ]; +} + +sub _build_second_allele_design_wells { + my $self = shift; + [ map { $self->design_wells($_) } @{$self->second_allele_designs} ]; +} + +sub _build_first_allele_final_vector_wells { + my $self = shift; + +} + +__PACKAGE__->meta->make_immutable; + +1; + +__END__ diff --git a/lib/LIMS2/AlleleRequestFactory.pm b/lib/LIMS2/AlleleRequestFactory.pm new file mode 100644 index 0000000000..411e34a5fb --- /dev/null +++ b/lib/LIMS2/AlleleRequestFactory.pm @@ -0,0 +1,54 @@ +package LIMS2::AlleleRequestFactory; + +use strict; +use warnings FATAL => 'all'; + +use Moose; +use Module::Pluggable::Object; +use LIMS2::Exception::Implementation; +use namespace::autoclean; + +has model => ( + is => 'ro', + isa => 'LIMS2::Model', + required => 1 +); + +has species => ( + is => 'ro', + isa => 'Str', + required => 1 +); + +sub plugins { + my $self = shift; + return Module::Pluggable::Object->new( search_path => 'LIMS2::AlleleRequest', require => 1 )->plugins; +} + +## no critic(RequireFinalReturn) +sub allele_request { + my ( $self, %params ) = @_; + + my $targeting_type = delete $params{targeting_type} + or LIMS2::Exception::Implementation->throw( "allele_request() requires targeting_type" ); + + $params{model} ||= $self->model; + $params{species} ||= $self->species; + + for my $plugin ( $self->plugins ) { + if ( $plugin->handles( $targeting_type ) ) { + return $plugin->new( \%params ); + } + } + + LIMS2::Exception::Implementation->throw( "Allele request targeting type '$targeting_type' not recognized" ); +} +## use critic + +__PACKAGE__->meta->make_immutable; + +1; + +__END__ + + diff --git a/t/60-allele-request.t b/t/60-allele-request.t new file mode 100755 index 0000000000..e7b4d5d062 --- /dev/null +++ b/t/60-allele-request.t @@ -0,0 +1,59 @@ +#!/usr/bin/env perl + +use strict; +use warnings FATAL => 'all'; + +#use LIMS2::Test; +use Test::Most; +use LIMS2::AlleleRequestFactory; + +# XXX Naughty hack, we should really use LIMS2::Test +{ + require LIMS2::Model; + + my $model; + + sub model { + return $model ||= LIMS2::Model->new( { user => 'tasks' } ); + } +} + +ok my $arf = LIMS2::AlleleRequestFactory->new( model => model(), species => 'Mouse' ), + 'create allele request factory'; + +isa_ok $arf, 'LIMS2::AlleleRequestFactory'; + +throws_ok { $arf->allele_request() } + qr/\Qallele_request() requires targeting_type\E/, 'allele_request requires targeting_type'; + +ok my $ar = $arf->allele_request( + gene_id => 'MGI:1343161', + targeting_type => 'double_targeted', + first_allele_mutation_type => 'ko first', + first_allele_cassette_function => 'ko first', + second_allele_mutation_type => 'ko first', + second_allele_cassette_function => 'reporter only' +), 'constructor succeeds'; + +my $first_allele_designs; +lives_ok { $first_allele_designs = $ar->first_allele_designs } 'first_allele_designs succeeds'; +cmp_bag [ map { $_->id } @{$first_allele_designs} ], [ 76 ], 'first_allele_designs returns expected result'; + +my $second_allele_designs; +lives_ok { $second_allele_designs = $ar->second_allele_designs } 'second_allele_designs succeeds'; +cmp_bag [ map { $_->id } @{$second_allele_designs} ], [ 76 ], 'second_allele_designs returns expected result'; + +my $first_allele_design_wells; +lives_ok { $first_allele_design_wells = $ar->first_allele_design_wells } 'first_allele_design_wells succeeds'; +cmp_bag [ map { $_->as_string } @{$first_allele_design_wells} ], [ '4_C04', '34_C04' ], 'first_allele_design_wells returns the expected result'; + +my $second_allele_design_wells; +lives_ok { $second_allele_design_wells = $ar->second_allele_design_wells } 'second_allele_design_wells succeeds'; +cmp_bag [ map { $_->as_string } @{$second_allele_design_wells} ], [ '4_C04', '34_C04' ], 'second_allele_design_wells returns the expected result'; + + + + + + +done_testing();