@@ -20,12 +20,13 @@ pub struct ColumnType {
2020 pub is_array : bool ,
2121 pub is_nullable : bool ,
2222 pub is_unsigned : bool ,
23+ pub record : Option < Vec < ColumnType > > ,
2324 pub max_length : Option < u64 > ,
2425}
2526
2627impl ColumnType {
2728 pub ( crate ) fn for_column_def ( c : & ColumnDef ) -> Result < Self , crate :: errors:: Error > {
28- Ok ( Self :: for_type_path (
29+ Self :: for_type_path (
2930 & c. tpe ,
3031 c. max_length
3132 . as_ref ( )
@@ -34,10 +35,13 @@ impl ColumnType {
3435 . map_err ( crate :: errors:: Error :: ColumnLiteralParseError )
3536 } )
3637 . transpose ( ) ?,
37- ) )
38+ )
3839 }
3940
40- fn for_type_path ( t : & syn:: TypePath , max_length : Option < u64 > ) -> Self {
41+ fn for_type_path (
42+ t : & syn:: TypePath ,
43+ max_length : Option < u64 > ,
44+ ) -> Result < Self , crate :: errors:: Error > {
4145 let last = t
4246 . path
4347 . segments
@@ -51,31 +55,80 @@ impl ColumnType {
5155 is_array : last. ident == "Array" ,
5256 is_nullable : last. ident == "Nullable" ,
5357 is_unsigned : last. ident == "Unsigned" ,
58+ record : None ,
5459 max_length,
5560 } ;
61+ let is_range = last. ident == "Range" ;
62+ let is_multirange = last. ident == "Multirange" ;
63+ let is_record = last. ident == "Record" ;
5664
57- let sql_name = if !ret. is_nullable && !ret. is_array && !ret. is_unsigned {
65+ let sql_name = if !ret. is_nullable
66+ && !ret. is_array
67+ && !ret. is_unsigned
68+ && !is_range
69+ && !is_multirange
70+ && !is_record
71+ {
5872 if last. ident == "PgLsn" {
5973 "pg_lsn" . to_string ( )
6074 } else {
6175 last. ident . to_string ( )
6276 }
6377 } else if let syn:: PathArguments :: AngleBracketed ( ref args) = last. arguments {
6478 let arg = args. args . first ( ) . expect ( "There is at least one argument" ) ;
65- if let syn:: GenericArgument :: Type ( syn:: Type :: Path ( p) ) = arg {
66- let s = Self :: for_type_path ( p, max_length) ;
67- ret. is_nullable |= s. is_nullable ;
68- ret. is_array |= s. is_array ;
69- ret. is_unsigned |= s. is_unsigned ;
70- s. sql_name
79+ if let syn:: GenericArgument :: Type ( syn:: Type :: Tuple ( t) ) = arg {
80+ ret. record = Some (
81+ t. elems
82+ . iter ( )
83+ . map ( |t| {
84+ if let syn:: Type :: Path ( p) = t {
85+ Self :: for_type_path ( p, None )
86+ } else {
87+ panic ! ( ) ;
88+ }
89+ } )
90+ . collect :: < Result < _ , _ > > ( ) ?,
91+ ) ;
92+ "record" . to_owned ( )
93+ } else if let syn:: GenericArgument :: Type ( syn:: Type :: Path ( p) ) = arg {
94+ let s = Self :: for_type_path ( p, max_length) ?;
95+ if is_range {
96+ match s. sql_name . to_uppercase ( ) . as_str ( ) {
97+ "INT4" | "INTEGER" => "int4range" . to_owned ( ) ,
98+ "INT8" | "BIGINT" => "int8range" . into ( ) ,
99+ "NUMERIC" => "numrange" . into ( ) ,
100+ "TIMESTAMP" | "TIMESTAMP WITHOUT TIME ZONE" => "tsrange" . into ( ) ,
101+ "TIMESTAMPTZ" | "TIMESTAMP WITH TIME ZONE" => "tstzrange" . into ( ) ,
102+ "DATE" => "daterange" . into ( ) ,
103+ s => format ! ( "{s}range" ) ,
104+ }
105+ } else if is_multirange {
106+ match s. sql_name . to_uppercase ( ) . as_str ( ) {
107+ "INT4" | "INTEGER" => "int4multirange" . to_owned ( ) ,
108+ "INT8" | "BIGINT" => "int8multirange" . into ( ) ,
109+ "NUMERIC" => "nummultirange" . into ( ) ,
110+ "TIMESTAMP" | "TIMESTAMP WITHOUT TIME ZONE" => "tsmultirange" . into ( ) ,
111+ "TIMESTAMPTZ" | "TIMESTAMP WITH TIME ZONE" => "tstzmultirange" . into ( ) ,
112+ "DATE" => "datemultirange" . into ( ) ,
113+ s => format ! ( "{s}multirange" ) ,
114+ }
115+ } else {
116+ if !ret. is_array {
117+ ret. is_nullable |= s. is_nullable ;
118+ ret. is_array |= s. is_array ;
119+ }
120+ ret. is_unsigned |= s. is_unsigned ;
121+ ret. record = ret. record . or ( s. record ) ;
122+ s. sql_name
123+ }
71124 } else {
72125 unreachable ! ( "That shouldn't happen" )
73126 }
74127 } else {
75128 unreachable ! ( "That shouldn't happen" )
76129 } ;
77130 ret. sql_name = sql_name;
78- ret
131+ Ok ( ret)
79132 }
80133}
81134
@@ -106,7 +159,7 @@ impl fmt::Display for ColumnType {
106159 }
107160}
108161
109- #[ derive( Debug ) ]
162+ #[ derive( Debug , Clone ) ]
110163pub struct ColumnDefinition {
111164 pub sql_name : String ,
112165 pub rust_name : String ,
0 commit comments