added full api
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
import { db } from '../db/client.js';
|
||||
import type { BirdRow, VetVisitRow, WeightRow } from '../types.js';
|
||||
|
||||
const birdSelectFields = `
|
||||
birds.id,
|
||||
birds.workspace_id,
|
||||
birds.name,
|
||||
birds.tag_id,
|
||||
birds.species,
|
||||
birds.date_of_birth::text,
|
||||
birds.gotcha_day::text,
|
||||
birds.chart_color,
|
||||
birds.photo_data_url,
|
||||
birds.notify_on_dob,
|
||||
birds.notify_on_gotcha_day,
|
||||
birds.created_at,
|
||||
latest.weight_grams AS latest_weight_grams,
|
||||
latest.recorded_on::text AS latest_recorded_on
|
||||
`;
|
||||
|
||||
export const getBirdById = async (birdId: string, workspaceId: number) => {
|
||||
const result = await db.query<BirdRow>(
|
||||
`SELECT
|
||||
${birdSelectFields}
|
||||
FROM birds
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT weight_grams, recorded_on
|
||||
FROM weight_records
|
||||
WHERE weight_records.bird_id = birds.id
|
||||
ORDER BY recorded_on DESC
|
||||
LIMIT 1
|
||||
) latest ON TRUE
|
||||
WHERE birds.id = $1
|
||||
AND birds.workspace_id = $2`,
|
||||
[birdId, workspaceId],
|
||||
);
|
||||
|
||||
return result.rows[0] ?? null;
|
||||
};
|
||||
|
||||
export const listBirds = async (workspaceId: number) => {
|
||||
const result = await db.query<BirdRow>(
|
||||
`SELECT
|
||||
${birdSelectFields}
|
||||
FROM birds
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT weight_grams, recorded_on
|
||||
FROM weight_records
|
||||
WHERE weight_records.bird_id = birds.id
|
||||
ORDER BY recorded_on DESC
|
||||
LIMIT 1
|
||||
) latest ON TRUE
|
||||
WHERE birds.workspace_id = $1
|
||||
ORDER BY birds.name ASC`,
|
||||
[workspaceId],
|
||||
);
|
||||
|
||||
return result.rows;
|
||||
};
|
||||
|
||||
export const createBird = async ({
|
||||
workspaceId,
|
||||
name,
|
||||
tagId,
|
||||
species,
|
||||
dateOfBirth,
|
||||
gotchaDay,
|
||||
chartColor,
|
||||
photoDataUrl,
|
||||
notifyOnDob,
|
||||
notifyOnGotchaDay,
|
||||
}: {
|
||||
workspaceId: number;
|
||||
name: string;
|
||||
tagId: string;
|
||||
species: string;
|
||||
dateOfBirth: string | null;
|
||||
gotchaDay: string | null;
|
||||
chartColor: string;
|
||||
photoDataUrl: string | null;
|
||||
notifyOnDob: boolean;
|
||||
notifyOnGotchaDay: boolean;
|
||||
}) => {
|
||||
const result = await db.query<BirdRow>(
|
||||
`INSERT INTO birds (workspace_id, name, tag_id, species, date_of_birth, gotcha_day, chart_color, photo_data_url, notify_on_dob, notify_on_gotcha_day)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
RETURNING id, workspace_id, name, tag_id, species, date_of_birth::text, gotcha_day::text, chart_color, photo_data_url, notify_on_dob, notify_on_gotcha_day, created_at, NULL::text AS latest_weight_grams, NULL::text AS latest_recorded_on`,
|
||||
[workspaceId, name, tagId, species, dateOfBirth, gotchaDay, chartColor, photoDataUrl, notifyOnDob, notifyOnGotchaDay],
|
||||
);
|
||||
|
||||
return result.rows[0] ?? null;
|
||||
};
|
||||
|
||||
export const updateBird = async ({
|
||||
birdId,
|
||||
workspaceId,
|
||||
name,
|
||||
tagId,
|
||||
species,
|
||||
dateOfBirth,
|
||||
gotchaDay,
|
||||
chartColor,
|
||||
photoDataUrl,
|
||||
notifyOnDob,
|
||||
notifyOnGotchaDay,
|
||||
}: {
|
||||
birdId: string;
|
||||
workspaceId: number;
|
||||
name: string;
|
||||
tagId: string;
|
||||
species: string;
|
||||
dateOfBirth: string | null;
|
||||
gotchaDay: string | null;
|
||||
chartColor: string;
|
||||
photoDataUrl: string | null;
|
||||
notifyOnDob: boolean;
|
||||
notifyOnGotchaDay: boolean;
|
||||
}) => {
|
||||
const result = await db.query<BirdRow>(
|
||||
`UPDATE birds
|
||||
SET name = $2,
|
||||
tag_id = $3,
|
||||
species = $4,
|
||||
date_of_birth = $5,
|
||||
gotcha_day = $6,
|
||||
chart_color = $7,
|
||||
photo_data_url = $8,
|
||||
notify_on_dob = $9,
|
||||
notify_on_gotcha_day = $10
|
||||
WHERE id = $1
|
||||
AND workspace_id = $11
|
||||
RETURNING id, workspace_id, name, tag_id, species, date_of_birth::text, gotcha_day::text, chart_color, photo_data_url, notify_on_dob, notify_on_gotcha_day, created_at,
|
||||
(
|
||||
SELECT weight_grams::text
|
||||
FROM weight_records
|
||||
WHERE bird_id = birds.id
|
||||
ORDER BY recorded_on DESC
|
||||
LIMIT 1
|
||||
) AS latest_weight_grams,
|
||||
(
|
||||
SELECT recorded_on::text
|
||||
FROM weight_records
|
||||
WHERE bird_id = birds.id
|
||||
ORDER BY recorded_on DESC
|
||||
LIMIT 1
|
||||
) AS latest_recorded_on`,
|
||||
[birdId, name, tagId, species, dateOfBirth, gotchaDay, chartColor, photoDataUrl, notifyOnDob, notifyOnGotchaDay, workspaceId],
|
||||
);
|
||||
|
||||
return result.rows[0] ?? null;
|
||||
};
|
||||
|
||||
export const deleteBird = async (birdId: string, workspaceId: number) => {
|
||||
const result = await db.query<{ id: string }>(
|
||||
`DELETE FROM birds
|
||||
WHERE id = $1
|
||||
AND workspace_id = $2
|
||||
RETURNING id`,
|
||||
[birdId, workspaceId],
|
||||
);
|
||||
|
||||
return Boolean(result.rowCount);
|
||||
};
|
||||
|
||||
export const listWeightsForBird = async (birdId: string, workspaceId: number, days: number) => {
|
||||
const result = await db.query<WeightRow>(
|
||||
`SELECT id, bird_id, weight_grams, recorded_on::text, notes
|
||||
FROM weight_records
|
||||
WHERE bird_id = $1
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM birds
|
||||
WHERE birds.id = weight_records.bird_id
|
||||
AND birds.workspace_id = $3
|
||||
)
|
||||
AND recorded_on >= CURRENT_DATE - (($2::int - 1) * INTERVAL '1 day')
|
||||
ORDER BY recorded_on ASC`,
|
||||
[birdId, days, workspaceId],
|
||||
);
|
||||
|
||||
return result.rows;
|
||||
};
|
||||
|
||||
export const createWeightForBird = async (birdId: string, weightGrams: number, recordedOn: string, notes: string | null) => {
|
||||
const result = await db.query<WeightRow>(
|
||||
`INSERT INTO weight_records (bird_id, weight_grams, recorded_on, notes)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, bird_id, weight_grams, recorded_on::text, notes`,
|
||||
[birdId, weightGrams, recordedOn, notes],
|
||||
);
|
||||
|
||||
return result.rows[0] ?? null;
|
||||
};
|
||||
|
||||
export const listVetVisitsForBird = async (birdId: string, workspaceId: number) => {
|
||||
const result = await db.query<VetVisitRow>(
|
||||
`SELECT id, bird_id, visited_on::text, clinic_name, reason, notes
|
||||
FROM vet_visits
|
||||
WHERE bird_id = $1
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM birds
|
||||
WHERE birds.id = vet_visits.bird_id
|
||||
AND birds.workspace_id = $2
|
||||
)
|
||||
ORDER BY visited_on DESC, created_at DESC`,
|
||||
[birdId, workspaceId],
|
||||
);
|
||||
|
||||
return result.rows;
|
||||
};
|
||||
|
||||
export const createVetVisitForBird = async (birdId: string, visitedOn: string, clinicName: string, reason: string, notes: string | null) => {
|
||||
const result = await db.query<VetVisitRow>(
|
||||
`INSERT INTO vet_visits (bird_id, visited_on, clinic_name, reason, notes)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, bird_id, visited_on::text, clinic_name, reason, notes`,
|
||||
[birdId, visitedOn, clinicName, reason, notes],
|
||||
);
|
||||
|
||||
return result.rows[0] ?? null;
|
||||
};
|
||||
Reference in New Issue
Block a user