Address PR #227 re-review (comment 2193). - Stability: `updatePageId`/`updateAlias` now `executeTakeFirstOrThrow`, so a row reaped by a concurrent `removeAlias` between the read and the UPDATE (READ COMMITTED) raises `NoResultError` instead of returning `undefined`. The service maps that to a retryable `ConflictException` (`ALIAS_PAGE_RACE`) rather than a 200-without-alias (swap) or a generic 400 from `undefined.id` (rename). Tests cover both branches. - Simplification: drop the redundant secondary "unexpected unique index" warn and the now-unused `UNIQUE_ALIAS_INDEX` const (the constraint name is already logged unconditionally; both index branches still distinguish "Alias already taken" vs ALIAS_PAGE_RACE). - Architecture: extract `isUniqueViolation`/`violatedConstraint` into database/utils.ts; adopt them in the share-alias service and favorite.repo (the bare `23505` check). ai-agent-roles (#222) is on a separate unmerged branch and should adopt them after #227 merges (noted at the helpers). Helper unit test added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
52 lines
1.8 KiB
TypeScript
52 lines
1.8 KiB
TypeScript
import { isUniqueViolation, violatedConstraint } from './utils';
|
|
|
|
/**
|
|
* Unit tests for the driver-bound Postgres unique-violation helpers extracted
|
|
* from the share-alias service (and now shared with favorite.repo). They encode
|
|
* two `kysely-postgres-js` / `postgres@3.x` quirks: the SQLSTATE is the string
|
|
* `'23505'`, and the violated index name arrives as `constraint_name` (with
|
|
* `constraint` only a fallback for other drivers).
|
|
*/
|
|
describe('isUniqueViolation', () => {
|
|
it('is true for a 23505 error', () => {
|
|
expect(isUniqueViolation({ code: '23505' })).toBe(true);
|
|
});
|
|
|
|
it('is false for any other code', () => {
|
|
expect(isUniqueViolation({ code: '08006' })).toBe(false);
|
|
});
|
|
|
|
it('is false when there is no code / not an object', () => {
|
|
expect(isUniqueViolation({})).toBe(false);
|
|
expect(isUniqueViolation(null)).toBe(false);
|
|
expect(isUniqueViolation(undefined)).toBe(false);
|
|
expect(isUniqueViolation(new Error('boom'))).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('violatedConstraint', () => {
|
|
it('reads the postgres@3.x `constraint_name` field', () => {
|
|
expect(
|
|
violatedConstraint({ code: '23505', constraint_name: 'idx_a' }),
|
|
).toBe('idx_a');
|
|
});
|
|
|
|
it('falls back to `constraint` when `constraint_name` is absent', () => {
|
|
expect(violatedConstraint({ code: '23505', constraint: 'idx_b' })).toBe(
|
|
'idx_b',
|
|
);
|
|
});
|
|
|
|
it('prefers `constraint_name` over `constraint` when both are present', () => {
|
|
expect(
|
|
violatedConstraint({ constraint_name: 'idx_a', constraint: 'idx_b' }),
|
|
).toBe('idx_a');
|
|
});
|
|
|
|
it('is undefined when neither field is present', () => {
|
|
expect(violatedConstraint({ code: '23505' })).toBeUndefined();
|
|
expect(violatedConstraint(null)).toBeUndefined();
|
|
expect(violatedConstraint(undefined)).toBeUndefined();
|
|
});
|
|
});
|