@@ -712,131 +712,146 @@ abstract class Model extends QueryBuilderImpl {
712712 return this ;
713713 }
714714
715- void _clearWithRelation (_RelationQuery r) {
716- _withRelation = _withRelation.where ((item) => item != r).toList ();
717- }
718-
719715 Future <void > _eagerLoadRelation (
720716 List <Map <String , dynamic >> models,
721717 _RelationQuery rq,
722718 Function (dynamic data) callBack,
723719 ) async {
724720 String relation = rq.relation;
721+ List <String > wr = relation.split ('.' );
725722
726- if (_withRelation.any ((r) => r.relation == relation)) {
727- List <String > wr = relation.split ('.' );
723+ String primaryRelation = wr.first;
728724
729- String primaryRelation = wr.first;
725+ List <String > getColumns = ['*' ];
726+ final relationParts = primaryRelation.split (':' );
730727
731- List < String > getColumns = [ '*' ];
732- final relationParts = primaryRelation. split ( ':' );
728+ if (relationParts.length > 1 ) {
729+ primaryRelation = relationParts.first. trim ( );
733730
734- if (relationParts.length > 1 ) {
735- primaryRelation = relationParts.first.trim ();
731+ final columnsString = relationParts.last.trim ();
736732
737- final columnsString = relationParts.last.trim ();
738-
739- if (columnsString.isNotEmpty) {
740- getColumns = columnsString
741- .split (',' )
742- .map ((col) => col.trim ())
743- .where ((col) => col.isNotEmpty)
744- .toList ();
745- }
733+ if (columnsString.isNotEmpty) {
734+ getColumns = columnsString
735+ .split (',' )
736+ .map ((col) => col.trim ())
737+ .where ((col) => col.isNotEmpty)
738+ .toList ();
746739 }
740+ }
747741
748- if (! _relations.containsKey (primaryRelation)) {
749- throw InvalidArgumentException (
750- 'Relation $relation not found in $runtimeType ' ,
751- );
752- }
742+ if (! _relations.containsKey (primaryRelation)) {
743+ throw InvalidArgumentException (
744+ 'Relation $relation not found in $runtimeType ' ,
745+ );
746+ }
753747
754- Relation rela = _relations[primaryRelation] as Relation ;
755- Model qb = rela.related;
756- rela.parent._clearWithRelation (rq);
748+ Relation rela = _relations[primaryRelation] as Relation ;
749+ Model qb = rela.related;
757750
758- if (rq.callback != null ) {
759- qb = rq.callback !(qb) as Model ;
760- }
751+ if (rq.callback != null ) {
752+ qb = rq.callback !(qb) as Model ;
753+ }
761754
762- if (rela is MorphRelation ) {
763- if (rela is MorphTo ) {
764- Set ids = models.map ((m) => m[rela.morphKey]).toSet ();
765- qb = qb.whereIn (rela.localKey, ids.toList ()) as Model ;
766- } else {
767- Set ids = models.map ((m) => m[rela.localKey]).toSet ();
768-
769- if (rela is MorphToMany || rela is MorphedByMany ) {
770- qb =
771- qb
772- .whereIn (rela.morphKey, ids.toList ())
773- .whereEqualTo (rela.morphType, rela.type)
774- .join (
775- rela.related.tableName,
776- '${rela .pivotTable }.${rela .relatedMorphKey }' ,
777- '=' ,
778- '${rela .related .tableName }.${rela .localKey }' ,
779- )
780- as Model ;
781- qb.tableName = rela.pivotTable! ;
782- } else {
783- qb =
784- qb
785- .whereIn (rela.morphKey, ids.toList ())
786- .whereEqualTo (rela.morphType, rela.type)
787- as Model ;
788- }
755+ if (rela is MorphRelation ) {
756+ if (rela is MorphTo ) {
757+ Set ids = models.map ((m) => m[rela.morphKey]).toSet ();
758+
759+ // Early return if no IDs to query
760+ if (ids.isEmpty) {
761+ callBack (rela.match (models, [], primaryRelation));
762+ return ;
789763 }
764+
765+ qb = qb.whereIn (rela.localKey, ids.toList ()) as Model ;
790766 } else {
791- late final String getLocalKey;
792- if (rela is BelongsTo ) {
793- getLocalKey =
794- rela.foreignKey ??
795- '${rela .related .runtimeType .toString ()}_id' .toLowerCase ();
796- } else {
797- getLocalKey = rela.localKey;
798- }
767+ Set ids = models.map ((m) => m[rela.localKey]).toSet ();
799768
800- Set ids = models.map ((m) => m[getLocalKey]).toSet ();
769+ // Early return if no IDs to query
770+ if (ids.isEmpty) {
771+ callBack (rela.match (models, [], primaryRelation));
772+ return ;
773+ }
801774
802- if (rela is BelongsToMany ) {
775+ if (rela is MorphToMany || rela is MorphedByMany ) {
803776 qb =
804777 qb
805- .whereIn (
806- '${rela .pivotTable }.${rela .parentPivotKey }' ,
807- ids.toList (),
808- )
778+ .whereIn (rela.morphKey, ids.toList ())
779+ .whereEqualTo (rela.morphType, rela.type)
809780 .join (
810- rela.pivotTable ,
811- '${rela .pivotTable }.${rela .relatedPivotKey }' ,
781+ rela.related.tableName ,
782+ '${rela .pivotTable }.${rela .relatedMorphKey }' ,
812783 '=' ,
813- '${rela .related .tableName }.${rela .relatedLocalKey }' ,
784+ '${rela .related .tableName }.${rela .localKey }' ,
814785 )
815786 as Model ;
816- } else if (rela is BelongsTo ) {
817- qb = qb.whereIn (rela.localKey, ids.toList ()) as Model ;
787+ qb.tableName = rela.pivotTable! ;
818788 } else {
819- qb = qb.whereIn (rela.foreignKey! , ids.toList ()) as Model ;
789+ qb =
790+ qb
791+ .whereIn (rela.morphKey, ids.toList ())
792+ .whereEqualTo (rela.morphType, rela.type)
793+ as Model ;
820794 }
821795 }
822- late final List <Map <String , dynamic >> results;
796+ } else {
797+ late final String getLocalKey;
798+ if (rela is BelongsTo ) {
799+ getLocalKey =
800+ rela.foreignKey ??
801+ '${rela .related .runtimeType .toString ()}_id' .toLowerCase ();
802+ } else {
803+ getLocalKey = rela.localKey;
804+ }
805+
806+ Set ids = models.map ((m) => m[getLocalKey]).toSet ();
807+
808+ // Early return if no IDs to query
809+ if (ids.isEmpty) {
810+ callBack (rela.match (models, [], primaryRelation));
811+ return ;
812+ }
823813
824- if (wr.length > 1 ) {
825- wr.removeAt (0 );
826- results = await qb.include (wr.join ('.' )).get (getColumns);
814+ if (rela is BelongsToMany ) {
815+ qb =
816+ qb
817+ .whereIn (
818+ '${rela .pivotTable }.${rela .parentPivotKey }' ,
819+ ids.toList (),
820+ )
821+ .join (
822+ rela.pivotTable,
823+ '${rela .pivotTable }.${rela .relatedPivotKey }' ,
824+ '=' ,
825+ '${rela .related .tableName }.${rela .relatedLocalKey }' ,
826+ )
827+ as Model ;
828+ } else if (rela is BelongsTo ) {
829+ qb = qb.whereIn (rela.localKey, ids.toList ()) as Model ;
827830 } else {
828- results = await qb.get (getColumns) ;
831+ qb = qb.whereIn (rela.foreignKey ! , ids. toList ()) as Model ;
829832 }
833+ }
834+
835+ late final List <Map <String , dynamic >> results;
830836
831- callBack (rela.match (models, results, primaryRelation));
837+ if (wr.length > 1 ) {
838+ wr.removeAt (0 );
839+ results = await qb.include (wr.join ('.' )).get (getColumns);
840+ } else {
841+ results = await qb.get (getColumns);
832842 }
843+
844+ callBack (rela.match (models, results, primaryRelation));
833845 }
834846
835847 Future <List <Map <String , dynamic >>> _loadRelations (
836848 List <Map <String , dynamic >> result,
837849 ) async {
838850 if (_withRelation.isNotEmpty) {
839- final relationsToLoad = List <_RelationQuery >.from (_withRelation);
851+ // Create an immutable copy of relations to load and clear the original list
852+ // This prevents concurrent modification when iterating
853+ final relationsToLoad = List <_RelationQuery >.unmodifiable (_withRelation);
854+ _withRelation = [];
840855
841856 for (_RelationQuery relation in relationsToLoad) {
842857 await _eagerLoadRelation (result, relation, (callBackResult) {
0 commit comments