feat(crud): full CRUD for Relation — wire to SQLAlchemy, drop store.py dep
CI / basic-check (push) Has been cancelled
CI / basic-check (push) Has been cancelled
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from uuid import uuid4
|
||||
|
||||
from app.schemas import EntityResponse, ListResponse, Relation
|
||||
from app.services.inventory import get_node_relations
|
||||
from app.services.store import RELATIONS
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.models import NetObjectModel, RelationModel
|
||||
from app.schemas import (
|
||||
EntityResponse, ListResponse, Relation,
|
||||
RelationCreate, RelationUpdate,
|
||||
)
|
||||
from app.services.inventory import _to_relation
|
||||
|
||||
router = APIRouter(prefix='/relations', tags=['relations'])
|
||||
|
||||
@@ -14,24 +23,84 @@ def list_relations(
|
||||
layer: str | None = None,
|
||||
type: str | None = Query(default=None),
|
||||
min_confidence: float | None = None,
|
||||
) -> ListResponse[Relation]:
|
||||
items = RELATIONS
|
||||
status: str | None = None,
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
q = db.query(RelationModel)
|
||||
if source_id:
|
||||
items = [r for r in items if r.source_id == source_id]
|
||||
q = q.filter(RelationModel.source_id == source_id)
|
||||
if target_id:
|
||||
items = [r for r in items if r.target_id == target_id]
|
||||
q = q.filter(RelationModel.target_id == target_id)
|
||||
if layer:
|
||||
items = [r for r in items if r.layer == layer]
|
||||
q = q.filter(RelationModel.layer == layer)
|
||||
if type:
|
||||
items = [r for r in items if r.type == type]
|
||||
q = q.filter(RelationModel.type == type)
|
||||
if min_confidence is not None:
|
||||
items = [r for r in items if r.confidence >= min_confidence]
|
||||
return ListResponse(count=len(items), items=items)
|
||||
q = q.filter(RelationModel.confidence >= min_confidence)
|
||||
if status:
|
||||
q = q.filter(RelationModel.status == status)
|
||||
rows = q.all()
|
||||
return ListResponse(count=len(rows), items=[_to_relation(r) for r in rows])
|
||||
|
||||
|
||||
@router.get('/{relation_id}', response_model=EntityResponse[Relation])
|
||||
def get_relation(relation_id: str) -> EntityResponse[Relation]:
|
||||
for item in RELATIONS:
|
||||
if item.id == relation_id:
|
||||
return EntityResponse(item=item)
|
||||
def get_relation(relation_id: str, db: Session = Depends(get_db)):
|
||||
row = db.query(RelationModel).filter(RelationModel.id == relation_id).first()
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail='Relation not found')
|
||||
return EntityResponse(item=_to_relation(row))
|
||||
|
||||
|
||||
@router.post('', response_model=EntityResponse[Relation], status_code=201)
|
||||
def create_relation(body: RelationCreate, db: Session = Depends(get_db)):
|
||||
for fk, val in [('source_id', body.source_id), ('target_id', body.target_id)]:
|
||||
if not db.query(NetObjectModel).filter(NetObjectModel.id == val).first():
|
||||
raise HTTPException(status_code=422, detail=f'{fk} {val!r} not found')
|
||||
now = datetime.now(timezone.utc)
|
||||
row = RelationModel(
|
||||
id=f'rel_{uuid4().hex[:8]}',
|
||||
type=body.type,
|
||||
layer=body.layer,
|
||||
source_id=body.source_id,
|
||||
target_id=body.target_id,
|
||||
direction=body.direction,
|
||||
source=body.source,
|
||||
confidence=body.confidence,
|
||||
status=body.status,
|
||||
attributes_json=json.dumps(body.attributes),
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
)
|
||||
db.add(row)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return EntityResponse(item=_to_relation(row))
|
||||
|
||||
|
||||
@router.patch('/{relation_id}', response_model=EntityResponse[Relation])
|
||||
def update_relation(relation_id: str, body: RelationUpdate, db: Session = Depends(get_db)):
|
||||
row = db.query(RelationModel).filter(RelationModel.id == relation_id).first()
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail='Relation not found')
|
||||
data = body.model_dump(exclude_unset=True)
|
||||
for fk in ('source_id', 'target_id'):
|
||||
if fk in data and data[fk]:
|
||||
if not db.query(NetObjectModel).filter(NetObjectModel.id == data[fk]).first():
|
||||
raise HTTPException(status_code=422, detail=f'{fk} {data[fk]!r} not found')
|
||||
if 'attributes' in data:
|
||||
data['attributes_json'] = json.dumps(data.pop('attributes'))
|
||||
for field, value in data.items():
|
||||
setattr(row, field, value)
|
||||
row.updated_at = datetime.now(timezone.utc)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
return EntityResponse(item=_to_relation(row))
|
||||
|
||||
|
||||
@router.delete('/{relation_id}', status_code=204)
|
||||
def delete_relation(relation_id: str, db: Session = Depends(get_db)):
|
||||
row = db.query(RelationModel).filter(RelationModel.id == relation_id).first()
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail='Relation not found')
|
||||
db.delete(row)
|
||||
db.commit()
|
||||
|
||||
Reference in New Issue
Block a user