@@ -168,14 +168,22 @@ fn pattern_impl(input: TokenStream) -> syn::Result<TokenStream> {
168168
169169 // Accumulate the token stream for each entity pattern.
170170 let mut entity_tokens = TokenStream2 :: new ( ) ;
171+ // Token stream that initializes attribute variables once.
172+ let mut attr_tokens = TokenStream2 :: new ( ) ;
173+ // Bring the namespace into scope for attribute initialization.
174+ attr_tokens. extend ( quote ! { use #ns as ns; } ) ;
171175 // Counter to create unique identifiers for entity variables.
172- let mut idx = 0usize ;
176+ let mut entity_idx = 0usize ;
177+ // Counter and map for unique attribute variables.
178+ let mut attr_idx = 0usize ;
179+ use std:: collections:: HashMap ;
180+ let mut attr_map: HashMap < String , Ident > = HashMap :: new ( ) ;
173181
174182 // Expand one block per entity described in the pattern.
175183 for entity in pattern {
176184 // Variable name representing the entity id.
177- let e_ident = format_ident ! ( "__e{}" , idx , span = Span :: call_site( ) ) ;
178- idx += 1 ;
185+ let e_ident = format_ident ! ( "__e{}" , entity_idx , span = Span :: call_site( ) ) ;
186+ entity_idx += 1 ;
179187 // Initialization depends on whether an id was supplied.
180188 let init = match entity. id {
181189 // Existing identifier variable: reuse it directly.
@@ -194,24 +202,35 @@ fn pattern_impl(input: TokenStream) -> syn::Result<TokenStream> {
194202 // Emit triple constraints for each field within the entity.
195203 for Field { name, value } in entity. fields {
196204 let field_ident = name;
205+
206+ // Reuse the same attribute variable for each unique field name.
207+ let a_var_ident = attr_map
208+ . entry ( field_ident. to_string ( ) )
209+ . or_insert_with ( || {
210+ let ident = format_ident ! ( "__a{}" , attr_idx, span = Span :: call_site( ) ) ;
211+ attr_idx += 1 ;
212+ attr_tokens. extend ( quote ! {
213+ let #ident: #crate_path:: query:: Variable <#crate_path:: value:: schemas:: genid:: GenId > = #ctx_ident. next_variable( ) ;
214+ constraints. push( Box :: new( #ident. is( #crate_path:: value:: ToValue :: to_value( ns:: ids:: #field_ident) ) ) ) ;
215+ } ) ;
216+ ident
217+ } )
218+ . clone ( ) ;
219+
197220 let triple_tokens = match value {
198221 // Literal value: create a variable bound to the literal and match it.
199222 FieldValue :: Lit ( expr) => {
200223 quote ! {
201224 {
202225 use #crate_path:: query:: TriblePattern ;
203226 use #ns as ns;
204- // fresh vars for attribute and value
205- let a_var: #crate_path:: query:: Variable <#crate_path:: value:: schemas:: genid:: GenId > = #ctx_ident. next_variable( ) ;
206227 let v_var: #crate_path:: query:: Variable <ns:: schemas:: #field_ident> = #ctx_ident. next_variable( ) ;
207228 // literal value converted to a `Value`
208229 let v: #crate_path:: value:: Value <ns:: schemas:: #field_ident> = #crate_path:: value:: ToValue :: to_value( #expr) ;
209- // ensure the attribute id matches
210- constraints. push( Box :: new( a_var. is( #crate_path:: value:: ToValue :: to_value( ns:: ids:: #field_ident) ) ) ) ;
211230 // ensure the literal matches the variable
212231 constraints. push( Box :: new( v_var. is( v) ) ) ;
213232 // match the triple from the dataset
214- constraints. push( Box :: new( #set_ident. pattern( #e_ident, a_var , v_var) ) ) ;
233+ constraints. push( Box :: new( #set_ident. pattern( #e_ident, #a_var_ident , v_var) ) ) ;
215234 }
216235 }
217236 }
@@ -221,10 +240,8 @@ fn pattern_impl(input: TokenStream) -> syn::Result<TokenStream> {
221240 {
222241 use #crate_path:: query:: TriblePattern ;
223242 use #ns as ns;
224- let a_var: #crate_path:: query:: Variable <#crate_path:: value:: schemas:: genid:: GenId > = #ctx_ident. next_variable( ) ;
225243 let v_var: #crate_path:: query:: Variable <ns:: schemas:: #field_ident> = #expr;
226- constraints. push( Box :: new( a_var. is( #crate_path:: value:: ToValue :: to_value( ns:: ids:: #field_ident) ) ) ) ;
227- constraints. push( Box :: new( #set_ident. pattern( #e_ident, a_var, v_var) ) ) ;
244+ constraints. push( Box :: new( #set_ident. pattern( #e_ident, #a_var_ident, v_var) ) ) ;
228245 }
229246 }
230247 }
@@ -239,6 +256,7 @@ fn pattern_impl(input: TokenStream) -> syn::Result<TokenStream> {
239256 let mut constraints: Vec <Box <dyn #crate_path:: query:: Constraint >> = vec![ ] ;
240257 let #ctx_ident = __local_find_context!( ) ;
241258 let #set_ident = #set;
259+ #attr_tokens
242260 #entity_tokens
243261 #crate_path:: query:: intersectionconstraint:: IntersectionConstraint :: new( constraints)
244262 }
0 commit comments