auto-rest-api 0.1.5__tar.gz → 0.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/PKG-INFO +1 -1
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/app.py +4 -1
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/cli.py +1 -1
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/handlers.py +28 -16
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/models.py +4 -4
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/pyproject.toml +1 -1
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/LICENSE.md +0 -0
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/README.md +0 -0
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/__init__.py +0 -0
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/__main__.py +0 -0
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/interfaces.py +0 -0
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/queries.py +0 -0
- {auto_rest_api-0.1.5 → auto_rest_api-0.1.6}/auto_rest/routers.py +0 -0
|
@@ -44,9 +44,12 @@ async def logging_middleware(request: Request, call_next: callable) -> Response:
|
|
|
44
44
|
"ip": request.client.host,
|
|
45
45
|
"port": request.client.port,
|
|
46
46
|
"method": request.method,
|
|
47
|
-
"endpoint":
|
|
47
|
+
"endpoint": request.url.path,
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
if request.url.query:
|
|
51
|
+
request_meta["endpoint"] += "?" + request.url.query
|
|
52
|
+
|
|
50
53
|
# Execute handling logic
|
|
51
54
|
try:
|
|
52
55
|
response = await call_next(request)
|
|
@@ -35,7 +35,7 @@ import logging.config
|
|
|
35
35
|
from argparse import ArgumentParser, HelpFormatter
|
|
36
36
|
from pathlib import Path
|
|
37
37
|
|
|
38
|
-
__all__ = ["configure_cli_logging", "create_cli_parser"]
|
|
38
|
+
__all__ = ["configure_cli_logging", "create_cli_parser", "VERSION"]
|
|
39
39
|
|
|
40
40
|
VERSION = importlib.metadata.version("auto-rest-api")
|
|
41
41
|
|
|
@@ -188,21 +188,42 @@ def create_list_records_handler(engine: DBEngine, table: Table) -> Callable[...,
|
|
|
188
188
|
"""
|
|
189
189
|
|
|
190
190
|
interface = create_interface(table)
|
|
191
|
-
|
|
191
|
+
interface_opt = create_interface(table, mode="optional")
|
|
192
|
+
col_names = tuple(table.columns.keys())
|
|
192
193
|
|
|
193
194
|
async def list_records_handler(
|
|
194
195
|
response: Response,
|
|
195
196
|
session: DBSession = Depends(create_session_iterator(engine)),
|
|
197
|
+
filters: interface_opt = Depends(),
|
|
196
198
|
_limit_: int = Query(0, ge=0, description="The maximum number of records to return."),
|
|
197
199
|
_offset_: int = Query(0, ge=0, description="The starting index of the returned records."),
|
|
198
|
-
_order_by_: Optional[Literal[*
|
|
199
|
-
_direction_: Literal["asc", "desc"] = Query("asc", description="Sort results in 'asc' or 'desc' order.")
|
|
200
|
+
_order_by_: Optional[Literal[*col_names]] = Query(None, description="The field name to sort by."),
|
|
201
|
+
_direction_: Literal["asc", "desc"] = Query("asc", description="Sort results in 'asc' or 'desc' order."),
|
|
200
202
|
) -> list[interface]:
|
|
201
203
|
"""Fetch a list of records from the database.
|
|
202
204
|
|
|
203
205
|
URL query parameters are used to enable filtering, ordering, and paginating returned values.
|
|
204
206
|
"""
|
|
205
207
|
|
|
208
|
+
query = select(table)
|
|
209
|
+
|
|
210
|
+
# Fetch data per the request parameters
|
|
211
|
+
for param, value in filters:
|
|
212
|
+
if value is not None:
|
|
213
|
+
column = getattr(table.c, param)
|
|
214
|
+
if value.lower() == "_null_":
|
|
215
|
+
query = query.filter(column.is_(None))
|
|
216
|
+
|
|
217
|
+
else:
|
|
218
|
+
query = query.filter(column.ilike(f"%{value}%"))
|
|
219
|
+
|
|
220
|
+
if _limit_ > 0:
|
|
221
|
+
query = query.offset(_offset_).limit(_limit_)
|
|
222
|
+
|
|
223
|
+
if _order_by_ is not None:
|
|
224
|
+
direction = {'desc': desc, 'asc': asc}[_direction_]
|
|
225
|
+
query = query.order_by(direction(_order_by_))
|
|
226
|
+
|
|
206
227
|
# Determine total record count
|
|
207
228
|
total_count_query = select(func.count()).select_from(table)
|
|
208
229
|
total_count = await execute_session_query(session, total_count_query)
|
|
@@ -214,17 +235,8 @@ def create_list_records_handler(engine: DBEngine, table: Table) -> Callable[...,
|
|
|
214
235
|
response.headers["x-order-by"] = str(_order_by_)
|
|
215
236
|
response.headers["x-order-direction"] = str(_direction_)
|
|
216
237
|
|
|
217
|
-
#
|
|
218
|
-
|
|
219
|
-
if _limit_ > 0:
|
|
220
|
-
query = query.offset(_offset_).limit(_limit_)
|
|
221
|
-
|
|
222
|
-
if _order_by_ is not None:
|
|
223
|
-
direction = {'desc': desc, 'asc': asc}[_direction_]
|
|
224
|
-
query = query.order_by(direction(_order_by_))
|
|
225
|
-
|
|
226
|
-
result = await execute_session_query(session, query)
|
|
227
|
-
return [row._mapping for row in result.all()]
|
|
238
|
+
# noinspection PyTypeChecker
|
|
239
|
+
return await execute_session_query(session, query)
|
|
228
240
|
|
|
229
241
|
return list_records_handler
|
|
230
242
|
|
|
@@ -257,7 +269,7 @@ def create_get_record_handler(engine: DBEngine, table: Table) -> Callable[..., A
|
|
|
257
269
|
return get_record_handler
|
|
258
270
|
|
|
259
271
|
|
|
260
|
-
def create_post_record_handler(engine: DBEngine, table: Table) -> Callable[..., Awaitable[
|
|
272
|
+
def create_post_record_handler(engine: DBEngine, table: Table) -> Callable[..., Awaitable[None]]:
|
|
261
273
|
"""Create a function for handling POST requests against a record in the database.
|
|
262
274
|
|
|
263
275
|
Args:
|
|
@@ -276,7 +288,7 @@ def create_post_record_handler(engine: DBEngine, table: Table) -> Callable[...,
|
|
|
276
288
|
) -> None:
|
|
277
289
|
"""Create a new record in the database."""
|
|
278
290
|
|
|
279
|
-
query = insert(table).values(**data.
|
|
291
|
+
query = insert(table).values(**data.model_dump())
|
|
280
292
|
await execute_session_query(session, query)
|
|
281
293
|
await commit_session(session)
|
|
282
294
|
|
|
@@ -32,7 +32,7 @@ connection and session handling are configured accordingly.
|
|
|
32
32
|
import asyncio
|
|
33
33
|
import logging
|
|
34
34
|
from pathlib import Path
|
|
35
|
-
from typing import Callable
|
|
35
|
+
from typing import AsyncGenerator, Callable, Generator
|
|
36
36
|
|
|
37
37
|
import yaml
|
|
38
38
|
from sqlalchemy import create_engine, Engine, MetaData, URL
|
|
@@ -169,7 +169,7 @@ def create_db_metadata(engine: DBEngine) -> MetaData:
|
|
|
169
169
|
return metadata
|
|
170
170
|
|
|
171
171
|
|
|
172
|
-
def create_session_iterator(engine: DBEngine) -> Callable[[],
|
|
172
|
+
def create_session_iterator(engine: DBEngine) -> Callable[[], Generator[Session, None, None] | AsyncGenerator[AsyncSession, None]]:
|
|
173
173
|
"""Create a generator for database sessions.
|
|
174
174
|
|
|
175
175
|
Returns a synchronous or asynchronous function depending on whether
|
|
@@ -185,12 +185,12 @@ def create_session_iterator(engine: DBEngine) -> Callable[[], DBSession]:
|
|
|
185
185
|
"""
|
|
186
186
|
|
|
187
187
|
if isinstance(engine, AsyncEngine):
|
|
188
|
-
async def session_iterator() -> AsyncSession:
|
|
188
|
+
async def session_iterator() -> AsyncGenerator[AsyncSession, None]:
|
|
189
189
|
async with AsyncSession(bind=engine, autocommit=False, autoflush=True) as session:
|
|
190
190
|
yield session
|
|
191
191
|
|
|
192
192
|
else:
|
|
193
|
-
def session_iterator() -> Session:
|
|
193
|
+
def session_iterator() -> Generator[Session, None, None]:
|
|
194
194
|
with Session(bind=engine, autocommit=False, autoflush=True) as session:
|
|
195
195
|
yield session
|
|
196
196
|
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "auto-rest-api"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
description = "Automatically map database schemas and deploy per-table REST API endpoints."
|
|
10
10
|
authors = [{ name = "Better HPC LLC" }]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|