@@ -286,51 +286,29 @@ func (fb *flowBuilder) addRetrieveAction(s *ast.RetrieveStmt) model.ID {
286286
287287 if s .StartVariable != "" {
288288 // Association retrieve: RETRIEVE $List FROM $Parent/Module.AssocName
289+ // Always use AssociationRetrieveSource to preserve the original syntax.
290+ // The runtime resolves traversal direction from association metadata.
289291 assocQN := s .Source .Module + "." + s .Source .Name
290292
291- // Look up association to determine type and direction.
292- // For Reference associations, AssociationRetrieveSource always returns a single
293- // object (the entity on the other end). When the user navigates from the child
294- // (non-owner) side, the intent is to get a list of parent entities — we must use
295- // a DatabaseRetrieveSource with XPath constraint instead.
296- assocInfo := fb .lookupAssociation (s .Source .Module , s .Source .Name )
297- startVarType := ""
298- if fb .varTypes != nil {
299- startVarType = fb .varTypes [s .StartVariable ]
293+ source = & microflows.AssociationRetrieveSource {
294+ BaseElement : model.BaseElement {ID : model .ID (types .GenerateID ())},
295+ StartVariable : s .StartVariable ,
296+ AssociationQualifiedName : assocQN ,
300297 }
301298
302- if assocInfo != nil && assocInfo .Type == domainmodel .AssociationTypeReference &&
303- assocInfo .childEntityQN != "" && startVarType == assocInfo .childEntityQN {
304- // Reverse traversal on Reference: child → parent (one-to-many)
305- // Use DatabaseRetrieveSource with XPath to get a list of parent entities
306- dbSource := & microflows.DatabaseRetrieveSource {
307- BaseElement : model.BaseElement {ID : model .ID (types .GenerateID ())},
308- EntityQualifiedName : assocInfo .parentEntityQN ,
309- XPathConstraint : "[" + assocQN + " = $" + s .StartVariable + "]" ,
310- }
311- source = dbSource
312- if fb .varTypes != nil {
313- fb .varTypes [s .Variable ] = "List of " + assocInfo .parentEntityQN
314- }
315- } else {
316- // Forward traversal or ReferenceSet: use AssociationRetrieveSource
317- source = & microflows.AssociationRetrieveSource {
318- BaseElement : model.BaseElement {ID : model .ID (types .GenerateID ())},
319- StartVariable : s .StartVariable ,
320- AssociationQualifiedName : assocQN ,
321- }
322- if fb .varTypes != nil {
323- if assocInfo != nil && assocInfo .Type == domainmodel .AssociationTypeReference {
324- // Reference forward traversal: returns single object
325- otherEntity := assocInfo .childEntityQN
326- if startVarType == assocInfo .childEntityQN {
327- otherEntity = assocInfo .parentEntityQN
328- }
329- fb .varTypes [s .Variable ] = otherEntity
330- } else {
331- // ReferenceSet or unknown: returns a list
332- fb .varTypes [s .Variable ] = "List of " + assocQN
299+ // Infer variable type for downstream validation
300+ if fb .varTypes != nil {
301+ assocInfo := fb .lookupAssociation (s .Source .Module , s .Source .Name )
302+ startVarType := fb .varTypes [s .StartVariable ]
303+ if assocInfo != nil && assocInfo .Type == domainmodel .AssociationTypeReference {
304+ otherEntity := assocInfo .childEntityQN
305+ if startVarType == assocInfo .childEntityQN {
306+ otherEntity = assocInfo .parentEntityQN
333307 }
308+ fb .varTypes [s .Variable ] = otherEntity
309+ } else {
310+ // ReferenceSet or unknown: returns a list
311+ fb .varTypes [s .Variable ] = "List of " + assocQN
334312 }
335313 }
336314 } else {
0 commit comments