Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 5x 2x 2x 1x 1x 1x | // Data Access Layer for Cost Calculator config
import type { CalculatorConfig } from "@interioring/utils/calculator";
import { eq, sql } from "drizzle-orm";
import type { DrizzleD1Database } from "drizzle-orm/d1";
import * as schema from "../db/schema";
import type { CalculatorConfigRow } from "../db/schema";
export class CalculatorConfigDal {
constructor(private db: DrizzleD1Database<typeof schema>) {}
async findByKey(key: string): Promise<CalculatorConfigRow | undefined> {
const rows = await this.db
.select()
.from(schema.calculatorConfig)
.where(eq(schema.calculatorConfig.key, key))
.limit(1);
return rows[0];
}
/**
* Race-safe upsert: INSERT OR IGNORE guards against concurrent creates,
* then UPDATE applies the new config + version. D1 has no transactions
* (see CLAUDE.md), so this is two ordered statements.
*/
async upsert(
key: string,
config: CalculatorConfig,
version: number,
): Promise<CalculatorConfigRow> {
await this.db.run(
sql`INSERT OR IGNORE INTO calculator_config (key, config, version, date_updated)
VALUES (${key}, ${JSON.stringify(config)}, ${version}, unixepoch())`,
);
const result = await this.db
.update(schema.calculatorConfig)
.set({ config, version, dateUpdated: new Date() })
.where(eq(schema.calculatorConfig.key, key))
.returning();
return result[0];
}
}
|