@@ -94,6 +94,8 @@ fn parse_entity_field(field: &syn::Field) -> Result<ParsingResult, syn::Error> {
9494 fk = Some ( Multiplicity :: OneToMany ) ;
9595 } else if nested. path . is_ident ( "one2one" ) {
9696 fk = Some ( Multiplicity :: OneToOne ) ;
97+ } else if nested. path . is_ident ( "one2opt" ) {
98+ fk = Some ( Multiplicity :: OneToOption ) ;
9799 }
98100 Ok ( ( ) )
99101 } ) ;
@@ -120,63 +122,87 @@ fn parse_entity_field(field: &syn::Field) -> Result<ParsingResult, syn::Error> {
120122 } else if attr. path ( ) . is_ident ( "transient" ) {
121123 let field = FieldDef { name : column_name. clone ( ) , tpe : column_type. clone ( ) } ;
122124 return Ok ( ParsingResult :: Transient ( TransientDef { field} ) )
123- } else if let Type :: Path ( type_path) = & column_type {
124- if let Some ( segment) = type_path. path . segments . last ( ) {
125- if attr. path ( ) . is_ident ( "one2many" ) && segment. ident == "Vec" {
125+ }
126+ }
127+ if let Type :: Path ( type_path) = & column_type {
128+ if let Some ( segment) = type_path. path . segments . last ( ) {
129+ match segment. ident . to_string ( ) . as_str ( ) {
130+ "Vec" => {
131+ // one-to-many
126132 if let PathArguments :: AngleBracketed ( args) = & segment. arguments {
127133 if let Some ( GenericArgument :: Type ( Type :: Path ( inner_type_path) ) ) = args. args . first ( ) {
128- let inner_type =
129- & inner_type_path. path . segments . last ( )
130- . ok_or_else ( || syn:: Error :: new ( field. span ( ) , "Parent field missing" ) ) ?. ident ;
131- let type_path = Type :: Path ( syn:: TypePath { qself : None , path : syn:: Path :: from ( inner_type. clone ( ) ) } ) ;
132- let field = FieldDef { name : column_name. clone ( ) , tpe : type_path } ;
133- return Ok ( ParsingResult :: RelationShip ( RelationshipDef { field, multiplicity : Multiplicity :: OneToMany } ) ) ;
134+ let inner_type = inner_type_path
135+ . path
136+ . segments
137+ . last ( )
138+ . ok_or_else ( || syn:: Error :: new ( field. span ( ) , "Parent field missing" ) ) ?
139+ . ident
140+ . clone ( ) ;
141+ let type_path = Type :: Path ( syn:: TypePath {
142+ qself : None ,
143+ path : syn:: Path :: from ( inner_type) ,
144+ } ) ;
145+ let field = FieldDef {
146+ name : column_name. clone ( ) ,
147+ tpe : type_path,
148+ } ;
149+ return Ok ( ParsingResult :: RelationShip ( RelationshipDef {
150+ field,
151+ multiplicity : Multiplicity :: OneToMany ,
152+ } ) ) ;
134153 }
135154 }
136- } else if attr. path ( ) . is_ident ( "one2one" ) {
137- // Default to OneToOne
138- let mut multiplicity = Multiplicity :: OneToOne ;
139- let mut actual_type = & field. ty ;
140-
141- // Check if the type is Option<T>
142- if let Type :: Path ( type_path) = & field. ty {
143- if let Some ( segment) = type_path. path . segments . first ( ) {
144- if segment. ident == "Option" {
145- // It is Option<T>, now get T
146- if let PathArguments :: AngleBracketed ( angle_bracketed) = & segment. arguments {
147- if let Some ( GenericArgument :: Type ( inner_type) ) = angle_bracketed. args . first ( ) {
148- actual_type = inner_type;
149- multiplicity = Multiplicity :: OneToOption ;
150- }
151- }
152- }
155+ }
156+ "Option" => {
157+ // one-to-option
158+ if let PathArguments :: AngleBracketed ( args) = & segment. arguments {
159+ if let Some ( GenericArgument :: Type ( Type :: Path ( inner_type_path) ) ) = args. args . first ( ) {
160+ let inner_type = inner_type_path
161+ . path
162+ . segments
163+ . last ( )
164+ . ok_or_else ( || syn:: Error :: new ( field. span ( ) , "Parent field missing" ) ) ?
165+ . ident
166+ . clone ( ) ;
167+ let type_path = Type :: Path ( syn:: TypePath {
168+ qself : None ,
169+ path : syn:: Path :: from ( inner_type) ,
170+ } ) ;
171+ let field = FieldDef {
172+ name : column_name. clone ( ) ,
173+ tpe : type_path,
174+ } ;
175+ return Ok ( ParsingResult :: RelationShip ( RelationshipDef {
176+ field,
177+ multiplicity : Multiplicity :: OneToOption ,
178+ } ) ) ;
153179 }
154180 }
155-
156- // Now get the segment from the actual type
157- if let Type :: Path ( type_path ) = actual_type {
158- if let Some ( segment ) = type_path . path . segments . last ( ) {
159- if segment. arguments . is_empty ( ) {
160- let struct_type = & segment . ident ;
161- let type_path = Type :: Path ( syn :: TypePath { qself : None , path : syn :: Path :: from ( struct_type . clone ( ) ) } ) ;
162- let field = FieldDef {
163- name : column_name . clone ( ) ,
164- tpe : type_path ,
165- } ;
166- return Ok ( ParsingResult :: RelationShip ( RelationshipDef {
167- field ,
168- multiplicity ,
169- } ) ) ;
170- }
171- }
181+ }
182+ _ => {
183+ // one-to-one (plain type)
184+ let struct_type = & segment . ident ;
185+ if segment. arguments . is_empty ( ) {
186+ let type_path = Type :: Path ( syn :: TypePath {
187+ qself : None ,
188+ path : syn :: Path :: from ( struct_type . clone ( ) ) ,
189+ } ) ;
190+ let field = FieldDef {
191+ name : column_name . clone ( ) ,
192+ tpe : type_path ,
193+ } ;
194+ return Ok ( ParsingResult :: RelationShip ( RelationshipDef {
195+ field ,
196+ multiplicity : Multiplicity :: OneToOne ,
197+ } ) ) ;
172198 }
173199 }
174200 }
175201 }
176202 }
177203 Err ( syn:: Error :: new (
178204 field. span ( ) ,
179- "Field must have one of #[pk(...)] / #[fk(...)] / #[column(...)] / #[one2one] / #[one2many] / #[transient] annotations of expected underlying types " ,
205+ "Field must have one of #[pk(...)] / #[fk(...)] / #[column(...)] / #[transient] annotations or it is a one2one, one2opt, or one2many relationship (e.g., `Vec<Transaction>` or `Option<Transaction>`). " ,
180206 ) )
181207 }
182208 }
0 commit comments