600 lines
21 KiB
TypeScript
600 lines
21 KiB
TypeScript
import { createCachedLoader, loadDropdownBundle } from "@/services/dropdownCache";
|
||
import { getAuthToken } from "@/utils/token";
|
||
import {
|
||
NONE_SELECT_VALUE,
|
||
type ReferenceBasesRecord,
|
||
type ReferenceQuery,
|
||
type ReferenceRecord,
|
||
type ReferenceSetPageOptions,
|
||
type ReferenceSetQuery,
|
||
type ReferenceSetRecord,
|
||
type SelectOption,
|
||
} from "./types";
|
||
|
||
interface BrapiPagination {
|
||
currentPage: number;
|
||
pageSize: number;
|
||
totalCount: number;
|
||
totalPages: number;
|
||
}
|
||
|
||
interface BrapiListResponse<T> {
|
||
metadata: {
|
||
pagination: BrapiPagination;
|
||
status: Array<Record<string, unknown>>;
|
||
datafiles: Array<Record<string, unknown>>;
|
||
};
|
||
result: {
|
||
data: T[];
|
||
};
|
||
}
|
||
|
||
interface BrapiSingleResponse<T> {
|
||
metadata: {
|
||
pagination: BrapiPagination;
|
||
status: Array<Record<string, unknown>>;
|
||
datafiles: Array<Record<string, unknown>>;
|
||
};
|
||
result: T;
|
||
}
|
||
|
||
interface VariantSetResponse {
|
||
variantSetDbId: string;
|
||
variantSetName: string | null;
|
||
referenceSetDbId: string | null;
|
||
}
|
||
|
||
interface VariantResponse {
|
||
variantDbId: string;
|
||
referenceSetDbId: string | null;
|
||
}
|
||
|
||
type ReferenceSetPayload = Partial<Record<
|
||
| "id"
|
||
| "reference_set_name"
|
||
| "assembly_pui"
|
||
| "description"
|
||
| "is_derived"
|
||
| "md5checksum"
|
||
| "source_uri"
|
||
| "species_ontology_term"
|
||
| "species_ontology_termuri"
|
||
| "source_germplasm_id",
|
||
unknown
|
||
>>;
|
||
|
||
type ReferencePayload = Partial<Record<
|
||
"id" | "reference_name" | "reference_set_id" | "length" | "md5checksum" | "source_divergence",
|
||
unknown
|
||
>>;
|
||
|
||
type ReferenceBasesPayload = Partial<Record<
|
||
"id" | "reference_id" | "page_number" | "bases",
|
||
unknown
|
||
>>;
|
||
|
||
const URL_PATTERN = /^https?:\/\/.+/i;
|
||
const BASES_PATTERN = /^[ACGTNacgtn*.-]*$/;
|
||
|
||
const apiBase = () => {
|
||
if (typeof window !== "undefined") return "";
|
||
return process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000";
|
||
};
|
||
|
||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||
const token = getAuthToken();
|
||
const response = await fetch(`${apiBase()}${path}`, {
|
||
...init,
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||
...(init?.headers || {}),
|
||
},
|
||
});
|
||
|
||
if (!response.ok) {
|
||
const detail = await response.text();
|
||
throw new Error(detail || `请求失败:${response.status}`);
|
||
}
|
||
return response.json() as Promise<T>;
|
||
}
|
||
|
||
const optionalText = (value: unknown) => {
|
||
const normalized = String(value ?? "").trim();
|
||
if (!normalized || normalized === NONE_SELECT_VALUE) return null;
|
||
return normalized;
|
||
};
|
||
|
||
const requiredText = (value: unknown, message: string) => {
|
||
const normalized = optionalText(value);
|
||
if (!normalized) throw new Error(message);
|
||
return normalized;
|
||
};
|
||
|
||
const optionalNumber = (value: unknown) => {
|
||
const normalized = optionalText(value);
|
||
if (normalized === null) return null;
|
||
const parsed = Number(normalized);
|
||
return Number.isNaN(parsed) ? null : parsed;
|
||
};
|
||
|
||
const optionalBoolean = (value: unknown) => {
|
||
const normalized = optionalText(value);
|
||
if (!normalized) return null;
|
||
return ["true", "1", "yes"].includes(normalized.toLowerCase());
|
||
};
|
||
|
||
const optionalUrl = (value: unknown, label: string) => {
|
||
const normalized = optionalText(value);
|
||
if (!normalized) return null;
|
||
if (!URL_PATTERN.test(normalized)) {
|
||
throw new Error(`${label} 必须是有效的 URL`);
|
||
}
|
||
return normalized;
|
||
};
|
||
|
||
const validateBases = (value: unknown, required = false) => {
|
||
const normalized = optionalText(value);
|
||
if (!normalized) {
|
||
if (required) throw new Error("碱基序列片段不能为空");
|
||
return null;
|
||
}
|
||
if (normalized.length > 2048) {
|
||
throw new Error("碱基序列片段不能超过 2048 字符");
|
||
}
|
||
if (!BASES_PATTERN.test(normalized)) {
|
||
throw new Error("碱基序列仅允<E4BB85>?A/C/G/T/N 及常见占位符");
|
||
}
|
||
return normalized.toUpperCase();
|
||
};
|
||
|
||
export const mapReferenceSet = (item: ReferenceSetRecord): ReferenceSetRecord => ({
|
||
...item,
|
||
id: item.referenceSetDbId || item.id,
|
||
reference_set_name: item.reference_set_name || item.referenceSetName || null,
|
||
assembly_pui: item.assembly_pui || item.assemblyPUI || null,
|
||
is_derived: item.is_derived ?? item.isDerived ?? null,
|
||
source_uri: item.source_uri || item.sourceURI || null,
|
||
species_ontology_term:
|
||
item.species_ontology_term
|
||
|| item.speciesOntologyTerm
|
||
|| (item as { species?: { term?: string } }).species?.term
|
||
|| null,
|
||
species_ontology_termuri:
|
||
item.species_ontology_termuri
|
||
|| item.speciesOntologyTermURI
|
||
|| (item as { species?: { termURI?: string } }).species?.termURI
|
||
|| null,
|
||
source_germplasm_id:
|
||
item.source_germplasm_id
|
||
|| item.sourceGermplasmDbId
|
||
|| (item as { sourceGermplasm?: Array<{ germplasmDbId?: string }> }).sourceGermplasm?.[0]?.germplasmDbId
|
||
|| null,
|
||
source_germplasm_name:
|
||
item.source_germplasm_name
|
||
|| item.sourceGermplasmName
|
||
|| (item as { sourceGermplasm?: Array<{ germplasmName?: string }> }).sourceGermplasm?.[0]?.germplasmName
|
||
|| null,
|
||
});
|
||
|
||
export const mapReference = (reference: ReferenceRecord): ReferenceRecord => ({
|
||
...reference,
|
||
id: reference.referenceDbId || reference.id,
|
||
reference_name: reference.reference_name || reference.referenceName || null,
|
||
reference_set_id: reference.reference_set_id || reference.referenceSetDbId || null,
|
||
reference_set_name: reference.reference_set_name || reference.referenceSetName || null,
|
||
source_divergence: reference.source_divergence ?? reference.sourceDivergence ?? null,
|
||
});
|
||
|
||
export const mapReferenceBases = (item: ReferenceBasesRecord): ReferenceBasesRecord => ({
|
||
...item,
|
||
id: item.referenceBasesDbId || item.id,
|
||
reference_id: item.reference_id || item.referenceDbId || null,
|
||
reference_name: item.reference_name || item.referenceName || null,
|
||
page_number: item.page_number ?? item.pageNumber ?? null,
|
||
});
|
||
|
||
function buildSpecies(payload: ReferenceSetPayload) {
|
||
const term = optionalText(payload.species_ontology_term);
|
||
const termURI = optionalUrl(payload.species_ontology_termuri, "物种本体 URI");
|
||
if (!term && !termURI) return undefined;
|
||
return { term, termURI };
|
||
}
|
||
|
||
function buildReferenceSetWriteBody(payload: ReferenceSetPayload) {
|
||
const body: Record<string, unknown> = {
|
||
referenceSetName: requiredText(payload.reference_set_name, "请填<E8AFB7>?ReferenceSet 名称"),
|
||
};
|
||
const optionalFields: Array<[string, unknown]> = [
|
||
["assemblyPUI", optionalText(payload.assembly_pui)],
|
||
["description", optionalText(payload.description)],
|
||
["isDerived", optionalBoolean(payload.is_derived)],
|
||
["md5checksum", optionalText(payload.md5checksum)],
|
||
["sourceURI", optionalUrl(payload.source_uri, "来源 URI")],
|
||
["sourceGermplasmDbId", optionalText(payload.source_germplasm_id)],
|
||
];
|
||
optionalFields.forEach(([key, value]) => {
|
||
if (value !== null && value !== undefined) body[key] = value;
|
||
});
|
||
const species = buildSpecies(payload);
|
||
if (species) body.species = species;
|
||
return body;
|
||
}
|
||
|
||
function buildReferenceWriteBody(payload: ReferencePayload) {
|
||
const body: Record<string, unknown> = {
|
||
referenceName: requiredText(payload.reference_name, "请填<E8AFB7>?Reference 名称"),
|
||
referenceSetDbId: requiredText(payload.reference_set_id, "请选择 ReferenceSet"),
|
||
};
|
||
const length = optionalNumber(payload.length);
|
||
const sourceDivergence = optionalNumber(payload.source_divergence);
|
||
const md5checksum = optionalText(payload.md5checksum);
|
||
if (length !== null) {
|
||
if (length < 0) throw new Error("序列长度不能为负");
|
||
body.length = length;
|
||
}
|
||
if (sourceDivergence !== null) body.sourceDivergence = sourceDivergence;
|
||
if (md5checksum) body.md5checksum = md5checksum;
|
||
return body;
|
||
}
|
||
|
||
function buildReferenceBasesWriteBody(payload: ReferenceBasesPayload, creating: boolean) {
|
||
const pageNumber = optionalNumber(payload.page_number);
|
||
if (pageNumber === null) throw new Error("请填写分页序");
|
||
if (pageNumber < 0) throw new Error("分页序号不能为负");
|
||
return {
|
||
referenceDbId: requiredText(payload.reference_id, "请选择 Reference"),
|
||
pageNumber,
|
||
bases: validateBases(payload.bases, creating),
|
||
};
|
||
}
|
||
|
||
function filterReferenceSets(rows: ReferenceSetRecord[], query?: ReferenceSetQuery) {
|
||
const name = optionalText(query?.reference_set_name)?.toLowerCase();
|
||
const assembly = optionalText(query?.assembly_pui)?.toLowerCase();
|
||
return rows.filter((row) => {
|
||
if (name && !String(row.reference_set_name ?? "").toLowerCase().includes(name)) return false;
|
||
if (assembly && !String(row.assembly_pui ?? "").toLowerCase().includes(assembly)) return false;
|
||
return true;
|
||
});
|
||
}
|
||
|
||
function filterReferences(rows: ReferenceRecord[], query?: ReferenceQuery) {
|
||
const name = optionalText(query?.reference_name)?.toLowerCase();
|
||
const referenceSetId = optionalText(query?.reference_set_id);
|
||
return rows.filter((row) => {
|
||
if (referenceSetId && row.reference_set_id !== referenceSetId) return false;
|
||
if (name && !String(row.reference_name ?? "").toLowerCase().includes(name)) return false;
|
||
return true;
|
||
});
|
||
}
|
||
|
||
function attachReferenceSetCounts(
|
||
rows: ReferenceSetRecord[],
|
||
references: ReferenceRecord[],
|
||
variantSets: VariantSetResponse[],
|
||
variants: VariantResponse[],
|
||
) {
|
||
return rows.map((row) => ({
|
||
...row,
|
||
reference_count: references.filter((item) => item.reference_set_id === row.id).length,
|
||
variantset_count: variantSets.filter((item) => item.referenceSetDbId === row.id).length,
|
||
variant_count: variants.filter((item) => item.referenceSetDbId === row.id).length,
|
||
}));
|
||
}
|
||
|
||
function attachReferenceBasesStats(references: ReferenceRecord[], basesPages: ReferenceBasesRecord[]) {
|
||
return references.map((reference) => {
|
||
const pages = basesPages.filter((page) => page.reference_id === reference.id);
|
||
const basesTotalLength = pages.reduce((total, page) => total + String(page.bases ?? "").length, 0);
|
||
return {
|
||
...reference,
|
||
bases_page_count: pages.length,
|
||
bases_total_length: basesTotalLength,
|
||
};
|
||
});
|
||
}
|
||
|
||
function enrichReferenceSetNames(
|
||
references: ReferenceRecord[],
|
||
referenceSets: ReferenceSetRecord[],
|
||
): ReferenceRecord[] {
|
||
const label = new Map(referenceSets.map((item) => [item.id, item.reference_set_name || item.id]));
|
||
return references.map((reference) => ({
|
||
...reference,
|
||
reference_set_name: reference.reference_set_id
|
||
? label.get(reference.reference_set_id) ?? reference.reference_set_name
|
||
: reference.reference_set_name,
|
||
}));
|
||
}
|
||
|
||
function enrichGermplasmNames(
|
||
rows: ReferenceSetRecord[],
|
||
germplasm: SelectOption[],
|
||
): ReferenceSetRecord[] {
|
||
const label = new Map(germplasm.map((item) => [item.value, item.label]));
|
||
return rows.map((row) => ({
|
||
...row,
|
||
source_germplasm_name: row.source_germplasm_id
|
||
? label.get(row.source_germplasm_id) ?? row.source_germplasm_name ?? row.source_germplasm_id
|
||
: row.source_germplasm_name,
|
||
}));
|
||
}
|
||
|
||
const referenceSetRowsLoader = createCachedLoader(async () => {
|
||
const response = await request<BrapiListResponse<ReferenceSetRecord>>("/brapi/v2/referencesets?page=0&pageSize=10");
|
||
return response.result.data.map(mapReferenceSet);
|
||
});
|
||
|
||
const referenceRowsLoader = createCachedLoader(async () => {
|
||
const response = await request<BrapiListResponse<ReferenceRecord>>("/brapi/v2/references?page=0&pageSize=10");
|
||
return response.result.data.map(mapReference);
|
||
});
|
||
|
||
const variantSetRowsLoader = createCachedLoader(async () => {
|
||
const response = await request<BrapiListResponse<VariantSetResponse>>("/brapi/v2/variantsets?page=0&pageSize=10");
|
||
return response.result.data;
|
||
});
|
||
|
||
const variantRowsLoader = createCachedLoader(async () => {
|
||
const response = await request<BrapiListResponse<VariantResponse>>("/brapi/v2/variants?page=0&pageSize=10");
|
||
return response.result.data;
|
||
});
|
||
|
||
const referenceBasesRowsLoader = createCachedLoader(async () => {
|
||
const response = await request<BrapiListResponse<ReferenceBasesRecord>>("/brapi/v2/referencebases?page=0&pageSize=10");
|
||
return response.result.data.map(mapReferenceBases);
|
||
});
|
||
|
||
export function invalidateReferenceSetPageCache() {
|
||
referenceSetRowsLoader.invalidate();
|
||
referenceRowsLoader.invalidate();
|
||
variantSetRowsLoader.invalidate();
|
||
variantRowsLoader.invalidate();
|
||
referenceBasesRowsLoader.invalidate();
|
||
}
|
||
|
||
export async function fetchReferenceSetOptions(force = false): Promise<ReferenceSetPageOptions> {
|
||
const [sharedOptions, referenceSets, references] = await Promise.all([
|
||
loadDropdownBundle({ germplasms: true }, force),
|
||
referenceSetRowsLoader.load(force),
|
||
referenceRowsLoader.load(force),
|
||
]);
|
||
|
||
return {
|
||
germplasm: sharedOptions.germplasms,
|
||
referenceSets: referenceSets.map((item) => ({
|
||
value: item.id,
|
||
label: item.reference_set_name || item.id,
|
||
})),
|
||
references: references.map((item) => ({
|
||
value: item.id,
|
||
label: `${item.reference_name || item.id}${item.reference_set_name ? ` / ${item.reference_set_name}` : ""}`,
|
||
})),
|
||
};
|
||
}
|
||
|
||
export async function loadReferenceSetPageData(params: {
|
||
referenceSetQuery?: ReferenceSetQuery;
|
||
referenceQuery?: ReferenceQuery;
|
||
force?: boolean;
|
||
} = {}) {
|
||
const force = params.force ?? false;
|
||
const [options, referenceSets, references, variantSets, variants, basesPages] = await Promise.all([
|
||
fetchReferenceSetOptions(force),
|
||
referenceSetRowsLoader.load(force),
|
||
referenceRowsLoader.load(force),
|
||
variantSetRowsLoader.load(force),
|
||
variantRowsLoader.load(force),
|
||
referenceBasesRowsLoader.load(force),
|
||
]);
|
||
|
||
const enrichedSets = enrichGermplasmNames(
|
||
attachReferenceSetCounts(referenceSets, references, variantSets, variants),
|
||
options.germplasm,
|
||
);
|
||
const enrichedReferences = attachReferenceBasesStats(
|
||
enrichReferenceSetNames(references, referenceSets),
|
||
basesPages,
|
||
);
|
||
|
||
return {
|
||
options,
|
||
referenceSets: filterReferenceSets(enrichedSets, params.referenceSetQuery),
|
||
references: filterReferences(enrichedReferences, params.referenceQuery),
|
||
basesPages,
|
||
variantSets,
|
||
variants,
|
||
};
|
||
}
|
||
|
||
export async function fetchReferenceSetRows(query?: ReferenceSetQuery, force = false): Promise<ReferenceSetRecord[]> {
|
||
const { referenceSets } = await loadReferenceSetPageData({ referenceSetQuery: query, force });
|
||
return referenceSets;
|
||
}
|
||
|
||
export async function fetchReferenceRows(query?: ReferenceQuery, force = false): Promise<ReferenceRecord[]> {
|
||
const { references } = await loadReferenceSetPageData({ referenceQuery: query, force });
|
||
return references;
|
||
}
|
||
|
||
export async function fetchReferenceSetDetail(id: string): Promise<ReferenceSetRecord> {
|
||
const response = await request<BrapiSingleResponse<ReferenceSetRecord>>(
|
||
`/brapi/v2/referencesets/${encodeURIComponent(id)}`,
|
||
);
|
||
const { options, references, variantSets, variants } = await loadReferenceSetPageData();
|
||
const [detail] = enrichGermplasmNames(
|
||
attachReferenceSetCounts([mapReferenceSet(response.result)], references, variantSets, variants),
|
||
options.germplasm,
|
||
);
|
||
return detail;
|
||
}
|
||
|
||
export async function fetchReferenceDetail(id: string): Promise<ReferenceRecord> {
|
||
const response = await request<BrapiSingleResponse<ReferenceRecord>>(
|
||
`/brapi/v2/references/${encodeURIComponent(id)}`,
|
||
);
|
||
const { referenceSets, basesPages } = await loadReferenceSetPageData();
|
||
const [detail] = attachReferenceBasesStats(
|
||
enrichReferenceSetNames([mapReference(response.result)], referenceSets),
|
||
basesPages,
|
||
);
|
||
return detail;
|
||
}
|
||
|
||
export async function fetchReferenceBasesRows(referenceDbId?: string, force = false): Promise<ReferenceBasesRecord[]> {
|
||
const pages = await referenceBasesRowsLoader.load(force);
|
||
const filtered = referenceDbId
|
||
? pages.filter((page) => page.reference_id === referenceDbId)
|
||
: pages;
|
||
return filtered.sort((a, b) => Number(a.page_number ?? 0) - Number(b.page_number ?? 0));
|
||
}
|
||
|
||
export function normalizeReferenceSetFormData(record: ReferenceSetRecord): Record<string, unknown> {
|
||
return {
|
||
id: record.id,
|
||
reference_set_name: record.reference_set_name ?? "",
|
||
assembly_pui: record.assembly_pui ?? "",
|
||
description: record.description ?? "",
|
||
is_derived: record.is_derived === true ? "true" : record.is_derived === false ? "false" : NONE_SELECT_VALUE,
|
||
md5checksum: record.md5checksum ?? "",
|
||
source_uri: record.source_uri ?? "",
|
||
species_ontology_term: record.species_ontology_term ?? "",
|
||
species_ontology_termuri: record.species_ontology_termuri ?? "",
|
||
source_germplasm_id: record.source_germplasm_id && record.source_germplasm_id !== NONE_SELECT_VALUE
|
||
? record.source_germplasm_id
|
||
: NONE_SELECT_VALUE,
|
||
};
|
||
}
|
||
|
||
export function normalizeReferenceFormData(record: ReferenceRecord): Record<string, unknown> {
|
||
return {
|
||
id: record.id,
|
||
reference_name: record.reference_name ?? "",
|
||
reference_set_id: record.reference_set_id ?? "",
|
||
length: record.length ?? "",
|
||
md5checksum: record.md5checksum ?? "",
|
||
source_divergence: record.source_divergence ?? "",
|
||
};
|
||
}
|
||
|
||
export function normalizeReferenceBasesFormData(record: ReferenceBasesRecord): Record<string, unknown> {
|
||
return {
|
||
id: record.id,
|
||
reference_id: record.reference_id ?? "",
|
||
page_number: record.page_number ?? "",
|
||
bases: record.bases ?? "",
|
||
};
|
||
}
|
||
|
||
export async function createReferenceSetRow(payload: ReferenceSetPayload): Promise<ReferenceSetRecord> {
|
||
const body = {
|
||
...buildReferenceSetWriteBody(payload),
|
||
...(optionalText(payload.id) ? { referenceSetDbId: optionalText(payload.id) } : {}),
|
||
};
|
||
const response = await request<BrapiListResponse<ReferenceSetRecord>>("/brapi/v2/referencesets", {
|
||
method: "POST",
|
||
body: JSON.stringify(body),
|
||
});
|
||
invalidateReferenceSetPageCache();
|
||
return mapReferenceSet(response.result.data[0]);
|
||
}
|
||
|
||
export async function updateReferenceSetRow(id: string, payload: ReferenceSetPayload): Promise<ReferenceSetRecord> {
|
||
const requestedId = optionalText(payload.id);
|
||
if (requestedId && requestedId !== id) {
|
||
throw new Error("ReferenceSet ID 不可修改,请新建记录");
|
||
}
|
||
const response = await request<BrapiSingleResponse<ReferenceSetRecord>>(
|
||
`/brapi/v2/referencesets/${encodeURIComponent(id)}`,
|
||
{
|
||
method: "PUT",
|
||
body: JSON.stringify(buildReferenceSetWriteBody(payload)),
|
||
},
|
||
);
|
||
invalidateReferenceSetPageCache();
|
||
return mapReferenceSet(response.result);
|
||
}
|
||
|
||
export async function deleteReferenceSetRow(id: string): Promise<void> {
|
||
await request<BrapiSingleResponse<ReferenceSetRecord>>(
|
||
`/brapi/v2/referencesets/${encodeURIComponent(id)}`,
|
||
{ method: "DELETE" },
|
||
);
|
||
invalidateReferenceSetPageCache();
|
||
}
|
||
|
||
export async function createReferenceRow(payload: ReferencePayload): Promise<ReferenceRecord> {
|
||
const body = {
|
||
...buildReferenceWriteBody(payload),
|
||
...(optionalText(payload.id) ? { referenceDbId: optionalText(payload.id) } : {}),
|
||
};
|
||
const response = await request<BrapiListResponse<ReferenceRecord>>("/brapi/v2/references", {
|
||
method: "POST",
|
||
body: JSON.stringify(body),
|
||
});
|
||
invalidateReferenceSetPageCache();
|
||
return mapReference(response.result.data[0]);
|
||
}
|
||
|
||
export async function updateReferenceRow(id: string, payload: ReferencePayload): Promise<ReferenceRecord> {
|
||
const requestedId = optionalText(payload.id);
|
||
if (requestedId && requestedId !== id) {
|
||
throw new Error("Reference ID 不可修改,请新建记录");
|
||
}
|
||
const response = await request<BrapiSingleResponse<ReferenceRecord>>(
|
||
`/brapi/v2/references/${encodeURIComponent(id)}`,
|
||
{
|
||
method: "PUT",
|
||
body: JSON.stringify(buildReferenceWriteBody(payload)),
|
||
},
|
||
);
|
||
invalidateReferenceSetPageCache();
|
||
return mapReference(response.result);
|
||
}
|
||
|
||
export async function deleteReferenceRow(id: string): Promise<void> {
|
||
await request<BrapiSingleResponse<ReferenceRecord>>(
|
||
`/brapi/v2/references/${encodeURIComponent(id)}`,
|
||
{ method: "DELETE" },
|
||
);
|
||
invalidateReferenceSetPageCache();
|
||
}
|
||
|
||
export async function createReferenceBasesRow(payload: ReferenceBasesPayload): Promise<ReferenceBasesRecord> {
|
||
const body = {
|
||
...buildReferenceBasesWriteBody(payload, true),
|
||
...(optionalText(payload.id) ? { referenceBasesDbId: optionalText(payload.id) } : {}),
|
||
};
|
||
const response = await request<BrapiListResponse<ReferenceBasesRecord>>("/brapi/v2/referencebases", {
|
||
method: "POST",
|
||
body: JSON.stringify(body),
|
||
});
|
||
invalidateReferenceSetPageCache();
|
||
return mapReferenceBases(response.result.data[0]);
|
||
}
|
||
|
||
export async function updateReferenceBasesRow(id: string, payload: ReferenceBasesPayload): Promise<ReferenceBasesRecord> {
|
||
const requestedId = optionalText(payload.id);
|
||
if (requestedId && requestedId !== id) {
|
||
throw new Error("ReferenceBases ID 不可修改,请新建记录");
|
||
}
|
||
const response = await request<BrapiSingleResponse<ReferenceBasesRecord>>(
|
||
`/brapi/v2/referencebases/${encodeURIComponent(id)}`,
|
||
{
|
||
method: "PUT",
|
||
body: JSON.stringify(buildReferenceBasesWriteBody(payload, false)),
|
||
},
|
||
);
|
||
invalidateReferenceSetPageCache();
|
||
return mapReferenceBases(response.result);
|
||
}
|
||
|
||
export async function deleteReferenceBasesRow(id: string): Promise<void> {
|
||
await request<BrapiSingleResponse<ReferenceBasesRecord>>(
|
||
`/brapi/v2/referencebases/${encodeURIComponent(id)}`,
|
||
{ method: "DELETE" },
|
||
);
|
||
invalidateReferenceSetPageCache();
|
||
}
|