import { doublePrecision, integer, text } from 'drizzle-orm/pg-core'; import { animaldexSchema } from './schemas'; import { id, timestamps, timestamptz } from './helpers'; export const animals = animaldexSchema.table('animals', { id: id(), species: text('species').notNull(), breed: text('breed'), animalName: text('animal_name'), description: text('description'), // AI detection stored on the animal (from the first/primary photo) aiBreedSuggestion: text('ai_breed_suggestion'), aiBreedConfidence: doublePrecision('ai_breed_confidence'), // Moderation — the animal entity is moderated once. // Accepted = visible on map (as long as it has accepted sightings too). // Denied animals are hidden but not deleted. submittedAt: timestamptz('submitted_at').notNull().defaultNow(), acceptedAt: timestamptz('accepted_at'), deniedAt: timestamptz('denied_at'), ...timestamps }); export const sightings = animaldexSchema.table('sightings', { id: id(), animalId: integer('animal_id') .notNull() .references(() => animals.id, { onDelete: 'cascade' }), reporterName: text('reporter_name'), seenAt: timestamptz('seen_at').notNull(), lat: doublePrecision('lat').notNull(), lng: doublePrecision('lng').notNull(), submittedAt: timestamptz('submitted_at').notNull().defaultNow(), acceptedAt: timestamptz('accepted_at'), deniedAt: timestamptz('denied_at'), ...timestamps }); export const photos = animaldexSchema.table('sighting_photos', { id: id(), sightingId: integer('sighting_id') .notNull() .references(() => sightings.id, { onDelete: 'cascade' }), r2Key: text('r2_key').notNull(), url: text('url').notNull(), sortOrder: integer('sort_order').notNull().default(0), uploadedAt: timestamptz('uploaded_at').notNull().defaultNow(), ...timestamps }); export type Animal = typeof animals.$inferSelect; export type NewAnimal = typeof animals.$inferInsert; export type Sighting = typeof sightings.$inferSelect; export type NewSighting = typeof sightings.$inferInsert; export type Photo = typeof photos.$inferSelect; export type ModerationStatus = 'pending' | 'accepted' | 'denied'; export function getModerationStatus( row: Pick ): ModerationStatus { if (row.deniedAt) return 'denied'; if (row.acceptedAt) return 'accepted'; return 'pending'; }