srs-api/src/services/shops.ts

40 lines
1.5 KiB
TypeScript

import type { Db } from '../db';
import { isUniqueViolation, RuleError } from './accountRules';
import type { Shop } from './shopScope';
export interface ShopListing extends Shop {
active: boolean;
}
export const SHOP_NAME_MAX = 100;
export const SHOP_CODE_MAX = 20;
export function createShop(db: Db, input: { name: string; code: string }): Shop {
const name = input.name.trim();
const code = input.code.trim();
if (name === '' || name.length > SHOP_NAME_MAX) {
throw new RuleError('invalid', `the shop name must be 1 to ${SHOP_NAME_MAX} characters`);
}
if (code === '' || code.length > SHOP_CODE_MAX || /\s/.test(code)) {
throw new RuleError('invalid', `the shop code must be 1 to ${SHOP_CODE_MAX} characters with no spaces`);
}
const sameName = db.prepare('SELECT 1 FROM shops WHERE active = 1 AND lower(name) = lower(?)').get(name);
if (sameName) throw new RuleError('conflict', 'an active shop already has that name');
try {
const id = Number(db.prepare('INSERT INTO shops (name, code) VALUES (?, ?)').run(name, code).lastInsertRowid);
return { id, name, code };
} catch (e) {
if (isUniqueViolation(e)) throw new RuleError('conflict', 'that shop code is already used');
throw e;
}
}
export function listShops(db: Db): ShopListing[] {
const rows = db.prepare('SELECT id, name, code, active FROM shops ORDER BY name, id').all() as Array<
Shop & { active: number }
>;
return rows.map((r) => ({ id: r.id, name: r.name, code: r.code, active: r.active === 1 }));
}