Skip to content

Commit 381c816

Browse files
committed
add: support for db urls in search
1 parent 99f7af8 commit 381c816

3 files changed

Lines changed: 62 additions & 5 deletions

File tree

utils/accessionLinks.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
getExternalArchiveUrl,
44
getInternalUrl,
55
parseAccessions,
6+
isAccessionUrl,
67
startsWithAccession,
78
} from "./accessionLinks";
89

@@ -161,3 +162,44 @@ describe("parseAccessions", () => {
161162
expect(parseAccessions("brain single cell rna")).toEqual([]);
162163
});
163164
});
165+
166+
describe("isAccessionUrl", () => {
167+
it("recognizes pasted archive URLs and finds the accession inside", () => {
168+
const cases: [string, string][] = [
169+
[
170+
"http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE317357",
171+
"/p/GSE317357",
172+
],
173+
["https://www.ncbi.nlm.nih.gov/sra/?term=SRX1234567", "/e/SRX1234567"],
174+
["https://www.ebi.ac.uk/ena/browser/view/SRP123456", "/p/SRP123456"],
175+
[
176+
"https://www.ebi.ac.uk/biostudies/arrayexpress/studies/E-MTAB-1234",
177+
"/p/E-MTAB-1234",
178+
],
179+
["https://ddbj.nig.ac.jp/search/entry/gea/E-GEAD-282", "/p/E-GEAD-282"],
180+
["https://ngdc.cncb.ac.cn/gsa/browse/CRA000004", "/p/CRA000004"],
181+
["www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSM7", "/s/GSM7"],
182+
];
183+
for (const [url, expected] of cases) {
184+
expect(isAccessionUrl(url)).toBe(true);
185+
expect(parseAccessions(url)[0]?.url).toBe(expected);
186+
}
187+
});
188+
189+
it("keeps PRJ/submission URLs on their async-resolve path", () => {
190+
const prj = parseAccessions(
191+
"https://www.ebi.ac.uk/ena/browser/view/PRJEB12345",
192+
)[0];
193+
expect(isAccessionUrl("https://www.ebi.ac.uk/ena/browser/view/PRJEB12345"))
194+
.toBe(true);
195+
expect(prj.isPrj).toBe(true);
196+
});
197+
198+
it("ignores non-URLs and URLs with no accession", () => {
199+
expect(isAccessionUrl("https://seqout.org/about")).toBe(false);
200+
expect(isAccessionUrl("https://github.com/some/repo")).toBe(false);
201+
// Not a URL: already handled by startsWithAccession, not this.
202+
expect(isAccessionUrl("GSE317357")).toBe(false);
203+
expect(isAccessionUrl("cancer single cell")).toBe(false);
204+
});
205+
});

utils/accessionLinks.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ export function startsWithAccession(query: string): boolean {
109109
return ACC_ANCHORED.test(query.trim());
110110
}
111111

112+
// A pasted archive URL — ".../acc.cgi?acc=GSE317357", ".../ena/browser/view/SRP12",
113+
// ".../arrayexpress/experiments/E-MTAB-1234" — is an accession the user wants to
114+
// open, not a phrase to full-text search. The accession sits mid-string, so
115+
// startsWithAccession can't see it. Any host counts: wherever the link came from,
116+
// the useful answer is the project page. Takes the first accession in the URL.
117+
export function isAccessionUrl(query: string): boolean {
118+
const trimmed = query.trim();
119+
if (!/^(?:https?:\/\/|www\.)/i.test(trimmed)) return false;
120+
return parseAccessions(trimmed).length > 0;
121+
}
122+
112123
export type ExternalArchive = { url: string; archive: string; label: string };
113124

114125
export function getExternalArchiveUrl(

utils/useSearchHistory.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { useState } from "react";
22
import { SERVER_URL } from "./constants";
3-
import { parseAccessions, startsWithAccession } from "./accessionLinks";
3+
import {
4+
isAccessionUrl,
5+
parseAccessions,
6+
startsWithAccession,
7+
} from "./accessionLinks";
48
import { getProjectShortUrl } from "./shortUrl";
59

610
const HISTORY_KEY = "searchHistory";
@@ -57,10 +61,10 @@ export function useSearchHistory() {
5761
);
5862
saveHistory(newHistory);
5963

60-
// "<accession> ..." (optionally with a pasted title/notes) → jump to the
61-
// first recognized accession instead of full-text search. Any further
62-
// accessions in the text are ignored.
63-
if (startsWithAccession(trimmed)) {
64+
// "<accession> ..." (optionally with a pasted title/notes), or an archive URL
65+
// with the accession inside it → jump to the first recognized accession
66+
// instead of full-text search. Any further accessions in the text are ignored.
67+
if (startsWithAccession(trimmed) || isAccessionUrl(trimmed)) {
6468
const first = parseAccessions(trimmed)[0];
6569
if (first) {
6670
if (first.isPrj) {

0 commit comments

Comments
 (0)