From ea092bca1028b3e4e3b3466a3f2739e327867b6d Mon Sep 17 00:00:00 2001 From: "Aaron D. Lee" Date: Fri, 3 Apr 2026 13:11:01 -0400 Subject: [PATCH] Add pets, pet_sightings, wildlife_sightings, pet_training_images tables Co-Authored-By: Claude Sonnet 4.6 --- tests/unit/test_schema.py | 51 +++++++++++++++++++++++++++++++++++- vigilar/storage/schema.py | 55 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_schema.py b/tests/unit/test_schema.py index 8f492aa..11a6d48 100644 --- a/tests/unit/test_schema.py +++ b/tests/unit/test_schema.py @@ -2,7 +2,7 @@ from sqlalchemy import create_engine, inspect -from vigilar.storage.schema import metadata +from vigilar.storage.schema import metadata, pets, pet_sightings, wildlife_sightings, pet_training_images def test_tables_created(tmp_path): @@ -21,3 +21,52 @@ def test_tables_created(tmp_path): ] for name in expected: assert name in table_names, f"Missing table: {name}" + + +class TestPetTables: + def test_pets_table_exists(self, test_db): + with test_db.connect() as conn: + result = conn.execute(pets.insert().values( + id="pet-1", name="Angel", species="cat", breed="DSH", + color_description="black", training_count=0, created_at=1000.0, + )) + row = conn.execute(pets.select().where(pets.c.id == "pet-1")).first() + assert row is not None + assert row.name == "Angel" + assert row.species == "cat" + + def test_pet_sightings_table(self, test_db): + with test_db.begin() as conn: + conn.execute(pets.insert().values( + id="pet-1", name="Angel", species="cat", training_count=0, created_at=1000.0, + )) + conn.execute(pet_sightings.insert().values( + ts=1000.0, pet_id="pet-1", species="cat", camera_id="kitchen", + confidence=0.92, labeled=True, + )) + rows = conn.execute(pet_sightings.select()).fetchall() + assert len(rows) == 1 + assert rows[0].camera_id == "kitchen" + + def test_wildlife_sightings_table(self, test_db): + with test_db.begin() as conn: + conn.execute(wildlife_sightings.insert().values( + ts=1000.0, species="bear", threat_level="PREDATOR", + camera_id="front", confidence=0.88, + )) + rows = conn.execute(wildlife_sightings.select()).fetchall() + assert len(rows) == 1 + assert rows[0].threat_level == "PREDATOR" + + def test_pet_training_images_table(self, test_db): + with test_db.begin() as conn: + conn.execute(pets.insert().values( + id="pet-1", name="Angel", species="cat", training_count=0, created_at=1000.0, + )) + conn.execute(pet_training_images.insert().values( + pet_id="pet-1", image_path="/var/vigilar/pets/training/angel/001.jpg", + source="upload", created_at=1000.0, + )) + rows = conn.execute(pet_training_images.select()).fetchall() + assert len(rows) == 1 + assert rows[0].source == "upload" diff --git a/vigilar/storage/schema.py b/vigilar/storage/schema.py index b63fec0..410af24 100644 --- a/vigilar/storage/schema.py +++ b/vigilar/storage/schema.py @@ -123,3 +123,58 @@ push_subscriptions = Table( Column("last_used_at", Integer), Column("user_agent", String), ) + +pets = Table( + "pets", + metadata, + Column("id", String, primary_key=True), + Column("name", String, nullable=False), + Column("species", String, nullable=False), + Column("breed", String), + Column("color_description", String), + Column("photo_path", String), + Column("training_count", Integer, nullable=False, default=0), + Column("created_at", Float, nullable=False), +) + +pet_sightings = Table( + "pet_sightings", + metadata, + Column("id", Integer, primary_key=True, autoincrement=True), + Column("ts", Float, nullable=False), + Column("pet_id", String), + Column("species", String, nullable=False), + Column("camera_id", String, nullable=False), + Column("confidence", Float), + Column("crop_path", String), + Column("labeled", Integer, nullable=False, default=0), + Column("event_id", Integer), +) +Index("idx_pet_sightings_ts", pet_sightings.c.ts.desc()) +Index("idx_pet_sightings_pet", pet_sightings.c.pet_id, pet_sightings.c.ts.desc()) +Index("idx_pet_sightings_camera", pet_sightings.c.camera_id, pet_sightings.c.ts.desc()) + +wildlife_sightings = Table( + "wildlife_sightings", + metadata, + Column("id", Integer, primary_key=True, autoincrement=True), + Column("ts", Float, nullable=False), + Column("species", String, nullable=False), + Column("threat_level", String, nullable=False), + Column("camera_id", String, nullable=False), + Column("confidence", Float), + Column("crop_path", String), + Column("event_id", Integer), +) +Index("idx_wildlife_ts", wildlife_sightings.c.ts.desc()) +Index("idx_wildlife_threat", wildlife_sightings.c.threat_level, wildlife_sightings.c.ts.desc()) + +pet_training_images = Table( + "pet_training_images", + metadata, + Column("id", Integer, primary_key=True, autoincrement=True), + Column("pet_id", String, nullable=False), + Column("image_path", String, nullable=False), + Column("source", String, nullable=False), + Column("created_at", Float, nullable=False), +)