1+ """ORM Models for v2 tables and objects."""
2+
13from datetime import datetime
24from typing import Any
35from uuid import NAMESPACE_DNS , UUID , uuid5
@@ -43,15 +45,6 @@ def jsonb_column(name: str, aliases: list[str] | None = None) -> Any:
4345 )
4446
4547
46- # NOTES
47- # - model validation is not triggered when table=True
48- # - Every object model needs to have three flavors:
49- # 1. the declarative model of the object's database table
50- # 2. the model of the manifest when creating a new object
51- # 3. the model of the manifest when updating an object
52- # 4. a response model for APIs related to the object
53-
54-
5548class BaseSQLModel (SQLModel ):
5649 __table_args__ = {"schema" : config .db .table_schema }
5750 metadata = metadata
@@ -71,10 +64,6 @@ class CampaignBase(BaseSQLModel):
7164 metadata_ : dict = jsonb_column ("metadata" , aliases = ["metadata" , "metadata_" ])
7265 configuration : dict = jsonb_column ("configuration" , aliases = ["configuration" , "data" , "spec" ])
7366
74-
75- class CampaignModel (CampaignBase ):
76- """model used for resource creation."""
77-
7867 @model_validator (mode = "before" )
7968 @classmethod
8069 def custom_model_validator (cls , data : Any , info : ValidationInfo ) -> Any :
@@ -83,15 +72,15 @@ def custom_model_validator(cls, data: Any, info: ValidationInfo) -> Any:
8372 """
8473 if isinstance (data , dict ):
8574 if "name" not in data :
86- raise ValueError ("' name' must be specified ." )
75+ raise ValueError ("<campaign> name missing ." )
8776 if "namespace" not in data :
8877 data ["namespace" ] = _default_campaign_namespace
8978 if "id" not in data :
9079 data ["id" ] = uuid5 (namespace = data ["namespace" ], name = data ["name" ])
9180 return data
9281
9382
94- class Campaign (CampaignModel , table = True ):
83+ class Campaign (CampaignBase , table = True ):
9584 """Model used for database operations involving campaigns_v2 table rows"""
9685
9786 __tablename__ : str = "campaigns_v2" # type: ignore[misc]
@@ -111,6 +100,12 @@ class CampaignUpdate(BaseSQLModel):
111100class NodeBase (BaseSQLModel ):
112101 """nodes_v2 db table"""
113102
103+ def __hash__ (self ) -> int :
104+ """A Node is hashable according to its unique ID, so it can be used in
105+ sets and other places hashable types are required.
106+ """
107+ return self .id .int
108+
114109 id : UUID = Field (primary_key = True )
115110 name : str
116111 namespace : UUID
@@ -119,33 +114,32 @@ class NodeBase(BaseSQLModel):
119114 default = ManifestKind .other ,
120115 sa_column = Column ("kind" , Enum (ManifestKind , length = 20 , native_enum = False , create_constraint = False )),
121116 )
122- status : StatusField | None = Field (
117+ status : StatusField = Field (
123118 default = StatusEnum .waiting ,
124119 sa_column = Column ("status" , Enum (StatusEnum , length = 20 , native_enum = False , create_constraint = False )),
125120 )
126121 metadata_ : dict = jsonb_column ("metadata" , aliases = ["metadata" , "metadata_" ])
127122 configuration : dict = jsonb_column ("configuration" , aliases = ["configuration" , "data" , "spec" ])
128123
129-
130- class NodeModel (NodeBase ):
131- """model validating class for Nodes"""
132-
133124 @model_validator (mode = "before" )
134125 @classmethod
135126 def custom_model_validator (cls , data : Any , info : ValidationInfo ) -> Any :
127+ """Validates the model based on different types of raw inputs,
128+ where some default non-optional fields can be auto-populated.
129+ """
136130 if isinstance (data , dict ):
137- if "version" not in data :
138- data [ "version" ] = 1
139- if "name" not in data :
140- raise ValueError ("'name' must be specified ." )
141- if "namespace" not in data :
142- data ["namespace " ] = _default_campaign_namespace
131+ if ( node_name := data . get ( "name" )) is None :
132+ raise ValueError ( "<node> name missing." )
133+ if ( node_namespace := data . get ( "namespace" )) is None :
134+ raise ValueError ("<node> namespace missing ." )
135+ if ( node_version := data . get ( "version" )) is None :
136+ data ["version " ] = node_version = 1
143137 if "id" not in data :
144- data ["id" ] = uuid5 (namespace = data [ "namespace" ] , name = f""" { data [ "name" ] } .{ data [ "version" ] } "" " )
138+ data ["id" ] = uuid5 (namespace = node_namespace , name = f"{ node_name } .{ node_version } " )
145139 return data
146140
147141
148- class Node (NodeModel , table = True ):
142+ class Node (NodeBase , table = True ):
149143 __tablename__ : str = "nodes_v2" # type: ignore[misc]
150144
151145 machine : UUID | None = Field (foreign_key = "machines_v2.id" , default = None , ondelete = "CASCADE" )
@@ -163,28 +157,12 @@ class EdgeBase(BaseSQLModel):
163157 configuration : dict = jsonb_column ("configuration" , aliases = ["configuration" , "data" , "spec" ])
164158
165159
166- class EdgeModel (EdgeBase ):
167- """model validating class for Edges"""
168-
169- @model_validator (mode = "before" )
170- @classmethod
171- def custom_model_validator (cls , data : Any , info : ValidationInfo ) -> Any :
172- if isinstance (data , dict ):
173- if "name" not in data :
174- raise ValueError ("'name' must be specified." )
175- if "namespace" not in data :
176- raise ValueError ("Edges may only exist in a 'namespace'." )
177- if "id" not in data :
178- data ["id" ] = uuid5 (namespace = data ["namespace" ], name = data ["name" ])
179- return data
180-
181-
182- class EdgeResponseModel (EdgeModel ):
160+ class EdgeResponseModel (EdgeBase ):
183161 source : Any
184162 target : Any
185163
186164
187- class Edge (EdgeModel , table = True ):
165+ class Edge (EdgeBase , table = True ):
188166 __tablename__ : str = "edges_v2" # type: ignore[misc]
189167
190168
@@ -216,24 +194,6 @@ class ManifestBase(BaseSQLModel):
216194 spec : dict = jsonb_column ("spec" , aliases = ["spec" , "configuration" , "data" ])
217195
218196
219- class ManifestModel (ManifestBase ):
220- """model validating class for Manifests"""
221-
222- @model_validator (mode = "before" )
223- @classmethod
224- def custom_model_validator (cls , data : Any , info : ValidationInfo ) -> Any :
225- if isinstance (data , dict ):
226- if "version" not in data :
227- data ["version" ] = 1
228- if "name" not in data :
229- raise ValueError ("'name' must be specified." )
230- if "namespace" not in data :
231- data ["namespace" ] = _default_campaign_namespace
232- if "id" not in data :
233- data ["id" ] = uuid5 (namespace = data ["namespace" ], name = f"""{ data ["name" ]} .{ data ["version" ]} """ )
234- return data
235-
236-
237197class Manifest (ManifestBase , table = True ):
238198 __tablename__ : str = "manifests_v2" # type: ignore[misc]
239199
0 commit comments