From 07215e56178e13e71b6e413b35faff3065ba3f88 Mon Sep 17 00:00:00 2001 From: dev Date: Mon, 1 Jun 2026 16:22:18 -0500 Subject: [PATCH] feat(store): recordTrain with pruning and getSummary --- src/store.js | 17 ++++++++++++++++- tests/store.test.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/store.js b/src/store.js index d774eab..28cd0f4 100644 --- a/src/store.js +++ b/src/store.js @@ -1,4 +1,4 @@ -import { parseTarget } from './pure.js'; +import { parseTarget, pruneHistory, summary as computeSummary } from './pure.js'; const KEY_TARGETS = 'tat.targets'; const KEY_HISTORY = 'tat.history'; @@ -78,4 +78,19 @@ export class Store { this.prefs.pos = { x: pos.x, y: pos.y }; return this._saveJson(KEY_PREFS, this.prefs); } + + recordTrain(attr, delta, ts = Date.now()) { + if (typeof delta !== 'number' || !Number.isFinite(delta) || delta <= 0) { + return false; + } + const list = this.history[attr] || []; + list.push({ ts, delta }); + this.history[attr] = pruneHistory(list, ts); + return this._saveJson(KEY_HISTORY, this.history); + } + + getSummary(attr, now = Date.now()) { + const list = this.history[attr] || []; + return computeSummary(list, now); + } } diff --git a/tests/store.test.js b/tests/store.test.js index 9d5c982..7016a64 100644 --- a/tests/store.test.js +++ b/tests/store.test.js @@ -1,8 +1,12 @@ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { Store } from '../src/store.js'; +import { MS_PER_DAY } from '../src/pure.js'; import { createLocalStorage } from './localstorage-shim.js'; +const DAY = MS_PER_DAY; +const NOW = 1_700_000_000_000; + function freshStore() { return new Store({ storage: createLocalStorage() }); } @@ -70,3 +74,28 @@ test('Store: latches off further saves after a storage write failure', () => { assert.equal(s.getTarget('strength'), 25_000_000); assert.equal(s.getTarget('speed'), 50_000_000); }); + +test('Store: recordTrain appends to per-attribute history', () => { + const s = freshStore(); + s.recordTrain('strength', 247, NOW); + s.recordTrain('strength', 250, NOW - 1000); + assert.equal(s.history.strength.length, 2); + assert.equal(s.history.strength[0].delta, 247); +}); + +test('Store: recordTrain prunes entries older than 30 days', () => { + const s = freshStore(); + s.recordTrain('strength', 100, NOW - 31 * DAY); + s.recordTrain('strength', 200, NOW); + assert.equal(s.history.strength.length, 1); + assert.equal(s.history.strength[0].delta, 200); +}); + +test('Store: getSummary returns computed summary for attribute', () => { + const s = freshStore(); + s.recordTrain('strength', 247, NOW - 1000); + s.recordTrain('strength', 247, NOW - 2000); + const sum = s.getSummary('strength', NOW); + assert.equal(sum.trainsToday, 2); + assert.equal(sum.perDay, Math.floor((2 / 7) * 247)); +});