Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCS-31 persist critical settings in database #14

Merged
merged 2 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src-tauri/migrations/2023-10-06-205928_init/down.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
-- This file should undo anything in `up.sql`
drop table if exists studies;
drop table if exists chapters;
drop table if exists lines;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
drop table if exists settings;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
create table if not exists settings (
key text not null,
value text not null,
primary key (key)
);
48 changes: 30 additions & 18 deletions src/composables/useGameTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,15 @@ export function useGameTree() {
const root = ref<PositionNode>();
const activeNode = ref<PositionNode>();

function addNode(fen: string, options?: AddMoveOptions): PositionNode {
/**
* Add a new node to the tree
*
* @param fen FEN string of the position
* @param options Options for the move
* @param force force move to be added, even if it already exists on current node
* @returns newly added node
*/
function addNode(fen: string, options?: AddMoveOptions, force: boolean = false): PositionNode {
const nodeId = window.crypto.randomUUID();
const newNode: PositionNode = {
id: nodeId,
Expand All @@ -63,7 +71,7 @@ export function useGameTree() {
if (!root.value) root.value = newNode;
if (activeNode.value) {
// check if move node exists in tree
if (activeNode.value.nextPosition && activeNode.value.nextPosition.move?.san === newNode.move?.san) {
if (activeNode.value.nextPosition && activeNode.value.nextPosition.move?.san === newNode.move?.san && !force) {
setActiveNode(activeNode.value.nextPosition);
return newNode;
} else if (activeNode.value.variations.length) {
Expand Down Expand Up @@ -145,25 +153,29 @@ export function useGameTree() {
const isNullMove = child.data.san === "--";
const move = parseSan(position, child.data.san) as NormalMove | undefined;
if ((!isNullMove && !move) || (isNullMove && !previousMove)) return; //illegal move
if (!isNullMove) position.play(move);
if (!isNullMove) position.play(move!);
const fen = makeFen(position.toSetup());
const node = addNode(fen, {
move: {
source: isNullMove ? makeSquare(previousMove!.from) : makeSquare(move!.from),
destination: isNullMove ? makeSquare(previousMove!.to) : makeSquare(move!.to),
san: child.data.san,
isCapture: child.data.san.includes("x"),
isCheck: child.data.san.includes("+"),
piece: {
role: isNullMove ? pos.board.getRole(previousMove!.from)! : pos.board.getRole(move!.from)!,
color: pos.turn,
promoted: isNullMove ? !!previousMove!.promotion : !!move!.promotion,
const node = addNode(
fen,
{
move: {
source: isNullMove ? makeSquare(previousMove!.from) : makeSquare(move!.from),
destination: isNullMove ? makeSquare(previousMove!.to) : makeSquare(move!.to),
san: child.data.san,
isCapture: child.data.san.includes("x"),
isCheck: child.data.san.includes("+"),
piece: {
role: isNullMove ? pos.board.getRole(previousMove!.from)! : pos.board.getRole(move!.from)!,
color: pos.turn,
promoted: isNullMove ? !!previousMove!.promotion : !!move!.promotion,
},
annotations: child.data.nags,
},
annotations: child.data.nags,
comment: child.data.comments && formatComment(child.data.comments.join("")),
startingComment: child.data.startingComments && formatComment(child.data.startingComments.join("")),
},
comment: child.data.comments && formatComment(child.data.comments.join("")),
startingComment: child.data.startingComments && formatComment(child.data.startingComments.join("")),
});
true
);

setActiveNode(node!);
if (child.children.length === 0) return;
Expand Down
31 changes: 31 additions & 0 deletions src/composables/useSetting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { db, execute, selectFirst } from "@services/database";
import { StorageLikeAsync, useStorageAsync } from "@vueuse/core";

export function useSetting(key: string, initialValue: string) {
const getItem = async (key: string) => {
const query = db.selectFrom("settings").select("value").where("key", "=", key).compile();
return (await selectFirst(query))?.value ?? null;
};

const setItem = async (key: string, value: string) => {
const query = db
.insertInto("settings")
.values({ key, value })
.onConflict((oc) => oc.column("key").doUpdateSet({ value: value }))
.compile();
await execute(query);
};

const removeItem = async (key: string) => {
const query = db.deleteFrom("settings").where("key", "=", key).compile();
await execute(query);
};

const storage: StorageLikeAsync = {
getItem,
setItem,
removeItem,
};

return useStorageAsync(key, initialValue, storage);
}
28 changes: 14 additions & 14 deletions src/database.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,45 @@ export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
: ColumnType<T, T | undefined, T>;

export interface Chapters {
id: Generated<number>;
created_at: Generated<string>;
study: number;
id: number;
name: string;
study: number;
}

export interface Lines {
id: Generated<number>;
chapter: number;
created_at: Generated<string>;
id: number;
moves: string;
name: string;
orientation: Generated<string>;
pgn: string;
chapter: number;
moves: string;
study: number;
orientation: Generated<string>;
}

export interface Positions {
id: Generated<number>;
chapter: number | null;
created_at: Generated<string>;
destination: Generated<string>;
fen: string;
study: number | null;
chapter: number | null;
id: number;
line: number | null;
san: string;
source: Generated<string>;
destination: Generated<string>;
study: number | null;
}

export interface Settings {
setting_key: string;
setting_value: string;
key: string;
value: string;
}

export interface Studies {
id: Generated<number>;
created_at: Generated<string>;
name: string;
description: string | null;
id: number;
name: string;
}

export interface DB {
Expand Down
7 changes: 2 additions & 5 deletions src/pages/settings/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
name="token"
class="flex-grow"
label="Personal API Access Token"
v-model.trim="lichessToken"
v-model.trim="lichess.personalAccessToken"
:schema="lichessTokenSchema"
:async-schema="lichessTokenAsyncSchema"
/>
Expand All @@ -40,7 +40,7 @@
id="chessdotcom-username"
name="chessdotcom-username"
class="flex-grow"
v-model.trim="chessdotcomUsername"
v-model.trim="chessdotcom.username"
:schema="chessdotcomUsernameSchema"
:async-schema="chessdotcomUsernameAsyncSchema"
/>
Expand Down Expand Up @@ -68,7 +68,6 @@ import { useBreadcrumbs } from "@stores/useBreadcrumbs";
import { useChessDotCom } from "@stores/useChessDotCom";
import { useLichess } from "@stores/useLichess";
import { open } from "@tauri-apps/api/shell";
import { ref } from "vue";
import { definePage } from "vue-router/auto";
import { z } from "zod";

Expand All @@ -88,7 +87,6 @@ setBreadcrumbs([
]);

const lichess = useLichess();
const lichessToken = ref(lichess.personalAccessToken);
const lichessTokenSchema = z
.string()
.min(1)
Expand All @@ -101,7 +99,6 @@ const lichessTokenAsyncSchema = z.string().refine(
);

const chessdotcom = useChessDotCom();
const chessdotcomUsername = ref(chessdotcom.username);
const chessdotcomUsernameSchema = z
.string()
.min(1)
Expand Down
9 changes: 7 additions & 2 deletions src/services/lichess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ interface ExportGameByIdQueryParameters {
export type LichessGame = z.infer<typeof GameSchema>;
export type MasterGameCollection = z.infer<typeof MasterGamesSchema>;

export function LichessClient(personalAccessToken: string) {
export function LichessClient(token: string) {
let personalAccessToken = token;
function setPersonalAccessToken(newToken: string) {
personalAccessToken = newToken;
}

/**
* @see https://lichess.org/api#tag/Games/operation/apiGamesUser
*/
Expand Down Expand Up @@ -172,7 +177,7 @@ export function LichessClient(personalAccessToken: string) {
}

return {
personalAccessToken,
setPersonalAccessToken,
exportGamesByUser,
exportGameById,
getCurrentAccount,
Expand Down
4 changes: 2 additions & 2 deletions src/stores/useChessDotCom.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useSetting } from "@composables/useSetting";
import { ChessDotComClient } from "@services/chessdotcom";
import { useLocalStorage } from "@vueuse/core";
import { defineStore } from "pinia";

export const useChessDotCom = defineStore("chessDotCom", () => {
const client = ChessDotComClient();
const username = useLocalStorage("chessdotcomUsername", "");
const username = useSetting("chessdotcomUsername", "");

async function validateAndSetUsername(player: string) {
const response = await client.getPlayer(player);
Expand Down
12 changes: 6 additions & 6 deletions src/stores/useLichess.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { useSetting } from "@composables/useSetting";
import { LichessClient } from "@services/lichess";
import { useLocalStorage } from "@vueuse/core";
import { defineStore } from "pinia";

export const useLichess = defineStore("lichess", () => {
const personalAccessToken = useLocalStorage("lichessToken", "");
const username = useLocalStorage("lichessUsername", "");
const personalAccessToken = useSetting("lichessToken", "");
const username = useSetting("lichessUsername", "");
const client = LichessClient(personalAccessToken.value);

async function validateAndSetPersonalAccessToken(token: string) {
client.personalAccessToken = token;
client.setPersonalAccessToken(token);
const response = await client.getCurrentAccount();
if (response.error) {
// reset token to previous one
username.value = response.username;
client.personalAccessToken = personalAccessToken.value;
client.setPersonalAccessToken(personalAccessToken.value);
return false;
}

username.value = response.username;
client.personalAccessToken = token;
client.setPersonalAccessToken(token);
personalAccessToken.value = token;
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions src/utilities/comment.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe("formatComment", () => {
expect(formatComment("b7-b5")).toBe("<b>b7</b>-<b>b5</b>");
expect(formatComment("0-0")).toBe("<b>0-0</b>");
expect(formatComment("0-0-0")).toBe("<b>0-0-0</b>");
// expect(formatComment("O-O")).toBe("<b>O-O</b>");
// expect(formatComment("O-O-O")).toBe("<b>O-O-O</b>");
expect(formatComment("O-O")).toBe("<b>O-O</b>");
expect(formatComment("O-O-O")).toBe("<b>O-O-O</b>");
});
});
3 changes: 2 additions & 1 deletion src/utilities/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export function formatComment(comment: string) {
const fenPattern = /@@StartFEN@@[^@]+?@@EndFEN@@/g;
comment_ = comment_.replaceAll(fenPattern, "");
// highlight chess moves
const chessMovePattern = /(([\d]{0,3}\.)?(\.{2,3})?[KQBNRP]?[a-h]?[1-8]?[x]?[a-h][1-8](=[NBRQK])?[+#]?)|0-0(-0)?/g;
const chessMovePattern =
/(([\d]{0,3}\.)?(\.{2,3})?[KQBNRP]?[a-h]?[1-8]?[x]?[a-h][1-8](=[NBRQK])?[+#]?|[0O]-[0O](-[0O])?)/g;
comment_ = comment_.replace(chessMovePattern, "<b>$1</b>");
comment_ = comment_.trim();

Expand Down
Loading