Commit da5f8e50 authored by Chunchi Che's avatar Chunchi Che

update sqlite

parent 0d3c3239
Pipeline #23026 failed with stages
in 12 minutes and 38 seconds
import sqliteMiddleWare, { sqliteCmd } from "@/middleware/sqlite";
import { FtsParams } from "@/middleware/sqlite/fts";
export interface CardMeta {
id: number;
......@@ -62,14 +63,10 @@ export async function fetchCard(id: number): Promise<CardMeta> {
* @returns 卡片数据
*
* */
export async function searchCards(
query: string,
type?: number
): Promise<CardMeta[]> {
// TODO: 让type支持多种filter类型
export async function searchCards(params: FtsParams): Promise<CardMeta[]> {
const res = await sqliteMiddleWare({
cmd: sqliteCmd.FTS,
payload: { query, type },
payload: { ftsParams: params },
});
return res.ftsResult ?? [];
}
......
import { Database } from "sql.js";
import { CardData, CardMeta, CardText } from "@/api";
interface FtsConditions {
// 过滤条件
types?: number[]; // 卡片类型
levels?: number[]; // 星阶/刻度/link值
atk?: [number, number]; // 攻击力区间
def?: [number, number]; // 防御力区间
race?: number; // 种族
attribute?: number; // 属性
}
export interface FtsParams {
query: string; // 用于全文检索的query
conditions: FtsConditions; // 过滤条件
}
export function invokeFts(db: Database, params: FtsParams): CardMeta[] {
const { query, conditions } = params;
const ftsTexts: CardText[] = [];
const ftsMetas: CardMeta[] = [];
const textStmt = db.prepare("SELECT * FROM texts WHERE name LIKE $query");
textStmt.bind({ $query: `%${query}%` });
while (textStmt.step()) {
const row = textStmt.getAsObject();
ftsTexts.push(row);
}
for (const text of ftsTexts) {
const id = text.id;
if (id) {
const sql = `SELECT * FROM datas ${getFtsCondtions(conditions)}`;
const dataStmt = db.prepare(sql);
const data: CardData = dataStmt.getAsObject({ $id: id });
ftsMetas.push({ id, data, text });
}
}
return ftsMetas;
}
function getFtsCondtions(conditions: FtsConditions): string {
const { types, levels, atk, def, race, attribute } = conditions;
const typesCondition = types
?.map((type) => `(types & ${type}) > 0`)
.join(" OR ");
const levelsCondition = levels
?.map((level) => `level = ${level}`)
.join(" OR ");
const atkCondition = atk ? `atk BETWEEN ${atk[0]} AND ${atk[1]}` : undefined;
const defCondition = def ? `def BETWEEN ${def[0]} AND ${def[1]}` : undefined;
const raceCondition = race !== undefined ? `race = ${race}` : undefined;
const attributeCondition =
attribute !== undefined ? `attribute = ${attribute}` : undefined;
const merged = [
typesCondition,
levelsCondition,
atkCondition,
defCondition,
raceCondition,
attributeCondition,
]
.filter((condition) => condition !== undefined)
.map((condition) => `(${condition})`)
.join(" AND ");
return merged !== "" ? `WHERE ${merged}` : "";
}
......@@ -11,6 +11,8 @@ import { CardData, CardMeta, CardText } from "@/api/cards";
import { useConfig } from "@/config";
import { pfetch } from "@/infra";
import { FtsParams, invokeFts } from "./fts";
const NeosConfig = useConfig();
export enum sqliteCmd {
......@@ -29,11 +31,9 @@ export interface sqliteAction {
dbUrl: string;
progressCallback?: (progress: number) => void; // 用于获取读取进度
};
// 需要读取卡牌数据的ID
payload?: {
id?: number; // 卡牌ID
query?: string; // 用于全文检索的query
type?: number; // 通过`type`过滤
ftsParams?: FtsParams; // 用于全文检索的参数
};
}
......@@ -89,44 +89,10 @@ export default async function (action: sqliteAction): Promise<sqliteResult> {
return {};
}
case sqliteCmd.FTS: {
if (YGODB && action.payload && action.payload.query) {
// TODO: 这里应该可以优化为联表查询
const query = action.payload.query;
const type = action.payload.type;
const ftsTexts: CardText[] = [];
const ftsMetas: CardMeta[] = [];
const textStmt = YGODB.prepare(
"SELECT * FROM texts WHERE name LIKE $query"
);
textStmt.bind({ $query: `%${query}%` });
while (textStmt.step()) {
const row = textStmt.getAsObject();
ftsTexts.push(row);
}
for (const text of ftsTexts) {
const id = text.id;
if (id && type !== undefined) {
const sql = "SELECT * FROM datas WHERE ID = $id AND type = $type";
const dataStmt = YGODB.prepare(sql);
const data: CardData = dataStmt.getAsObject({
$id: id,
$type: type,
});
ftsMetas.push({ id, data, text });
} else if (id) {
const sql = "SELECT * FROM datas WHERE ID = $id";
const dataStmt = YGODB.prepare(sql);
const data: CardData = dataStmt.getAsObject({ $id: id });
ftsMetas.push({ id, data, text });
}
}
if (YGODB && action.payload && action.payload.ftsParams) {
const metas = invokeFts(YGODB, action.payload.ftsParams);
return { ftsResult: ftsMetas };
return { ftsResult: metas };
} else {
console.warn("ygo db not init or query not provied!");
}
......
import {
DeleteOutlined,
DownloadOutlined,
PlusOutlined,
FileAddOutlined,
PlusOutlined,
} from "@ant-design/icons";
import { Button, Dropdown, MenuProps } from "antd";
......
......@@ -13,10 +13,10 @@ import {
Button,
ConfigProvider,
Input,
Dropdown,
Space,
type ThemeConfig,
} from "antd";
import classNames from "classnames";
import { memo, useEffect, useRef, useState } from "react";
import { DndProvider, useDrag, useDrop } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
......@@ -48,7 +48,6 @@ import {
iDeckToEditingDeck,
type Type,
} from "./utils";
import classNames from "classnames";
const theme: ThemeConfig = {
components: {
......@@ -209,9 +208,9 @@ const Search: React.FC = () => {
const [searchWord, setSearchWord] = useState("");
const [searchResult, setSearchResult] = useState<CardMeta[]>([]);
const handleSearch = async () => {
const result = (await searchCards(searchWord)).filter(
(card) => !isToken(card.data.type ?? 0)
); // 衍生物不显示
const result = (
await searchCards({ query: searchWord, conditions: {} })
).filter((card) => !isToken(card.data.type ?? 0)); // 衍生物不显示
setSearchResult(result);
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment