initial version of streba 2
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { PEAKS } from './peaks-seed';
|
||||
|
||||
const DATA_DIR = process.env.STREBA_DATA_DIR ?? 'data';
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
|
||||
export const db = new Database(path.join(DATA_DIR, 'streba.db'));
|
||||
db.pragma('journal_mode = WAL');
|
||||
db.pragma('foreign_keys = ON');
|
||||
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS activities (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL DEFAULT 'outdoor',
|
||||
date TEXT,
|
||||
distance_m REAL NOT NULL,
|
||||
duration_s REAL,
|
||||
moving_s REAL,
|
||||
elev_gain_m REAL NOT NULL DEFAULT 0,
|
||||
elev_loss_m REAL NOT NULL DEFAULT 0,
|
||||
elev_min_m REAL,
|
||||
elev_max_m REAL,
|
||||
points TEXT NOT NULL,
|
||||
bounds TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS peaks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
elevation_m INTEGER NOT NULL,
|
||||
lat REAL NOT NULL,
|
||||
lon REAL NOT NULL,
|
||||
country TEXT NOT NULL,
|
||||
region TEXT NOT NULL,
|
||||
climbed_at TEXT,
|
||||
activity_id INTEGER REFERENCES activities(id) ON DELETE SET NULL,
|
||||
note TEXT
|
||||
);
|
||||
`);
|
||||
|
||||
const seedPeak = db.prepare(`
|
||||
INSERT OR IGNORE INTO peaks (name, elevation_m, lat, lon, country, region)
|
||||
VALUES (@name, @elevation_m, @lat, @lon, @country, @region)
|
||||
`);
|
||||
db.transaction(() => {
|
||||
for (const peak of PEAKS) seedPeak.run(peak);
|
||||
})();
|
||||
|
||||
export interface ActivityRow {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
date: string | null;
|
||||
distance_m: number;
|
||||
duration_s: number | null;
|
||||
moving_s: number | null;
|
||||
elev_gain_m: number;
|
||||
elev_loss_m: number;
|
||||
elev_min_m: number | null;
|
||||
elev_max_m: number | null;
|
||||
points: string;
|
||||
bounds: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface PeakRow {
|
||||
id: number;
|
||||
name: string;
|
||||
elevation_m: number;
|
||||
lat: number;
|
||||
lon: number;
|
||||
country: string;
|
||||
region: string;
|
||||
climbed_at: string | null;
|
||||
activity_id: number | null;
|
||||
note: string | null;
|
||||
}
|
||||
|
||||
export function listActivities(): Omit<ActivityRow, 'points'>[] {
|
||||
return db
|
||||
.prepare(
|
||||
`SELECT id, name, type, date, distance_m, duration_s, moving_s,
|
||||
elev_gain_m, elev_loss_m, elev_min_m, elev_max_m, bounds, created_at
|
||||
FROM activities ORDER BY date DESC, id DESC`
|
||||
)
|
||||
.all() as Omit<ActivityRow, 'points'>[];
|
||||
}
|
||||
|
||||
export function getActivity(id: number): ActivityRow | undefined {
|
||||
return db.prepare('SELECT * FROM activities WHERE id = ?').get(id) as ActivityRow | undefined;
|
||||
}
|
||||
|
||||
export function deleteActivity(id: number): void {
|
||||
db.prepare('DELETE FROM activities WHERE id = ?').run(id);
|
||||
}
|
||||
|
||||
export function listPeaks(): PeakRow[] {
|
||||
return db.prepare('SELECT * FROM peaks ORDER BY elevation_m DESC').all() as PeakRow[];
|
||||
}
|
||||
|
||||
export function togglePeak(id: number, date?: string): PeakRow | undefined {
|
||||
const peak = db.prepare('SELECT * FROM peaks WHERE id = ?').get(id) as PeakRow | undefined;
|
||||
if (!peak) return undefined;
|
||||
if (peak.climbed_at) {
|
||||
db.prepare('UPDATE peaks SET climbed_at = NULL, activity_id = NULL WHERE id = ?').run(id);
|
||||
} else {
|
||||
db.prepare('UPDATE peaks SET climbed_at = ? WHERE id = ?').run(
|
||||
date ?? new Date().toISOString().slice(0, 10),
|
||||
id
|
||||
);
|
||||
}
|
||||
return db.prepare('SELECT * FROM peaks WHERE id = ?').get(id) as PeakRow;
|
||||
}
|
||||
|
||||
export function markPeakClimbed(peakId: number, activityId: number, date: string | null): void {
|
||||
db.prepare(
|
||||
'UPDATE peaks SET climbed_at = ?, activity_id = ? WHERE id = ? AND climbed_at IS NULL'
|
||||
).run(date ?? new Date().toISOString().slice(0, 10), activityId, peakId);
|
||||
}
|
||||
Reference in New Issue
Block a user