Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve separation of concerns between core and backend libraries #11

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"orjson",
"pydantic[dotenv]",
"stac_pydantic==2.0.*",
"stac-fastapi @ git+https://github.com/stac-utils/stac-fastapi.git@2d72c588151fc16eec1564553a653a039bce6c58",
"stac-fastapi @ git+https://github.com/stac-utils/stac-fastapi.git@c4b738ea3bf8f50473db35b7b505edf1a46d2b06",
"asyncpg",
"buildpg",
"brotli_asgi",
Expand Down
72 changes: 14 additions & 58 deletions stac_fastapi/pgstac/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import re
from datetime import datetime
from typing import Any, Dict, List, Optional, Union
from urllib.parse import urljoin

import attr
import orjson
Expand All @@ -13,8 +12,6 @@
from pygeofilter.backends.cql2_json import to_cql2
from pygeofilter.parsers.cql2_text import parse as parse_cql2_text
from pypgstac.hydration import hydrate
from stac_pydantic.links import Relations
from stac_pydantic.shared import MimeTypes
from starlette.requests import Request

from stac_fastapi.pgstac.config import Settings
Expand All @@ -23,7 +20,6 @@
from stac_fastapi.pgstac.utils import filter_fields
from stac_fastapi.types.core import AsyncBaseCoreClient
from stac_fastapi.types.errors import InvalidQueryParameter, NotFoundError
from stac_fastapi.types.requests import get_base_url
from stac_fastapi.types.stac import Collection, Collections, Item, ItemCollection

NumType = Union[float, int]
Expand All @@ -33,49 +29,20 @@
class CoreCrudClient(AsyncBaseCoreClient):
"""Client for core endpoints defined by stac."""

async def all_collections(self, **kwargs) -> Collections:
async def fetch_all_collections(self, request: Request) -> Collections:
"""Read all collections from the database."""
request: Request = kwargs["request"]
base_url = get_base_url(request)
pool = request.app.state.readpool

async with pool.acquire() as conn:
collections = await conn.fetchval(
return await conn.fetchval(
"""
SELECT * FROM all_collections();
"""
)
linked_collections: List[Collection] = []
if collections is not None and len(collections) > 0:
for c in collections:
coll = Collection(**c)
coll["links"] = await CollectionLinks(
collection_id=coll["id"], request=request
).get_links(extra_links=coll.get("links"))

linked_collections.append(coll)

links = [
{
"rel": Relations.root.value,
"type": MimeTypes.json,
"href": base_url,
},
{
"rel": Relations.parent.value,
"type": MimeTypes.json,
"href": base_url,
},
{
"rel": Relations.self.value,
"type": MimeTypes.json,
"href": urljoin(base_url, "collections"),
},
]
collection_list = Collections(collections=linked_collections or [], links=links)
return collection_list

async def get_collection(self, collection_id: str, **kwargs) -> Collection:

async def fetch_collection(
self, collection_id: str, request: Request
) -> Collection:
"""Get collection by id.

Called with `GET /collections/{collection_id}`.
Expand All @@ -86,9 +53,6 @@ async def get_collection(self, collection_id: str, **kwargs) -> Collection:
Returns:
Collection.
"""
collection: Optional[Dict[str, Any]]

request: Request = kwargs["request"]
pool = request.app.state.readpool
async with pool.acquire() as conn:
q, p = render(
Expand All @@ -97,15 +61,7 @@ async def get_collection(self, collection_id: str, **kwargs) -> Collection:
""",
id=collection_id,
)
collection = await conn.fetchval(q, *p)
if collection is None:
raise NotFoundError(f"Collection {collection_id} does not exist.")

collection["links"] = await CollectionLinks(
collection_id=collection_id, request=request
).get_links(extra_links=collection.get("links"))

return Collection(**collection)
return await conn.fetchval(q, *p)

async def _get_base_item(
self, collection_id: str, request: Request
Expand Down Expand Up @@ -245,7 +201,7 @@ async def _get_base_item(collection_id: str) -> Dict[str, Any]:
).get_links()
return collection

async def item_collection(
async def handle_collection_items(
self,
collection_id: str,
limit: Optional[int] = None,
Expand All @@ -265,7 +221,7 @@ async def item_collection(
An ItemCollection.
"""
# If collection does not exist, NotFoundError wil be raised
await self.get_collection(collection_id, **kwargs)
await self.handle_get_collection(collection_id, **kwargs)

req = self.post_request_model(
collections=[collection_id], limit=limit, token=token
Expand All @@ -277,7 +233,7 @@ async def item_collection(
item_collection["links"] = links
return item_collection

async def get_item(self, item_id: str, collection_id: str, **kwargs) -> Item:
async def handle_get_item(self, item_id: str, collection_id: str, **kwargs) -> Item:
"""Get item by id.

Called with `GET /collections/{collection_id}/items/{item_id}`.
Expand All @@ -290,7 +246,7 @@ async def get_item(self, item_id: str, collection_id: str, **kwargs) -> Item:
Item.
"""
# If collection does not exist, NotFoundError wil be raised
await self.get_collection(collection_id, **kwargs)
await self.handle_get_collection(collection_id, **kwargs)

req = self.post_request_model(
ids=[item_id], collections=[collection_id], limit=1
Expand All @@ -303,7 +259,7 @@ async def get_item(self, item_id: str, collection_id: str, **kwargs) -> Item:

return Item(**item_collection["features"][0])

async def post_search(
async def handle_post_search(
self, search_request: PgstacSearch, **kwargs
) -> ItemCollection:
"""Cross catalog search (POST).
Expand All @@ -319,7 +275,7 @@ async def post_search(
item_collection = await self._search_base(search_request, **kwargs)
return ItemCollection(**item_collection)

async def get_search(
async def handle_get_search(
self,
collections: Optional[List[str]] = None,
ids: Optional[List[str]] = None,
Expand Down Expand Up @@ -408,4 +364,4 @@ async def get_search(
raise HTTPException(
status_code=400, detail=f"Invalid parameters provided {e}"
)
return await self.post_search(search_request, request=kwargs["request"])
return await self.handle_post_search(search_request, request=kwargs["request"])
14 changes: 7 additions & 7 deletions stac_fastapi/pgstac/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
class TransactionsClient(AsyncBaseTransactionsClient):
"""Transactions extension specific CRUD operations."""

async def create_item(
async def handle_create_item(
self, collection_id: str, item: stac_types.Item, **kwargs
) -> Optional[Union[stac_types.Item, Response]]:
"""Create item."""
Expand All @@ -45,7 +45,7 @@ async def create_item(
).get_links(extra_links=item.get("links"))
return stac_types.Item(**item)

async def update_item(
async def handle_update_item(
self, collection_id: str, item_id: str, item: stac_types.Item, **kwargs
) -> Optional[Union[stac_types.Item, Response]]:
"""Update item."""
Expand All @@ -72,7 +72,7 @@ async def update_item(
).get_links(extra_links=item.get("links"))
return stac_types.Item(**item)

async def create_collection(
async def handle_create_collection(
self, collection: stac_types.Collection, **kwargs
) -> Optional[Union[stac_types.Collection, Response]]:
"""Create collection."""
Expand All @@ -85,7 +85,7 @@ async def create_collection(

return stac_types.Collection(**collection)

async def update_collection(
async def handle_update_collection(
self, collection: stac_types.Collection, **kwargs
) -> Optional[Union[stac_types.Collection, Response]]:
"""Update collection."""
Expand All @@ -97,7 +97,7 @@ async def update_collection(
).get_links(extra_links=collection.get("links"))
return stac_types.Collection(**collection)

async def delete_item(
async def handle_delete_item(
self, item_id: str, **kwargs
) -> Optional[Union[stac_types.Item, Response]]:
"""Delete item."""
Expand All @@ -106,7 +106,7 @@ async def delete_item(
await dbfunc(pool, "delete_item", item_id)
return JSONResponse({"deleted item": item_id})

async def delete_collection(
async def handle_delete_collection(
self, collection_id: str, **kwargs
) -> Optional[Union[stac_types.Collection, Response]]:
"""Delete collection."""
Expand All @@ -120,7 +120,7 @@ async def delete_collection(
class BulkTransactionsClient(AsyncBaseBulkTransactionsClient):
"""Postgres bulk transactions."""

async def bulk_item_insert(self, items: Items, **kwargs) -> str:
async def handle_bulk_item_insert(self, items: Items, **kwargs) -> str:
"""Bulk item insertion using pgstac."""
request = kwargs["request"]
pool = request.app.state.writepool
Expand Down