11import logging
22from abc import ABC , abstractmethod
3- from typing import List , Any , Type , Tuple , Dict , Iterator
3+ from datetime import datetime , date
4+ from typing import List , Any , Type , Tuple , Dict , Iterator , Optional
45
56from resotoclient .models import Kind , Model
67from resotolib .args import Namespace
78from resotolib .types import Json
8- from sqlalchemy import Boolean , Column , Float , Integer , JSON , MetaData , String , Table , DDL
9- from sqlalchemy .engine import Engine , Connection
9+ from resotolib .utils import UTC_Date_Format
10+ from sqlalchemy import (
11+ Boolean ,
12+ Column ,
13+ Float ,
14+ Integer ,
15+ JSON ,
16+ MetaData ,
17+ String ,
18+ Table ,
19+ DDL ,
20+ DateTime ,
21+ Date ,
22+ TypeDecorator ,
23+ )
24+ from sqlalchemy .engine import Engine , Connection , Dialect
1025from sqlalchemy .sql .ddl import DropTable , DropConstraint
1126from sqlalchemy .sql .dml import ValuesBase
1227
13- from cloud2sql .util import value_in_path
1428from cloud2sql .schema_utils import (
1529 base_kinds ,
1630 temp_prefix ,
1933 get_link_table_name ,
2034 kind_properties ,
2135)
36+ from cloud2sql .util import value_in_path
2237
2338log = logging .getLogger ("resoto.cloud2sql" )
2439
2540
41+ class DateTimeString (TypeDecorator ): # type: ignore
42+ """
43+ This type decorator translates between string (python) and datetime (sqlalchemy) types.
44+ """
45+
46+ impl = DateTime
47+ cache_ok = True
48+
49+ def process_bind_param (self , value : Optional [str ], dialect : Dialect ) -> Optional [datetime ]:
50+ return datetime .strptime (value , UTC_Date_Format ) if value else None
51+
52+ def process_result_value (self , value : Optional [datetime ], dialect : Dialect ) -> Optional [str ]:
53+ return value .strftime (UTC_Date_Format ) if value else None
54+
55+
56+ class DateString (TypeDecorator ): # type: ignore
57+ """
58+ This type decorator translates between string (python) and date (sqlalchemy) types.
59+ """
60+
61+ impl = Date
62+ cache_ok = True
63+
64+ def process_bind_param (self , value : Optional [str ], dialect : Dialect ) -> Optional [date ]:
65+ return date .fromisoformat (value ) if value else None
66+
67+ def process_result_value (self , value : Optional [datetime ], dialect : Dialect ) -> Optional [str ]:
68+ return value .strftime ("%Y-%m-%d" ) if value else None
69+
70+
2671def sql_kind_to_column_type (kind_name : str , model : Model ) -> Any : # Type[TypeEngine[Any]]
2772 kind = model .kinds .get (kind_name )
2873 if "[]" in kind_name :
@@ -33,11 +78,15 @@ def sql_kind_to_column_type(kind_name: str, model: Model) -> Any: # Type[TypeEn
3378 return JSON
3479 elif kind_name in ("int32" , "int64" ):
3580 return Integer
36- elif kind_name in "float" :
81+ elif kind_name == "float" :
3782 return Float
38- elif kind_name in "double" :
83+ elif kind_name == "double" :
3984 return Float # use Double with sqlalchemy 2
40- elif kind_name in ("string" , "date" , "datetime" , "duration" ):
85+ elif kind_name == "datetime" :
86+ return DateTimeString
87+ elif kind_name == "date" :
88+ return DateString
89+ elif kind_name in ("string" , "duration" ):
4190 return String
4291 elif kind_name == "boolean" :
4392 return Boolean
0 commit comments