import assert from 'node:assert/strict'; import test from 'node:test'; import { completePendingBirdTransfersForOwner, createBird, createPendingBirdTransfer, getBirdById, listWeightsForBird, transferBirdToWorkspace, } from './birdRepository.js'; import { mockDb } from '../test/mockDb.js'; test('getBirdById returns null when the bird does not exist in the workspace', async () => { const { calls } = mockDb({ rowCount: 0, rows: [] }); const bird = await getBirdById('bird-1', 10); assert.equal(bird, null); assert.equal(calls.length, 1); assert.deepEqual(calls[0].params, ['bird-1', 10]); }); test('createBird returns the inserted bird row', async () => { mockDb({ rowCount: 1, rows: [ { id: 'bird-1', workspace_id: 10, name: 'Kiwi', tag_id: 'A-1', species: 'Cockatiel', gender: 'female', date_of_birth: null, gotcha_day: null, chart_color: '#cb3a35', photo_data_url: null, notify_on_dob: false, notify_on_gotcha_day: false, created_at: '2026-04-14T00:00:00.000Z', latest_weight_grams: null, latest_recorded_on: null, }, ], }); const bird = await createBird({ workspaceId: 10, name: 'Kiwi', tagId: 'A-1', species: 'Cockatiel', gender: 'female', dateOfBirth: null, gotchaDay: null, chartColor: '#cb3a35', photoDataUrl: null, notifyOnDob: false, notifyOnGotchaDay: false, }); assert.equal(bird?.name, 'Kiwi'); assert.equal(bird?.workspace_id, 10); assert.equal(bird?.gender, 'female'); }); test('listWeightsForBird scopes by bird, workspace, and day window', async () => { const { calls } = mockDb({ rowCount: 0, rows: [], }); const weights = await listWeightsForBird('bird-1', 10, 30); assert.deepEqual(weights, []); assert.equal(calls.length, 1); assert.deepEqual(calls[0].params, ['bird-1', 30, 10]); assert.match(calls[0].text, /FROM weight_records/); }); test('transferBirdToWorkspace moves the bird to the target workspace', async () => { const { calls } = mockDb({ rowCount: 1, rows: [ { id: 'bird-1', workspace_id: 22, name: 'Kiwi', tag_id: 'A-1', species: 'Cockatiel', gender: 'female', date_of_birth: null, gotcha_day: null, chart_color: '#cb3a35', photo_data_url: null, notify_on_dob: false, notify_on_gotcha_day: false, created_at: '2026-04-14T00:00:00.000Z', latest_weight_grams: '92', latest_recorded_on: '2026-04-14', }, ], }); const bird = await transferBirdToWorkspace('bird-1', 10, 22); assert.equal(bird?.workspace_id, 22); assert.deepEqual(calls[0].params, ['bird-1', 10, 22]); assert.match(calls[0].text, /UPDATE birds/); }); test('createPendingBirdTransfer stores an open transfer for auto-completion', async () => { const { calls } = mockDb({ rowCount: 1, rows: [ { id: 'transfer-1', bird_id: 'bird-1', source_workspace_id: 10, destination_owner_email: 'receiver@example.com', requested_by_user_id: 'user-1', completed_at: null, completed_workspace_id: null, last_error: null, created_at: '2026-04-15T00:00:00.000Z', }, ], }); const transfer = await createPendingBirdTransfer({ birdId: 'bird-1', sourceWorkspaceId: 10, destinationOwnerEmail: 'receiver@example.com', requestedByUserId: 'user-1', }); assert.equal(transfer?.id, 'transfer-1'); assert.deepEqual(calls[0].params, ['bird-1', 10, 'receiver@example.com', 'user-1']); assert.match(calls[0].text, /INSERT INTO pending_bird_transfers/); assert.match(calls[0].text, /ON CONFLICT/); }); test('completePendingBirdTransfersForOwner moves pending birds and marks completion', async () => { const { calls } = mockDb( { rowCount: 1, rows: [ { id: 'transfer-1', bird_id: 'bird-1', source_workspace_id: 10, destination_owner_email: 'receiver@example.com', requested_by_user_id: 'user-1', completed_at: null, completed_workspace_id: null, last_error: null, created_at: '2026-04-15T00:00:00.000Z', }, ], }, { rowCount: 1, rows: [ { id: 'bird-1', workspace_id: 22, name: 'Kiwi', tag_id: 'A-1', species: 'Cockatiel', gender: 'female', date_of_birth: null, gotcha_day: null, chart_color: '#cb3a35', photo_data_url: null, notify_on_dob: false, notify_on_gotcha_day: false, created_at: '2026-04-14T00:00:00.000Z', latest_weight_grams: '92', latest_recorded_on: '2026-04-14', }, ], }, { rowCount: 1, rows: [] }, ); const result = await completePendingBirdTransfersForOwner('receiver@example.com', 22); assert.deepEqual(result, { completed: 1, failed: 0 }); assert.deepEqual(calls[0].params, ['receiver@example.com']); assert.deepEqual(calls[1].params, ['bird-1', 10, 22]); assert.deepEqual(calls[2].params, ['transfer-1', 22]); assert.match(calls[2].text, /completed_at = CURRENT_TIMESTAMP/); });