File size: 2,642 Bytes
cd0c7a9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
"""BLAST program / database matrix and sequence-type-aware resolution.

Programs map to the NCBI QBLAST PROGRAMS. Databases are validated against the
program's valid target types so a protein-only db (nr) is never sent for a
nucleotide program (blastn) and vice versa.
"""

from app.services.sequence_utils import detect_sequence_type

PROTEIN_PROGRAMS = ["blastp", "tblastn"]
NUCLEOTIDE_PROGRAMS = ["blastn", "blastx", "tblastx"]
ALL_PROGRAMS = ["blastp", "blastn", "blastx", "tblastn", "tblastx"]

PROGRAM_DATABASES = {
    "blastp": ["nr", "swissprot", "pdb", "pdbaa", "refseq_protein", "env_nr"],
    "blastn": ["nt", "refseq_rna", "refseq_genomic", "est", "gss"],
    "blastx": ["nr", "swissprot", "pdb", "pdbaa", "refseq_protein"],
    "tblastn": ["nt", "refseq_rna", "refseq_genomic", "est", "gss"],
    "tblastx": ["nt", "refseq_rna", "refseq_genomic", "est", "gss"],
}

DEFAULT_PROGRAM = {"protein": "blastp", "dna": "blastn", "rna": "blastn"}
DEFAULT_DATABASE = {"protein": "nr", "dna": "nt", "rna": "nt"}
FAST_DATABASE = {"protein": "swissprot", "dna": "refseq_rna", "rna": "refseq_rna"}


def resolve_blast_params(
    sequence: str,
    program: str | None = None,
    database: str | None = None,
    fast_mode: bool = False,
) -> tuple[str, str, str]:
    """Return (program, database, seq_type) with safe normalization.

    An explicitly requested program that doesn't match the query's detected
    type raises ValueError (the caller surfaces it as a clear job error).
    An incompatible or missing database falls back to the program's default so
    the frontend's permissive defaults (e.g. nr sent for a DNA query) degrade
    gracefully instead of erroring.
    """
    seq_type = detect_sequence_type(sequence)
    if seq_type not in ("protein", "dna", "rna"):
        raise ValueError(f"Could not determine sequence type for BLAST (detected: {seq_type})")

    if not program:
        program = DEFAULT_PROGRAM[seq_type]
    program = program.lower().strip()
    if program not in ALL_PROGRAMS:
        raise ValueError(f"Unsupported BLAST program: {program}")

    allowed = PROTEIN_PROGRAMS if seq_type == "protein" else NUCLEOTIDE_PROGRAMS
    if program not in allowed:
        raise ValueError(f"Program '{program}' cannot be used with a {seq_type} query")

    if not database:
        database = FAST_DATABASE[seq_type] if fast_mode else DEFAULT_DATABASE[seq_type]
    database = database.lower().strip()

    valid_dbs = PROGRAM_DATABASES[program]
    if database not in valid_dbs:
        database = FAST_DATABASE[seq_type] if fast_mode else DEFAULT_DATABASE[seq_type]

    return program, database, seq_type