Skip to content

Commit 50874a8

Browse files
committed
feat: implement local storage layer and schema
1 parent 01f9766 commit 50874a8

2 files changed

Lines changed: 128 additions & 0 deletions

File tree

src/storage/db.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { ProblemRecord, Settings, SyncLogEntry, RetryQueueItem } from './types';
2+
3+
const SCHEMA_VERSION = 1;
4+
5+
export const DEFAULT_SETTINGS: Settings = {
6+
pat: null,
7+
repository: null,
8+
folderStructure: 'Difficulty',
9+
versionMode: 'versioned',
10+
commitTemplate: "Solved: {title}\nDifficulty: {difficulty}\nLanguage: {language}\nRuntime: {runtime}",
11+
autoSync: true,
12+
readmeEnabled: true,
13+
schemaVersion: SCHEMA_VERSION,
14+
};
15+
16+
export const db = {
17+
async get<T>(key: string): Promise<T | null> {
18+
const result = await chrome.storage.local.get(key);
19+
return result[key] || null;
20+
},
21+
22+
async set<T>(key: string, value: T): Promise<void> {
23+
await chrome.storage.local.set({ [key]: value });
24+
},
25+
26+
async getSettings(): Promise<Settings> {
27+
const settings = await this.get<Settings>('settings');
28+
if (!settings) return DEFAULT_SETTINGS;
29+
30+
// Future migration logic can go here based on settings.schemaVersion
31+
return settings;
32+
},
33+
34+
async updateSettings(partial: Partial<Settings>): Promise<Settings> {
35+
const current = await this.getSettings();
36+
const updated = { ...current, ...partial };
37+
await this.set('settings', updated);
38+
return updated;
39+
},
40+
41+
async getAllProblems(): Promise<ProblemRecord[]> {
42+
const data = await chrome.storage.local.get(null);
43+
const problems: ProblemRecord[] = [];
44+
for (const key in data) {
45+
if (key.startsWith('problems:')) {
46+
problems.push(data[key]);
47+
}
48+
}
49+
return problems;
50+
},
51+
52+
async saveProblem(problem: ProblemRecord): Promise<void> {
53+
await this.set(`problems:${problem.id}:${problem.language}`, problem);
54+
},
55+
56+
async getProblem(id: string, language: string): Promise<ProblemRecord | null> {
57+
return this.get<ProblemRecord>(`problems:${id}:${language}`);
58+
},
59+
60+
async addLogEntry(entry: SyncLogEntry): Promise<void> {
61+
const dateKey = new Date(entry.timestamp).toISOString().split('T')[0];
62+
const logsKey = `log:${dateKey}`;
63+
const logs = (await this.get<SyncLogEntry[]>(logsKey)) || [];
64+
logs.push(entry);
65+
await this.set(logsKey, logs);
66+
},
67+
68+
async getLogs(date: Date): Promise<SyncLogEntry[]> {
69+
const dateKey = date.toISOString().split('T')[0];
70+
return (await this.get<SyncLogEntry[]>(`log:${dateKey}`)) || [];
71+
},
72+
73+
async pushToQueue(item: Omit<RetryQueueItem, 'attempts'>): Promise<void> {
74+
const queue = (await this.get<RetryQueueItem[]>('queue')) || [];
75+
queue.push({ ...item, attempts: 0 });
76+
await this.set('queue', queue);
77+
},
78+
79+
async getQueue(): Promise<RetryQueueItem[]> {
80+
return (await this.get<RetryQueueItem[]>('queue')) || [];
81+
},
82+
83+
async saveQueue(queue: RetryQueueItem[]): Promise<void> {
84+
await this.set('queue', queue);
85+
}
86+
};

src/storage/types.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export interface ProblemRecord {
2+
id: string;
3+
title: string;
4+
difficulty: 'Easy' | 'Medium' | 'Hard';
5+
language: string;
6+
runtime: string;
7+
memory: string;
8+
submissionTime: number;
9+
tags?: string[];
10+
companyTags?: string[];
11+
code: string;
12+
url: string;
13+
version: number;
14+
}
15+
16+
export type FolderStructure = 'Difficulty' | 'Topic' | 'Language' | 'Number' | 'Flat';
17+
18+
export interface Settings {
19+
pat: string | null;
20+
repository: string | null;
21+
folderStructure: FolderStructure;
22+
versionMode: 'versioned' | 'overwrite';
23+
commitTemplate: string;
24+
autoSync: boolean;
25+
readmeEnabled: boolean;
26+
schemaVersion: number;
27+
}
28+
29+
export interface SyncLogEntry {
30+
problemId: string;
31+
title: string;
32+
timestamp: number;
33+
status: 'success' | 'failure' | 'skipped';
34+
reason?: string;
35+
}
36+
37+
export interface RetryQueueItem {
38+
problemId: string;
39+
reason: string;
40+
timestamp: number;
41+
attempts: number;
42+
}

0 commit comments

Comments
 (0)