Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion models/BaseEntity.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -2602,10 +2602,14 @@ component accessors="true" {

var relationshipName = variables._str.slice( arguments.missingMethodName, 4 );

if ( !hasRelationship( relationshipName ) ) {
if ( !hasRelationship( relationshipName ) && !isRelationshipLoaded( relationshipName ) ) {
return;
}

if ( isRelationshipLoaded( relationshipName ) ) {
return retrieveRelationship( relationshipName );
}

if ( !isRelationshipLoaded( relationshipName ) && variables._preventLazyLoading ) {
variables._lazyLoadingViolationCallback( this, relationshipName );
}
Expand Down
38 changes: 38 additions & 0 deletions models/QuickBuilder.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ component accessors="true" transientCache="false" {
property name="_asMemento" default="false";
property name="_asMementoSettings";

/**
* Callbacks applied to each hydrated entity before return transformations.
*/
property name="_entityTransformers";

/**
* Used to quickly identify QueryBuilder instances
* instead of resorting to `isInstanceOf` which is slow.
Expand All @@ -94,6 +99,7 @@ component accessors="true" transientCache="false" {
variables._asMemento = false;
variables._asQuery = false;
variables._withAliases = false;
variables._entityTransformers = [];
param variables._preventLazyLoading = false;
if ( !variables.keyExists( "_lazyLoadingViolationCallback" ) || isNull( variables._lazyLoadingViolationCallback ) ) {
variables._lazyLoadingViolationCallback = ( entity, relationName ) => {
Expand All @@ -109,6 +115,18 @@ component accessors="true" transientCache="false" {
return this;
}

/**
* Adds a callback that transforms each hydrated entity before it is returned.
*
* @transformer The callback accepting and returning an entity.
*
* @return quick.models.QuickBuilder
*/
public QuickBuilder function addEntityTransformer( required any transformer ) {
variables._entityTransformers.append( arguments.transformer );
return this;
}

function onDIComplete() {
variables.qb.setQuickBuilder( this );
variables.qb.setColumnFormatter( function( column ) {
Expand Down Expand Up @@ -1489,6 +1507,16 @@ component accessors="true" transientCache="false" {
* @return any
*/
private any function handleTransformations( entity ) {
if ( !variables._asQuery ) {
if ( isArray( arguments.entity ) ) {
arguments.entity = arguments.entity.map( function( item ) {
return applyEntityTransformers( arguments.item );
} );
} else if ( !isNull( arguments.entity ) ) {
arguments.entity = applyEntityTransformers( arguments.entity );
}
}

if ( !variables._asMemento ) {
return arguments.entity;
}
Expand All @@ -1502,6 +1530,15 @@ component accessors="true" transientCache="false" {
} );
}

/**
* Applies all configured entity transformers to one hydrated entity.
*/
private any function applyEntityTransformers( required any entity ) {
return variables._entityTransformers.reduce( function( transformed, transformer ) {
return arguments.transformer( arguments.transformed );
}, arguments.entity );
}

/**
* Activates the global scopes while checking for excluded global scopes.
*
Expand Down Expand Up @@ -1741,6 +1778,7 @@ component accessors="true" transientCache="false" {
newBuilder.set_withAliases( this.get_withAliases() );
newBuilder.set_asMemento( this.get_asMemento() );
newBuilder.set_asMementoSettings( this.get_asMementoSettings() );
newBuilder.set_entityTransformers( this.get_entityTransformers() );
return newBuilder;
}

Expand Down
Loading
Loading