Skip to content
This repository was archived by the owner on Feb 22, 2026. It is now read-only.

Commit 0b80967

Browse files
authored
Merge pull request #547 from palit-pratyush/GET/deployed-contracts-endpoints
Implemented GET/deployed-contracts-endpoints
2 parents 2fcd5e7 + fba9896 commit 0b80967

File tree

5 files changed

+135
-2
lines changed

5 files changed

+135
-2
lines changed

py-be/app/api/routes.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
from datetime import datetime
44

55
from fastapi import Depends, FastAPI, HTTPException, status
6-
from pydantic import BaseModel, ConfigDict, constr, field_validator
6+
from pydantic import BaseModel, ConfigDict, Field, constr, field_validator
77
from sqlalchemy import or_
88
from sqlalchemy.orm import Session
99

1010
from ..models.base import init_db
11+
from ..models.deployed_contract import DeployedContract
1112
from ..models.generated_contract import GeneratedContract
1213
from ..models.user import User
1314
from ..services.base import get_db
@@ -92,6 +93,18 @@ class GeneratedContractRead(BaseModel):
9293
updated_at: datetime
9394

9495

96+
class DeployedContractRead(BaseModel):
97+
"""Schema returned for deployed contracts."""
98+
99+
model_config = ConfigDict(from_attributes=True, populate_by_name=True)
100+
101+
id: int
102+
contract_name: str
103+
contract_address: str
104+
metadata: dict | None = Field(None, alias="contract_metadata")
105+
deployed_at: datetime
106+
107+
95108
@app.post(
96109
"/generate",
97110
response_model=GeneratedContractRead,
@@ -149,3 +162,39 @@ def generate_contract(
149162
db.commit()
150163
db.refresh(contract)
151164
return contract
165+
166+
167+
@app.get(
168+
"/deployed_contracts",
169+
response_model=list[DeployedContractRead],
170+
status_code=status.HTTP_200_OK,
171+
)
172+
def get_deployed_contracts(
173+
name: str | None = None,
174+
sort_by: str = "deployed_at",
175+
order: str = "desc",
176+
db: Session = Depends(get_db),
177+
) -> list[DeployedContract]:
178+
"""Retrieve deployed contracts with optional filtering and sorting."""
179+
180+
valid_sort = {
181+
"deployed_at": DeployedContract.deployed_at,
182+
"contract_name": DeployedContract.contract_name,
183+
}
184+
if sort_by not in valid_sort:
185+
raise HTTPException(
186+
status_code=status.HTTP_400_BAD_REQUEST,
187+
detail="Invalid sort_by field",
188+
)
189+
190+
query = db.query(DeployedContract)
191+
if name:
192+
query = query.filter(DeployedContract.contract_name.ilike(f"%{name}%"))
193+
194+
sort_column = valid_sort[sort_by]
195+
if order == "desc":
196+
query = query.order_by(sort_column.desc())
197+
else:
198+
query = query.order_by(sort_column.asc())
199+
200+
return query.all()

py-be/app/models/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
def init_db() -> None:
2020
"""Create database tables."""
2121
# Import models here to ensure they are registered with SQLAlchemy
22-
from . import generated_contract, user # noqa: F401
22+
from . import deployed_contract, generated_contract, user # noqa: F401
2323

2424
Base.metadata.create_all(bind=engine)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Model for storing deployed contract metadata."""
2+
3+
from datetime import datetime
4+
5+
from sqlalchemy import JSON, Column, DateTime, Integer, String
6+
7+
from .base import Base
8+
9+
10+
class DeployedContract(Base):
11+
"""SQLAlchemy model for a deployed contract."""
12+
13+
__tablename__ = "deployed_contracts"
14+
15+
id = Column(Integer, primary_key=True, index=True)
16+
contract_name = Column(String, nullable=False)
17+
contract_address = Column(String, unique=True, nullable=False, index=True)
18+
contract_metadata = Column("metadata", JSON, nullable=True)
19+
deployed_at = Column(DateTime, default=datetime.utcnow)

py-be/tests/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
from app.models.base import Base
99
from app.services.base import get_db
1010

11+
1112
TEST_DATABASE_URL = os.getenv(
1213
"TEST_DATABASE_URL",
1314
"postgresql://postgres:Soham2003@localhost:5432/starkfinder_test",
1415
)
16+
os.environ["DATABASE_URL"] = TEST_DATABASE_URL
1517

1618

1719
engine = create_engine(TEST_DATABASE_URL)
@@ -29,6 +31,12 @@ def setup_test_database():
2931
yield
3032

3133
drop_database(TEST_DATABASE_URL)
34+
Base.metadata.drop_all(bind=engine)
35+
if TEST_DATABASE_URL.startswith("sqlite"):
36+
try:
37+
os.remove("test.db")
38+
except FileNotFoundError:
39+
pass
3240

3341

3442
@pytest.fixture()
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""Tests for the GET /deployed_contracts endpoint."""
2+
3+
from datetime import datetime, timedelta
4+
5+
from fastapi.testclient import TestClient
6+
7+
from app.api import routes
8+
from app.models.deployed_contract import DeployedContract
9+
10+
client = TestClient(routes.app)
11+
12+
13+
def seed_contracts(db):
14+
"""Insert sample deployed contracts into the database."""
15+
db.query(DeployedContract).delete()
16+
now = datetime.utcnow()
17+
contracts = [
18+
DeployedContract(
19+
contract_name="A",
20+
contract_address="0x1",
21+
contract_metadata={"v": 1},
22+
deployed_at=now - timedelta(days=1),
23+
),
24+
DeployedContract(
25+
contract_name="B",
26+
contract_address="0x2",
27+
deployed_at=now,
28+
),
29+
DeployedContract(
30+
contract_name="C",
31+
contract_address="0x3",
32+
deployed_at=now - timedelta(days=2),
33+
),
34+
]
35+
db.add_all(contracts)
36+
db.commit()
37+
return contracts
38+
39+
40+
def test_list_deployed_contracts_default_order(db_session):
41+
seed_contracts(db_session)
42+
res = client.get("/deployed_contracts")
43+
assert res.status_code == 200
44+
data = res.json()
45+
assert [c["contract_name"] for c in data] == ["B", "A", "C"]
46+
47+
48+
def test_list_deployed_contracts_filter_and_sort(db_session):
49+
seed_contracts(db_session)
50+
res = client.get(
51+
"/deployed_contracts",
52+
params={"name": "A", "sort_by": "contract_name", "order": "asc"},
53+
)
54+
assert res.status_code == 200
55+
data = res.json()
56+
assert len(data) == 1
57+
assert data[0]["contract_name"] == "A"

0 commit comments

Comments
 (0)