import { query } from "../pool.js"; import type { User } from "./types.js"; export async function countUsers(): Promise { const { rows } = await query<{ count: string }>("SELECT count(*) FROM users"); return Number(rows[0]?.count ?? 0); } export async function findUserByEmail(email: string): Promise { const { rows } = await query( "SELECT * FROM users WHERE lower(email) = lower($1) AND is_active = true", [email], ); return rows[0] ?? null; } export async function findUserById(id: string): Promise { const { rows } = await query("SELECT * FROM users WHERE id = $1", [id]); return rows[0] ?? null; } export interface CreateUserInput { email: string; passwordHash: string; passwordAlgoVersion: number; roleKey: string; fullName?: string; createdBy?: string | null; } export async function createUser(input: CreateUserInput): Promise { const { rows } = await query( `INSERT INTO users (email, password_hash, password_algo_version, role_key, full_name, created_by) VALUES (lower($1), $2, $3, $4, $5, $6) RETURNING *`, [ input.email, input.passwordHash, input.passwordAlgoVersion, input.roleKey, input.fullName ?? null, input.createdBy ?? null, ], ); const user = rows[0]; if (!user) throw new Error("failed to create user"); return user; } export async function updateUserPassword( userId: string, passwordHash: string, passwordAlgoVersion: number, ): Promise { await query("UPDATE users SET password_hash = $1, password_algo_version = $2 WHERE id = $3", [ passwordHash, passwordAlgoVersion, userId, ]); } export async function grantUserApplication( userId: string, applicationKey: "core" | "reseller" | "subscriber", ): Promise { await query( `INSERT INTO user_applications (user_id, application_key) VALUES ($1, $2) ON CONFLICT (user_id, application_key) DO NOTHING`, [userId, applicationKey], ); } export async function getUserApplications(userId: string): Promise { const { rows } = await query<{ application_key: string }>( "SELECT application_key FROM user_applications WHERE user_id = $1", [userId], ); return rows.map((r) => r.application_key); }