fetchForTranscript.ts 4.09 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/**
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17 18
import { wrap } from 'comlink';

19
import downloadAsFile from 'src/shared/helpers/downloadAsFile';
20

21 22 23 24 25
import {
  TranscriptOptions,
  TranscriptOption,
  transcriptOptionsOrder
} from 'src/shared/components/instant-download/instant-download-transcript/InstantDownloadTranscript';
26
import {
27
  fetchTranscriptSequenceMetadata,
Imran Salam's avatar
Imran Salam committed
28
  fetchGeneWithoutTranscriptsSequenceMetadata,
29
  TranscriptSequenceMetadata
30
} from './fetchSequenceChecksums';
31

32
import type {
33 34 35 36
  WorkerApi,
  SingleSequenceFetchParams
} from 'src/shared/workers/sequenceFetcher.worker';

37 38 39 40 41 42 43 44
type Options = {
  transcript: Partial<TranscriptOptions>;
  gene: {
    genomicSequence: boolean;
  };
};

type FetchPayload = {
45
  genomeId: string;
46
  geneId: string;
47
  transcriptId: string;
48 49 50 51 52
  options: Options;
};

export const fetchForTranscript = async (payload: FetchPayload) => {
  const {
53
    genomeId,
54 55 56 57
    geneId,
    transcriptId,
    options: { transcript: transcriptOptions, gene: geneOptions }
  } = payload;
58
  const transcriptSequenceData = await fetchTranscriptSequenceMetadata({
59 60 61
    genomeId,
    transcriptId
  });
62 63 64 65
  const sequenceDownloadParams = prepareDownloadParameters({
    transcriptSequenceData,
    options: transcriptOptions
  });
66

67
  if (geneOptions.genomicSequence) {
Imran Salam's avatar
Imran Salam committed
68 69 70 71 72 73 74
    const metadata = await fetchGeneWithoutTranscriptsSequenceMetadata({
      genomeId,
      geneId
    });
    sequenceDownloadParams.unshift(
      getGenomicSequenceData(metadata.stable_id, metadata.unversioned_stable_id)
    );
75
  }
76

77 78 79
  const worker = new Worker(
    new URL('src/shared/workers/sequenceFetcher.worker.ts', import.meta.url)
  );
80 81 82 83

  const service = wrap<WorkerApi>(worker);

  const sequences = await service.downloadSequences(sequenceDownloadParams);
84

85 86 87
  worker.terminate();

  downloadAsFile(sequences, `${transcriptId}.fasta`, {
88 89 90 91
    type: 'text/x-fasta'
  });
};

92 93 94
type PrepareDownloadParametersParams = {
  transcriptSequenceData: TranscriptSequenceMetadata;
  options: Partial<TranscriptOptions>;
95 96
};

97 98 99
// map of field names received from component to field names returned when fetching checksums
const labelTypeToSequenceType: Record<
  TranscriptOption,
Imran Salam's avatar
Imran Salam committed
100 101 102 103 104
  | keyof Omit<
      TranscriptSequenceMetadata,
      'stable_id' | 'unversioned_stable_id'
    >
  | 'genomic'
105 106 107
> = {
  genomicSequence: 'genomic',
  cdna: 'cdna',
Imran Salam's avatar
Imran Salam committed
108 109
  cds: 'cds',
  proteinSequence: 'protein'
110
};
111

Imran Salam's avatar
Imran Salam committed
112 113 114 115
export const prepareDownloadParameters = (
  params: PrepareDownloadParametersParams
) =>
  transcriptOptionsOrder
116
    .filter((option) => params.options[option])
Imran Salam's avatar
Imran Salam committed
117
    .map((option) => labelTypeToSequenceType[option]) // 'genomic', 'cdna', 'cds', 'protein'
118 119
    .map((option) => {
      if (option === 'genomic') {
Imran Salam's avatar
Imran Salam committed
120 121 122 123
        return getGenomicSequenceData(
          params.transcriptSequenceData.stable_id,
          params.transcriptSequenceData.unversioned_stable_id
        );
124 125
      } else {
        const dataForSingleSequence = params.transcriptSequenceData[option];
Imran Salam's avatar
Imran Salam committed
126

127 128 129 130
        if (!dataForSingleSequence) {
          // shouldn't happen; but to keep typescript happy
          return null;
        }
Imran Salam's avatar
Imran Salam committed
131

132 133 134 135 136 137 138
        return {
          label: dataForSingleSequence.label,
          url: `/api/refget/sequence/${dataForSingleSequence.checksum}?accept=text/plain`
        };
      }
    })
    .filter(Boolean) as SingleSequenceFetchParams[];
139

Imran Salam's avatar
Imran Salam committed
140 141 142 143 144 145 146
export const getGenomicSequenceData = (
  versionedStableId: string,
  unversionedStableId: string
) => ({
  label: `${versionedStableId} genomic`,
  url: `https://rest.ensembl.org/sequence/id/${unversionedStableId}?content-type=text/plain&type=genomic`
});