From 47d746cf715067d2be4205071b290a96f191dc3a Mon Sep 17 00:00:00 2001 From: Christian Mueller Date: Mon, 6 Apr 2026 12:55:57 +0200 Subject: [PATCH] feat(datapoints): add datapoint manager with CRUD and transform support (Task 6) Co-Authored-By: Claude Sonnet 4.6 --- .../modules/datapoints/datapoint-manager.ts | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 display/middleware/src/modules/datapoints/datapoint-manager.ts diff --git a/display/middleware/src/modules/datapoints/datapoint-manager.ts b/display/middleware/src/modules/datapoints/datapoint-manager.ts new file mode 100644 index 0000000..9061983 --- /dev/null +++ b/display/middleware/src/modules/datapoints/datapoint-manager.ts @@ -0,0 +1,136 @@ +import { getDb } from '../../db/index'; +import { applyTransform, type TransformConfig } from './transforms'; + +export interface Datapoint { + id: number; + name: string; + label: string; + unit: string | null; + value: string | null; + status: string; + source_type: string; + source_id: number; + topic_id: number | null; + query_id: number | null; + transform: string | null; + enabled: number; + updated_at: string; +} + +export interface DatapointUpdate { + label?: string; + unit?: string; + transform?: string | null; + enabled?: number; +} + +export function getAllDatapoints(): Datapoint[] { + const db = getDb(); + return db + .prepare('SELECT * FROM datapoints WHERE enabled = 1') + .all() as Datapoint[]; +} + +export function getDatapointById(id: number): Datapoint | undefined { + const db = getDb(); + return db + .prepare('SELECT * FROM datapoints WHERE id = ?') + .get(id) as Datapoint | undefined; +} + +export function updateDatapointValue(id: number, rawValue: string): Datapoint | undefined { + const db = getDb(); + const dp = db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint | undefined; + if (!dp) return undefined; + + let config: TransformConfig | null = null; + if (dp.transform) { + try { + config = JSON.parse(dp.transform) as TransformConfig; + } catch { + config = null; + } + } + + const transformed = applyTransform(rawValue, config); + + db.run( + `UPDATE datapoints SET value = ?, status = 'ok', updated_at = datetime('now') WHERE id = ?`, + [transformed, id] + ); + + return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint | undefined; +} + +export function updateDatapoint(id: number, data: DatapointUpdate): Datapoint | undefined { + const db = getDb(); + const fields: string[] = []; + const values: unknown[] = []; + + if (data.label !== undefined) { + fields.push('label = ?'); + values.push(data.label); + } + if (data.unit !== undefined) { + fields.push('unit = ?'); + values.push(data.unit); + } + if (data.transform !== undefined) { + fields.push('transform = ?'); + values.push(data.transform); + } + if (data.enabled !== undefined) { + fields.push('enabled = ?'); + values.push(data.enabled); + } + + if (fields.length === 0) return getDatapointById(id); + + values.push(id); + db.run(`UPDATE datapoints SET ${fields.join(', ')} WHERE id = ?`, values); + return getDatapointById(id); +} + +export function createDatapointFromMqtt( + brokerId: number, + topicId: number, + topicPath: string +): Datapoint { + const db = getDb(); + const result = db.run( + `INSERT INTO datapoints (name, label, source_type, source_id, topic_id, enabled) + VALUES (?, ?, 'mqtt', ?, ?, 1)`, + [topicPath, topicPath, brokerId, topicId] + ); + const id = result.lastInsertRowid as number; + return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint; +} + +export function createDatapointFromPg( + sourceId: number, + queryId: number, + queryName: string +): Datapoint { + const db = getDb(); + const result = db.run( + `INSERT INTO datapoints (name, label, source_type, source_id, query_id, enabled) + VALUES (?, ?, 'postgresql', ?, ?, 1)`, + [queryName, queryName, sourceId, queryId] + ); + const id = result.lastInsertRowid as number; + return db.prepare('SELECT * FROM datapoints WHERE id = ?').get(id) as Datapoint; +} + +export function getDatapointByTopicId(topicId: number): Datapoint | undefined { + const db = getDb(); + return db + .prepare('SELECT * FROM datapoints WHERE topic_id = ?') + .get(topicId) as Datapoint | undefined; +} + +export function getDatapointByQueryId(queryId: number): Datapoint | undefined { + const db = getDb(); + return db + .prepare('SELECT * FROM datapoints WHERE query_id = ?') + .get(queryId) as Datapoint | undefined; +}