Created Queries and Execute endpoint

This commit is contained in:
2025-02-24 12:15:01 +03:00
parent cabcf837f9
commit 836ce1dc82
14 changed files with 635 additions and 50 deletions

View File

@@ -1,7 +1,9 @@
# schemas.py
from pydantic import BaseModel
from typing import Optional
from core.enums import ConnectionTypes, UserRole
import re
from typing import Union, List, Optional, Literal, Any
from typing_extensions import Annotated
from pydantic import BaseModel, Field, field_validator, ValidationInfo, UUID4
from core.enums import ConnectionTypes, UserRole, FilterOperator, SortOrder
from core.exceptions import QueryValidationError
class ConnectionBase(BaseModel):
@@ -57,3 +59,136 @@ class UserInDBBase(UserBase):
class User(UserInDBBase):
pass
class FilterClause(BaseModel):
column: str
operator: FilterOperator
value: Optional[Union[str, int, float, bool, list]] = None
@field_validator("column")
@classmethod
def validate_column(cls, v: str) -> str:
if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", v):
raise QueryValidationError(
loc=["filters", "column"], msg="Invalid column name format"
)
return v
@field_validator("value")
@classmethod
def validate_value(
cls,
v: Optional[Union[str, int, float, bool, list]],
values: ValidationInfo,
) -> Optional[Union[str, int, float, bool, list]]:
operator = values.data.get("operator")
if operator in [FilterOperator.is_null, FilterOperator.is_not_null]:
if v is not None:
raise QueryValidationError(
loc=["filters", "value"],
msg="Value must be null for IS NULL/IS NOT NULL operators",
)
elif operator == FilterOperator.in_:
if not isinstance(v, list):
raise QueryValidationError(
loc=["filters", "value"],
msg="IN operator requires a list of values",
)
elif v is None:
raise QueryValidationError(
loc=["filters", "value"], msg="Value required for this operator"
)
return v
class SortClause(BaseModel):
column: str
order: SortOrder = SortOrder.asc
@field_validator("column")
@classmethod
def validate_column(cls, v: str) -> str:
if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", v):
raise QueryValidationError(
loc=["sort_by", "column"], msg="Invalid column name format"
)
return v
class SelectQueryBase(BaseModel):
name: str # a short name for this query.
description: str | None = None # describing what does this query do.
table_name: str
columns: Union[Literal["*"], List[str]] = "*"
filters: Optional[List[FilterClause]] = None
sort_by: Optional[List[SortClause]] = None
limit: Annotated[int, Field(strict=True, gt=0)] = None
offset: Annotated[int, Field(strict=True, ge=0)] = None
@field_validator("table_name")
@classmethod
def validate_table_name(cls, v: str) -> str:
if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", v):
raise QueryValidationError(
loc=["table_name"], msg="Invalid table name format"
)
return v
@field_validator("columns")
@classmethod
def validate_columns(
cls, v: Union[Literal["*"], List[str]]
) -> Union[Literal["*"], List[str]]:
if v == "*":
return v
for col in v:
if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", col):
raise QueryValidationError(
loc=["columns"], msg=f"Invalid column name: {col}"
)
return v
class SelectQuery(SelectQueryBase):
sql: str
params: list[str | int | float]
class SelectQueryIn(SelectQuery):
owner_id: int
class SelectQueryInDB(SelectQueryIn):
id: int
class SelectResultData(BaseModel):
columns: List[str]
data: List[List[Any]]
class SelectQueryInResult(BaseModel):
id: int
sql: str
params: list[str | int | float]
class Config:
from_attributes = True
class SelectQueryMetaData(BaseModel):
cursor: Optional[UUID4] = Field(
None,
description="A UUID4 cursor for pagination. Can be None if no more data is available.",
)
total_number: int
has_more: bool = False
class SelectResult(BaseModel):
meta: SelectQueryMetaData
query: SelectQueryInResult
results: SelectResultData | None