Skip to content

Commit

Permalink
feat(HasManyThrough): The hasManyThrough function now returns `HasM…
Browse files Browse the repository at this point in the history
…anyDeep` relationships
  • Loading branch information
elpete committed Mar 14, 2024
1 parent 5331b36 commit 1af491a
Show file tree
Hide file tree
Showing 14 changed files with 683 additions and 281 deletions.
75 changes: 46 additions & 29 deletions models/BaseEntity.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -1701,7 +1701,7 @@ component accessors="true" {
*
* @return quick.models.Relationships.HasManyThrough
*/
private HasManyThrough function hasManyThrough( required array relationships, string relationMethodName ) {
private HasManyDeep function hasManyThrough( required array relationships, string relationMethodName ) {
if ( arguments.relationships.len() <= 1 ) {
throw(
type = "RelationshipsLengthMismatch",
Expand All @@ -1716,37 +1716,54 @@ component accessors="true" {
"This instance is not loaded so it cannot access the [#arguments.relationMethodName#] relationship. Either load the entity from the database using a query executor (like `first`) or base your query off of the [#arguments.relationships[ arguments.relationships.len() ]#] entity directly and use the `has` or `whereHas` methods to constrain it based on data in [#entityName()#]."
);

// this is set here for the first case where the previousEntity is
// `this` entity and we don't want to double prefix
var aliasPrefix = variables._aliasPrefix;
var previousEntity = this;
var relationshipsMap = arguments.relationships.reduce( function( map, relation, index ) {
var mirroredIndex = relationships.len() == 2 ? ( index == 1 ? 2 : 1 ) : ( index + ( relationships.len() - 1 ) ) % (
relationships.len() + 1
);
mirroredIndex = mirroredIndex == 0 ? index : mirroredIndex;
previousEntity.set_aliasPrefix( aliasPrefix & mirroredIndex & "_" );
var relationship = previousEntity.ignoreLoadedGuard( function() {
return invoke( previousEntity, relation );
var related = "";
var parent = this;
var through = [];
var foreignKeys = [];
var localKeys = [];

var predecessor = this;
for ( var i = 1; i <= arguments.relationships.len(); i++ ) {
var relationName = arguments.relationships[ i ];
var relationship = predecessor.ignoreLoadedGuard( function() {
return invoke( predecessor, relationName );
} );
relationship.applyAliasSuffix( "_" & aliasPrefix & mirroredIndex );
map[ relation ] = relationship;
previousEntity = relationship.getRelated();
return map;
}, structNew( "ordered" ) );

return variables._wirebox.getInstance(
name = "HasManyThrough@quick",
initArguments = {
"related" : relationshipsMap[ relationships[ relationships.len() ] ].getRelated(),
"relationName" : relationships[ relationships.len() ],
"relationMethodName" : arguments.relationMethodName,
"parent" : this,
"relationships" : arguments.relationships,
"relationshipsMap" : relationshipsMap,
"withConstraints" : !variables._withoutRelationshipConstraints
relationship.withAlias( "#relationName#_#i#" );

var updatedArgs = relationship.appendToDeepRelationship( through, foreignKeys, localKeys, i );
through = updatedArgs.through;
foreignKeys = updatedArgs.foreignKeys;
localKeys = updatedArgs.localKeys;

if ( i == arguments.relationships.len() ) {
related = relationship.getRelated().mappingName();
} else {
var relatedEntity = relationship.getRelated();
var throughMapping = relatedEntity.mappingName();
var successor = relatedEntity.ignoreLoadedGuard( function() {
return invoke( relatedEntity, relationships[ i + 1 ] );
} );
if ( relatedEntity.mappingName() == successor.getParent().mappingName() ) {
if ( successor.getParent().tableName() != successor.getParent().tableAlias() ) {
throughMapping &= " AS #successor.getParent().tableAlias()#";
}
}

through.append( throughMapping );
predecessor = successor.getParent();
}
);
}

return this.ignoreLoadedGuard( function() {
return hasManyDeep(
related,
through,
foreignKeys,
localKeys,
relationMethodName
);
} );
}

/**
Expand Down
7 changes: 7 additions & 0 deletions models/Relationships/BaseRelationship.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ component accessors="true" implements="IRelationship" {
);
}

public boolean function addEagerConstraints( required array entities, required any baseEntity ) {
throw(
type = "NotImplemented",
message = "The `addEagerConstraints` method must be implemented in the concrete relationship."
);
}

/**
* Retrieves the values of the key from each entity passed.
*
Expand Down
31 changes: 30 additions & 1 deletion models/Relationships/BelongsTo.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
* }
* ```
*/
component extends="quick.models.Relationships.BaseRelationship" accessors="true" {
component
extends ="quick.models.Relationships.BaseRelationship"
implements="IConcatenatableRelationship"
accessors ="true"
{

/**
* An alias for the parent entity.
Expand Down Expand Up @@ -456,4 +460,29 @@ component extends="quick.models.Relationships.BaseRelationship" accessors="true"
} );
}

public struct function appendToDeepRelationship(
required array through,
required array foreignKeys,
required array localKeys,
required numeric position
) {
if ( variables.localKeys.len() == 1 ) {
arguments.foreignKeys.append( variables.localKeys, true );
} else {
arguments.foreignKeys.append( variables.localKeys );
}

if ( variables.foreignKeys.len() == 1 ) {
arguments.localKeys.append( variables.foreignKeys, true );
} else {
arguments.localKeys.append( variables.foreignKeys );
}

return {
"through" : arguments.through,
"foreignKeys" : arguments.foreignKeys,
"localKeys" : arguments.localKeys
};
}

}
45 changes: 44 additions & 1 deletion models/Relationships/BelongsToMany.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
* }
* ```
*/
component extends="quick.models.Relationships.BaseRelationship" accessors="true" {
component
extends ="quick.models.Relationships.BaseRelationship"
implements="IConcatenatableRelationship"
accessors ="true"
{

/**
* The pivot table name between relationships.
Expand Down Expand Up @@ -700,4 +704,43 @@ component extends="quick.models.Relationships.BaseRelationship" accessors="true"
} );
}

public struct function appendToDeepRelationship(
required array through,
required array foreignKeys,
required array localKeys,
required numeric position
) {
arguments.through.append( variables.table );

if ( variables.foreignPivotKeys.len() == 1 ) {
arguments.foreignKeys.append( variables.foreignPivotKeys, true );
} else {
arguments.foreignKeys.append( variables.foreignPivotKeys );
}

if ( variables.relatedKeys.len() == 1 ) {
arguments.foreignKeys.append( variables.relatedKeys, true );
} else {
arguments.foreignKeys.append( variables.relatedKeys );
}

if ( variables.parentKeys.len() == 1 ) {
arguments.localKeys.append( variables.parentKeys, true );
} else {
arguments.localKeys.append( variables.parentKeys );
}

if ( variables.relatedPivotKeys.len() == 1 ) {
arguments.localKeys.append( variables.relatedPivotKeys, true );
} else {
arguments.localKeys.append( variables.relatedPivotKeys );
}

return {
"through" : arguments.through,
"foreignKeys" : arguments.foreignKeys,
"localKeys" : arguments.localKeys
};
}

}
Loading

0 comments on commit 1af491a

Please sign in to comment.