@@ -398,7 +398,7 @@ Criteria.setMethod(function getAssociationConfiguration(alias) {
398398 *
399399 * @author Jelle De Loecker <[email protected] > 400400 * @since 1.1.0
401- * @version 1.4.0
401+ * @version 1.4.1
402402 *
403403 * @param {string } name
404404 * @param {Object } item
@@ -426,14 +426,20 @@ Criteria.setMethod(function getCriteriaForAssociation(name, item) {
426426 options = this . options ;
427427
428428 // For self-referencing associations (e.g., Person.Parent → Person),
429- // only allow if we have recursive depth remaining.
429+ // only allow if we have recursive depth remaining OR explicit nested associations .
430430 // This prevents infinite loops while still supporting hierarchical data.
431431 if ( assoc_model . name == options . init_model ) {
432432 // Check if we have recursive depth available
433433 let recursive = options . recursive ;
434434
435- if ( ! Number . isSafeInteger ( recursive ) || recursive <= 0 ) {
436- // No recursive depth - block to prevent potential infinite loops
435+ // Also check for explicit nested associations via dot notation (e.g., 'Parent.Parent')
436+ // If there's an explicit Select for this association with nested associations,
437+ // we should allow it even without recursive depth
438+ let has_explicit_nested = options . select ?. associations ?. [ name ] ?. associations ;
439+ let has_nested_associations = has_explicit_nested && Object . keys ( has_explicit_nested ) . length > 0 ;
440+
441+ if ( ! has_nested_associations && ( ! Number . isSafeInteger ( recursive ) || recursive <= 0 ) ) {
442+ // No recursive depth and no explicit nested associations - block to prevent infinite loops
437443 return ;
438444 }
439445 }
@@ -985,20 +991,44 @@ Select.setMethod(Blast.checksumSymbol, function toChecksum() {
985991 return result ;
986992} ) ;
987993
994+ /**
995+ * Get the model to use for association lookups.
996+ * For nested Selects (e.g., when populating 'Project.Client'),
997+ * this returns the associated model, not the criteria's root model.
998+ *
999+ * @author Jelle De Loecker <[email protected] > 1000+ * @since 1.4.1
1001+ * @version 1.4.1
1002+ *
1003+ * @return {Model }
1004+ */
1005+ Select . setMethod ( function getModelForAssociations ( ) {
1006+
1007+ // If this Select has an associated model set (for nested associations),
1008+ // use that instead of the criteria's model
1009+ if ( this . associated_model ) {
1010+ return this . associated_model ;
1011+ }
1012+
1013+ return this . criteria ?. model ;
1014+ } ) ;
1015+
9881016/**
9891017 * Add an association
9901018 *
9911019 * @author Jelle De Loecker <[email protected] > 9921020 * @since 1.1.0
993- * @version 1.3.4
1021+ * @version 1.4.1
9941022 *
9951023 * @param {string } name
9961024 *
9971025 * @return {Select } This creates a new Select instance
9981026 */
9991027Select . setMethod ( function addAssociation ( name ) {
10001028
1001- if ( ! this . criteria ?. model ) {
1029+ let model = this . getModelForAssociations ( ) ;
1030+
1031+ if ( ! model ) {
10021032 throw new Error ( 'Unable to select an association: this Criteria has no model info' ) ;
10031033 }
10041034
@@ -1032,14 +1062,23 @@ Select.setMethod(function addAssociation(name) {
10321062
10331063 // Get the association data
10341064 try {
1035- let info = this . criteria . model . getAssociation ( name ) ;
1065+ let info = model . getAssociation ( name ) ;
10361066
10371067 if ( info ) {
10381068 // Make sure the localkey is added to the resultset
10391069 this . requireFieldForQuery ( info . options . localKey ) ;
1070+
1071+ // Store the associated model on the nested Select so it can
1072+ // resolve its own nested associations correctly
1073+ // (e.g., for 'Project.Client', the Project Select needs to know
1074+ // to look up 'Client' on the Project model, not the root model)
1075+ let associated_model = this . getModel ( info . modelName ) ;
1076+ if ( associated_model ) {
1077+ this . associations [ name ] . associated_model = associated_model ;
1078+ }
10401079 }
10411080 } catch ( err ) {
1042- console . warn ( 'Failed to find "' + name + '" association for ' + this . criteria . model . model_name ) ;
1081+ console . warn ( 'Failed to find "' + name + '" association for ' + model . model_name ) ;
10431082 }
10441083
10451084 return this . associations [ name ] ;
0 commit comments