Initialize governed Dataflow module
This commit is contained in:
161
src/govoplan_dataflow/backend/schemas.py
Normal file
161
src/govoplan_dataflow/backend/schemas.py
Normal file
@@ -0,0 +1,161 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from datetime import datetime
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
|
||||
PipelineStatus = Literal["draft", "active", "archived"]
|
||||
EditorMode = Literal["graph", "sql"]
|
||||
DiagnosticSeverity = Literal["info", "warning", "error"]
|
||||
|
||||
|
||||
class GraphPosition(BaseModel):
|
||||
x: float
|
||||
y: float
|
||||
|
||||
@field_validator("x", "y")
|
||||
@classmethod
|
||||
def finite_coordinate(cls, value: float) -> float:
|
||||
if not math.isfinite(value):
|
||||
raise ValueError("Graph coordinates must be finite")
|
||||
return value
|
||||
|
||||
|
||||
class GraphNode(BaseModel):
|
||||
id: str = Field(min_length=1, max_length=100, pattern=r"^[A-Za-z0-9_.:-]+$")
|
||||
type: str = Field(min_length=1, max_length=80)
|
||||
label: str = Field(min_length=1, max_length=200)
|
||||
position: GraphPosition
|
||||
config: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class GraphEdge(BaseModel):
|
||||
id: str = Field(min_length=1, max_length=120, pattern=r"^[A-Za-z0-9_.:-]+$")
|
||||
source: str = Field(min_length=1, max_length=100)
|
||||
target: str = Field(min_length=1, max_length=100)
|
||||
source_port: str = Field(default="output", min_length=1, max_length=80)
|
||||
target_port: str = Field(default="input", min_length=1, max_length=80)
|
||||
|
||||
|
||||
class PipelineGraph(BaseModel):
|
||||
schema_version: Literal[1] = 1
|
||||
nodes: list[GraphNode] = Field(default_factory=list, max_length=100)
|
||||
edges: list[GraphEdge] = Field(default_factory=list, max_length=200)
|
||||
|
||||
|
||||
class DataflowDiagnostic(BaseModel):
|
||||
severity: DiagnosticSeverity
|
||||
code: str
|
||||
message: str
|
||||
node_id: str | None = None
|
||||
field: str | None = None
|
||||
|
||||
|
||||
class PipelineRevisionResponse(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
revision: int
|
||||
schema_version: int
|
||||
graph: PipelineGraph
|
||||
sql_text: str | None
|
||||
editor_mode: EditorMode
|
||||
content_hash: str
|
||||
created_by: str | None
|
||||
created_at: datetime
|
||||
|
||||
|
||||
class PipelineResponse(BaseModel):
|
||||
id: str
|
||||
tenant_id: str
|
||||
name: str
|
||||
description: str | None
|
||||
status: PipelineStatus
|
||||
current_revision: int
|
||||
created_by: str | None
|
||||
updated_by: str | None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
revision: PipelineRevisionResponse
|
||||
|
||||
|
||||
class PipelineListResponse(BaseModel):
|
||||
pipelines: list[PipelineResponse]
|
||||
|
||||
|
||||
class PipelineCreateRequest(BaseModel):
|
||||
name: str = Field(min_length=1, max_length=300)
|
||||
description: str | None = Field(default=None, max_length=4000)
|
||||
status: PipelineStatus = "draft"
|
||||
graph: PipelineGraph
|
||||
sql_text: str | None = Field(default=None, max_length=100_000)
|
||||
editor_mode: EditorMode = "graph"
|
||||
|
||||
|
||||
class PipelineUpdateRequest(PipelineCreateRequest):
|
||||
expected_revision: int = Field(ge=1)
|
||||
|
||||
|
||||
class PipelineDraftRequest(BaseModel):
|
||||
graph: PipelineGraph | None = None
|
||||
sql_text: str | None = Field(default=None, max_length=100_000)
|
||||
source_nodes: list[GraphNode] = Field(default_factory=list, max_length=20)
|
||||
|
||||
|
||||
class PipelineValidationResponse(BaseModel):
|
||||
valid: bool
|
||||
graph: PipelineGraph | None
|
||||
sql_text: str | None
|
||||
diagnostics: list[DataflowDiagnostic]
|
||||
|
||||
|
||||
class PipelineSqlResponse(PipelineValidationResponse):
|
||||
pass
|
||||
|
||||
|
||||
class PipelinePreviewRequest(BaseModel):
|
||||
pipeline_id: str | None = None
|
||||
revision: int | None = Field(default=None, ge=1)
|
||||
graph: PipelineGraph | None = None
|
||||
sql_text: str | None = Field(default=None, max_length=100_000)
|
||||
source_nodes: list[GraphNode] = Field(default_factory=list, max_length=20)
|
||||
row_limit: int = Field(default=100, ge=1, le=500)
|
||||
|
||||
|
||||
class PreviewColumn(BaseModel):
|
||||
name: str
|
||||
type: str
|
||||
nullable: bool = True
|
||||
|
||||
|
||||
class NodePreviewDiagnostic(BaseModel):
|
||||
node_id: str
|
||||
status: Literal["succeeded", "failed", "skipped"]
|
||||
input_rows: int = 0
|
||||
output_rows: int = 0
|
||||
duration_ms: float = 0
|
||||
columns: list[PreviewColumn] = Field(default_factory=list)
|
||||
messages: list[str] = Field(default_factory=list)
|
||||
|
||||
|
||||
class PipelinePreviewResponse(BaseModel):
|
||||
run_id: str | None
|
||||
pipeline_id: str | None
|
||||
revision: int | None
|
||||
status: Literal["succeeded", "failed"]
|
||||
columns: list[PreviewColumn]
|
||||
rows: list[dict[str, Any]]
|
||||
total_rows: int
|
||||
truncated: bool
|
||||
diagnostics: list[DataflowDiagnostic]
|
||||
node_diagnostics: list[NodePreviewDiagnostic]
|
||||
definition_hash: str
|
||||
executor_version: str
|
||||
|
||||
|
||||
class PipelineDeleteResponse(BaseModel):
|
||||
deleted: bool
|
||||
pipeline_id: str
|
||||
Reference in New Issue
Block a user