upsert with uuid or fail for schema

This commit is contained in:
stfrigerio 2025-04-05 14:52:34 +02:00
parent 0d1bf53ea8
commit cba7bda90a
4 changed files with 24 additions and 15 deletions

View file

@ -1,6 +1,6 @@
//? Expected structure returned by the data service fetch method.
export interface HabitRecord {
value: number;
value: number; //? Service should SELECT 'actual_value_col AS value'
}
//? Base arguments for identifying a habit entry, now includes column names.

View file

@ -9,7 +9,6 @@ export interface HabitCounterUIElements {
/** Updates the text content of the value display. */
export function updateDisplayValue(elements: HabitCounterUIElements, newValue: number | string): void {
//& console.log(`[HabitCounterUI] updateDisplayValue called with: ${newValue}`);
if (elements.valueDisplay) {
elements.valueDisplay.textContent = String(newValue);
} else {
@ -20,7 +19,6 @@ export function updateDisplayValue(elements: HabitCounterUIElements, newValue: n
export function updateStaticUI(elements: HabitCounterUIElements, emoji: string, habitKey: string): void {
if (elements.labelElement) {
const newLabelText = `${emoji} ${habitKey}:`;
console.log(`[HabitCounterUI] DEBUG: Attempting to set label textContent to: "${newLabelText}"`);
elements.labelElement.textContent = newLabelText;
} else {
console.error("[HabitCounterUI] updateStaticUI: labelElement was null.");
@ -35,7 +33,6 @@ export function updateStaticUI(elements: HabitCounterUIElements, emoji: string,
/** Sets the component to visually indicate an error state. */
export function setComponentErrorState(elements: HabitCounterUIElements, message: string = "Error"): void {
//& console.warn(`[HabitCounterUI] setComponentErrorState called with message: "${message}"`);
updateDisplayValue(elements, "ERR");
if (elements.wrapper) {
elements.wrapper.style.borderColor = "var(--text-error)";
@ -46,7 +43,6 @@ export function setComponentErrorState(elements: HabitCounterUIElements, message
/** Clears any visual error indication. */
export function clearComponentErrorState(elements: HabitCounterUIElements): void {
//& console.log(`[HabitCounterUI] clearComponentErrorState called.`);
//? Only reset if actually in error state (check border color)
if (elements.wrapper && elements.wrapper.style.borderColor !== "transparent") {
elements.wrapper.style.borderColor = "transparent";

View file

@ -1,4 +1,3 @@
// src/webcomponents/registration.ts
import { DBService } from "../../DBService";
import { HabitCounter } from "./HabitCounter";
@ -36,7 +35,7 @@ export const registerHabitCounter = (el: HTMLElement, dbService: DBService) => {
const component = document.createElement("habit-counter") as HabitCounter;
//^ Set attributes that the component will read later
component.setAttribute("habit", habitKey); // Set 'habit' attribute
component.setAttribute("habit", habitKey);
component.setAttribute("table", table);
if (date) component.setAttribute("date", date);
else component.setAttribute("date", "@date");

View file

@ -3,6 +3,8 @@ import { HabitRecord, HabitDataArgs, UpdateHabitDataArgs } from "../HabitCounter
import { quoteSqlIdentifier } from "./utils/quoteSqlIdentifier";
import { validateFetchArgs, validateUpdateArgs } from "./utils/validateHabitArgs";
interface UuidResult { uuid: string; }
export class HabitDataService {
private dbService: DBService;
@ -48,15 +50,27 @@ export class HabitDataService {
const safeValueCol = quoteSqlIdentifier(args.valueCol);
const safeDateCol = quoteSqlIdentifier(args.dateCol);
//^ Use specified columns in INSERT, ON CONFLICT target, and UPDATE SET
const sql = `
INSERT INTO ${safeTable} (${safeHabitIdCol}, ${safeDateCol}, ${safeValueCol}) VALUES (?, ?, ?)
ON CONFLICT(${safeHabitIdCol}, ${safeDateCol}) DO UPDATE SET ${safeValueCol} = excluded.${safeValueCol};
`;
//! Requires UNIQUE constraint on the specified (habitIdCol, dateCol)
const params = [args.habitKey, args.date, args.newValue];
//? Attempt to fetch existing UUID
const fetchUuidSql = `SELECT uuid FROM ${safeTable} WHERE ${safeHabitIdCol} = ? AND ${safeDateCol} = ?`;
const fetchUuidParams = [args.habitKey, args.date];
const uuidResult = await this.dbService.getQuery<UuidResult>(fetchUuidSql, fetchUuidParams);
const existingUuid = uuidResult?.[0]?.uuid;
await this.dbService.runQuery(sql, params);
if (existingUuid && typeof existingUuid === 'string') {
const updateSql = `UPDATE ${safeTable} SET ${safeValueCol} = ? WHERE uuid = ?`;
const updateParams = [args.newValue, existingUuid];
await this.dbService.runQuery(updateSql, updateParams);
} else {
//^ Use specified columns in INSERT, ON CONFLICT target, and UPDATE SET without uuid
const sql = `
INSERT INTO ${safeTable} (${safeHabitIdCol}, ${safeDateCol}, ${safeValueCol}) VALUES (?, ?, ?)
ON CONFLICT(${safeHabitIdCol}, ${safeDateCol}) DO UPDATE SET ${safeValueCol} = excluded.${safeValueCol};
`;
//! Requires UNIQUE constraint on the specified (habitIdCol, dateCol)
const params = [args.habitKey, args.date, args.newValue];
await this.dbService.runQuery(sql, params);
}
} catch (error) {
console.error(`[HabitDataService] Error in updateHabitValue for ${args.habitKey}:`, error);