feat(ADM-018): completed feature

This commit is contained in:
chattie
2026-08-17 22:23:10 +02:00
parent cf1c69fc8b
commit d595b4871f
871 changed files with 47411 additions and 281 deletions

View File

@@ -61,6 +61,66 @@ export class PgUserRepository implements UserRepository {
passwordHash: row.password_hash,
};
}
async findById(id: string): Promise<User | undefined> {
const result = await this.pool.query<UserRow>(
`SELECT id, email, role, created_at
FROM identity_users WHERE id = $1`,
[id],
);
const row = result.rows[0];
if (!row) return undefined;
return { id: row.id, email: row.email, role: row.role, createdAt: row.created_at };
}
async listUsers(params?: { limit?: number; offset?: number; role?: string; q?: string }): Promise<{ items: User[]; total: number }> {
const limit = params?.limit ?? 20;
const offset = params?.offset ?? 0;
const conditions: string[] = [];
const values: unknown[] = [];
let i = 1;
if (params?.role) { conditions.push(`role = $${i++}`); values.push(params.role); }
if (params?.q) { conditions.push(`(email ILIKE $${i++} OR role ILIKE $${i++})`); values.push(`%${params.q}%`); values.push(`%${params.q}%`); }
const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
const countResult = await this.pool.query<{ count: string }>(
`SELECT COUNT(*) FROM identity_users ${where}`,
values,
);
const total = parseInt(countResult.rows[0]?.count ?? '0', 10);
const rows = await this.pool.query<UserRow>(
`SELECT id, email, role, created_at FROM identity_users ${where} ORDER BY created_at DESC LIMIT $${i++} OFFSET $${i}`,
[...values, limit, offset],
);
return {
items: rows.rows.map((r) => ({ id: r.id, email: r.email, role: r.role, createdAt: r.created_at })),
total,
};
}
async updateUser(id: string, patch: { role?: string; passwordHash?: string }): Promise<User> {
const sets: string[] = [];
const values: unknown[] = [];
let i = 1;
if (patch.role) { sets.push(`role = $${i++}`); values.push(patch.role); }
if (patch.passwordHash) { sets.push(`password_hash = $${i++}`); values.push(patch.passwordHash); }
if (!sets.length) {
const existing = await this.findById(id);
if (!existing) throw new Error('User not found');
return existing;
}
values.push(id);
const result = await this.pool.query<UserRow>(
`UPDATE identity_users SET ${sets.join(', ')} WHERE id = $${i} RETURNING id, email, role, created_at`,
values,
);
const row = result.rows[0];
if (!row) throw new Error('User not found');
return { id: row.id, email: row.email, role: row.role, createdAt: row.created_at };
}
async deleteUser(id: string): Promise<void> {
await this.pool.query(`DELETE FROM identity_users WHERE id = $1`, [id]);
}
}
function isPgError(error: unknown): error is { code: string } {