Skip to content

Commit

Permalink
Add search via bakrep api
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasjelonek committed Aug 31, 2023
1 parent e766b7e commit 34f14ad
Show file tree
Hide file tree
Showing 9 changed files with 326 additions and 41 deletions.
54 changes: 40 additions & 14 deletions src/BakrepApi.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import {
BakrepSearchResultSchema,
type BakrepSearchResult,
} from "./model/BakrepSearchResult";
import { BaktaResultSchema, type BaktaResult } from "./model/BaktaResults";
import { CheckmResultSchema, type CheckmResult } from "./model/CheckmResults";
import { DatasetSchema, type Dataset } from "./model/Dataset";
import { GtdbtkResultSchema, type GtdbtkResult } from "./model/GtdbtkResult";
import { MlstResultSchema, type MlstResult } from "./model/MlstResults";
import type { SearchInfo, SearchRequest } from "./model/Search";

let baseurl: string = "http://localhost:8080";
function initApi(url: string) {
Expand All @@ -16,6 +21,8 @@ interface BakrepApi {
fetchGtdbtkResult(dataset: Dataset): Promise<GtdbtkResult>;
fetchCheckmResult(dataset: Dataset): Promise<CheckmResult>;
fetchMlstResult(dataset: Dataset): Promise<MlstResult>;
search(request: SearchRequest): Promise<BakrepSearchResult>;
searchinfo(): Promise<SearchInfo>;
}

class BakrepApiImpl implements BakrepApi {
Expand All @@ -39,71 +46,90 @@ class BakrepApiImpl implements BakrepApi {
}
fetchBaktaResult(dataset: Dataset): Promise<BaktaResult> {
const bakta = dataset.results.filter(
(x) => x.attributes.tool === "bakta" && x.attributes.filetype === "json"
(x) => x.attributes.tool === "bakta" && x.attributes.filetype === "json",
);
if (bakta.length == 0) {
return Promise.reject(
`Unsupported: Dataset does not contain bakta result: ${dataset}`
`Unsupported: Dataset does not contain bakta result: ${dataset}`,
);
}
if (bakta.length > 1)
return Promise.reject(
`Unsupported: Dataset constains multiple bakta results: ${dataset}`
`Unsupported: Dataset constains multiple bakta results: ${dataset}`,
);
return fetch(bakta[0].url).then(this.toJson).then(BaktaResultSchema.parse);
}
fetchGtdbtkResult(dataset: Dataset): Promise<GtdbtkResult> {
const gtdb = dataset.results.filter(
(x) => x.attributes.tool === "gtdbtk" && x.attributes.filetype === "json"
(x) => x.attributes.tool === "gtdbtk" && x.attributes.filetype === "json",
);
if (gtdb.length == 0) {
return Promise.reject(
`Unsupported: Dataset does not contain gtdbtk result: ${dataset}`
`Unsupported: Dataset does not contain gtdbtk result: ${dataset}`,
);
}
if (gtdb.length > 1)
return Promise.reject(
`Unsupported: Dataset constains multiple gtdbtk results: ${dataset}`
`Unsupported: Dataset constains multiple gtdbtk results: ${dataset}`,
);
return fetch(gtdb[0].url).then(this.toJson).then(GtdbtkResultSchema.parse);
}
fetchCheckmResult(dataset: Dataset): Promise<CheckmResult> {
const checkm = dataset.results.filter(
(x) => x.attributes.tool === "checkm2" && x.attributes.filetype === "json"
(x) =>
x.attributes.tool === "checkm2" && x.attributes.filetype === "json",
);
if (checkm.length == 0) {
return Promise.reject(
`Unsupported: Dataset does not contain checkm result: ${dataset}`
`Unsupported: Dataset does not contain checkm result: ${dataset}`,
);
}
if (checkm.length > 1) {
return Promise.reject(
`Unsupported: Dataset constains multiple checkm results: ${dataset}`
`Unsupported: Dataset constains multiple checkm results: ${dataset}`,
);
}
return fetch(checkm[0].url).then(this.toJson).then(CheckmResultSchema.parse);
return fetch(checkm[0].url)
.then(this.toJson)
.then(CheckmResultSchema.parse);
}
fetchMlstResult(dataset: Dataset): Promise<MlstResult> {
const mlst = dataset.results.filter(
(x) => x.attributes.tool === "mlst" && x.attributes.filetype === "json"
(x) => x.attributes.tool === "mlst" && x.attributes.filetype === "json",
);
if (mlst.length == 0) {
return Promise.reject(
`Unsupported: Dataset does not contain mlst result: ${dataset}`
`Unsupported: Dataset does not contain mlst result: ${dataset}`,
);
}
if (mlst.length > 1) {
return Promise.reject(
`Unsupported: Dataset constains multiple mlst results: ${dataset}`
`Unsupported: Dataset constains multiple mlst results: ${dataset}`,
);
}
return fetch(mlst[0].url).then(this.toJson).then(MlstResultSchema.parse);
}
searchinfo(): Promise<SearchInfo> {
return fetch(baseurl + "/search/_info")
.then(this.toJson)
.then((j) => j as SearchInfo);
}
search(request: SearchRequest): Promise<BakrepSearchResult> {
return fetch(baseurl + "/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(request),
})
.then(this.toJson)
.then((j) => BakrepSearchResultSchema.parse(j));
}
}

function useApi(): BakrepApi {
return new BakrepApiImpl(baseurl);
}

export type { BakrepApi };
export { initApi, useApi };
export type { BakrepApi };
44 changes: 44 additions & 0 deletions src/model/BakrepSearchResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { z } from "zod";
import { GenomeSchema, StatsSchema } from "./BaktaResults";
import { QualitySchema } from "./CheckmResults";
import { ClassfificationSchema } from "./GtdbtkResult";

const SimpleFeatureSchema = z.object({
gene: z.optional(z.nullable(z.string())),
product: z.optional(z.nullable(z.string())),
});

const SimpleGtdbtkSchema = z.object({
classification: ClassfificationSchema,
});
const SimpleMlstEntrySchema = z.object({
sequence_type: z.string(),
});
const SimpleCheckm2Schema = z.object({
quality: QualitySchema,
});

const BakrepSearchEntrySchema = z.object({
id: z.string(),
bakta: z.optional(
z.object({
genome: GenomeSchema,
stats: StatsSchema,
features: z.optional(z.array(SimpleFeatureSchema)),
}),
),
gtdbtk: z.optional(SimpleGtdbtkSchema),
mlst: z.optional(SimpleMlstEntrySchema),
checkm2: z.optional(SimpleCheckm2Schema),
});

const BakrepSearchResultSchema = z.object({
offset: z.number(),
total: z.number(),
results: z.array(BakrepSearchEntrySchema),
});

export type BakrepSearchResultEntry = z.infer<typeof BakrepSearchEntrySchema>;
export type BakrepSearchResult = z.infer<typeof BakrepSearchResultSchema>;

export { BakrepSearchEntrySchema, BakrepSearchResultSchema };
4 changes: 2 additions & 2 deletions src/model/BaktaResults.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from "zod";

const GenomeSchema = z.object({
export const GenomeSchema = z.object({
genus: z.string(),
species: z.string(),
strain: z.string(),
Expand All @@ -9,7 +9,7 @@ const GenomeSchema = z.object({
translation_table: z.number(),
});

const StatsSchema = z.object({
export const StatsSchema = z.object({
no_sequences: z.number(),
size: z.number(),
gc: z.number(),
Expand Down
4 changes: 2 additions & 2 deletions src/model/CheckmResults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const CalculationSchema = z.object({
model: z.string(),
translation_table: z.number(),
notes: z.string(),
})
});

const CheckmResultSchema = z.object({
quality: QualitySchema,
Expand All @@ -20,4 +20,4 @@ export type Quality = z.infer<typeof QualitySchema>;
export type Calculation = z.infer<typeof CalculationSchema>;
export type CheckmResult = z.infer<typeof CheckmResultSchema>;

export { CheckmResultSchema };
export { CheckmResultSchema, QualitySchema, CalculationSchema };
76 changes: 76 additions & 0 deletions src/model/Search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
export type EmptyQuery = {};
export type NumberQuery = {
field: string;
op: "==" | "!=" | "<" | "<=" | ">" | ">=" | "[]";
value: number;
};
export type RangeQuery = {
field: string;
op: "[]";
value: {
from: number;
to: number;
};
};
export type StringQuery = {
field: string;
op: "==" | "~";
value: string;
};
export type CompoundQuery = {
op: "or" | "and";
value: Query[];
};
export type NotQuery = {
op: "not";
value: Query;
};
export type NestedQuery = {
op: "nested";
field: string;
value: Query;
};

export type Query =
| EmptyQuery
| CompoundQuery
| NotQuery
| NumberQuery
| StringQuery
| NestedQuery
| RangeQuery;

export type SortOption = {
field: string;
ord: "asc" | "desc";
};

export type SearchRequest = {
offset: number;
limit: number;
query: Query;
sort: SortOption[];
};

export type SearchResult<T> = {
offset: number;
total: number;
results: T[];
};

export type SearchInfoLeaf = {
field: string;
ops: string[];
type: "text" | "number";
};
export type SearchInfoNested = {
field: string;
fields: SearchInfoField[];
ops: string[];
type: "nested";
};
export type SearchInfoField = SearchInfoLeaf | SearchInfoNested;

export type SearchInfo = {
fields: SearchInfoField[];
};
2 changes: 1 addition & 1 deletion src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const router = createRouter({
{
path: "/search",
name: "search",
component: () => import("../views/SearchView.vue"),
component: () => import("../views/search/SearchView.vue"),
},
{
path: "/imprint",
Expand Down
22 changes: 0 additions & 22 deletions src/views/SearchView.vue

This file was deleted.

Loading

0 comments on commit 34f14ad

Please sign in to comment.