Skip to content

Commit

Permalink
feat(Relationships): Add additional fetch methods to all relationships
Browse files Browse the repository at this point in the history
Adds `firstOrNew`, `firstOrCreate`, `firstWhere`, `findOrNew`, and `findOrCreate`.
  • Loading branch information
elpete committed May 31, 2024
1 parent b1212de commit 9709b2f
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
102 changes: 102 additions & 0 deletions models/Relationships/BaseRelationship.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,67 @@ component accessors="true" implements="IRelationship" {
return variables.relationshipBuilder.firstOrFail();
}

/**
* Gets the first matching record for the relationship or returns an unloaded entity
*
* @attributes A struct of attributes to restrict the query. If no entity is
* found the attributes are filled on the new entity returned.
* @newAttributes A struct of attributes to fill on the new entity if no entity
* is found. These attributes are combined with `attributes`.
* @ignoreNonExistentAttributes If true, does not throw an exception if an
* attribute does not exist. Instead, it skips
* the non-existent attribute.
*
* @return quick.models.BaseEntity
*/
public any function firstOrNew(
struct attributes = {},
struct newAttributes = {},
boolean ignoreNonExistentAttributes = false
) {
return variables.relationshipBuilder.firstOrNew( argumentCollection = arguments );
}

/**
* Finds the first matching record for the relationship or creates a new entity.
*
* @attributes A struct of attributes to restrict the query. If no entity is
* found the attributes are filled on the new entity created.
* @newAttributes A struct of attributes to fill on the created entity if no entity
* is found. These attributes are combined with `attributes`.
* @ignoreNonExistentAttributes If true, does not throw an exception if an
* attribute does not exist. Instead, it skips
* the non-existent attribute.
*
* @return quick.models.BaseEntity
*/
public any function firstOrCreate(
struct attributes = {},
struct newAttributes = {},
boolean ignoreNonExistentAttributes = false
) {
return variables.relationshipBuilder.firstOrCreate( argumentCollection = arguments );
}

/**
* Adds a basic where clause to the relationship query and returns the first result.
*
* @column The name of the column with which to constrain the query. A closure can be passed to begin a nested where statement.
* @operator The operator to use for the constraint (i.e. "=", "<", ">=", etc.). A value can be passed as the `operator` and the `value` left null as a shortcut for equals (e.g. where( "column", 1 ) == where( "column", "=", 1 ) ).
* @value The value with which to constrain the column. An expression (`builder.raw()`) can be passed as well.
* @combinator The boolean combinator for the clause (e.g. "and" or "or"). Default: "and"
*
* @return quick.models.BaseEntity
*/
public any function firstWhere(
any column,
any operator,
any value,
string combinator = "and"
) {
return variables.relationshipBuilder.firstWhere( argumentCollection = arguments );
}

/**
* Finds the first matching record with a given id for the relationship.
* Returns null if no record is found.
Expand All @@ -178,6 +239,47 @@ component accessors="true" implements="IRelationship" {
return variables.relationshipBuilder.findOrFail( arguments.id );
}

/**
* Returns the related entity with the id value as the primary key.
* If no record is found, it returns a new unloaded entity.
*
* @id The id value to find.
* @attributes A struct of attributes to fill on the new entity if no entity is found.
* @ignoreNonExistentAttributes If true, does not throw an exception if an
* attribute does not exist. Instead, it skips
* the non-existent attribute.
*
* @return quick.models.BaseEntity
*/
public any function findOrNew(
required any id,
struct attributes = {},
boolean ignoreNonExistentAttributes = false
) {
return variables.relationshipBuilder.findOrNew( argumentCollection = arguments );
}

/**
* Returns the related entity with the id value as the primary key.
* If no record is found, it returns a newly created entity.
*
* @id The id value to find.
* @attributes A struct of attributes to use when creating the new entity
* if no entity is found.
* @ignoreNonExistentAttributes If true, does not throw an exception if an
* attribute does not exist. Instead, it skips
* the non-existent attribute.
*
* @return quick.models.BaseEntity
*/
public any function findOrCreate(
required any id,
struct attributes = {},
boolean ignoreNonExistentAttributes = false
) {
return variables.relationshipBuilder.findOrCreate( argumentCollection = arguments );
}

/**
* Returns all results for the related entity.
* Note: `all` resets any query restrictions, including relationship restrictions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,47 @@ component extends="tests.resources.ModuleIntegrationSpec" {
expect( postQuery.result.sqlparameters ).toBe( [ 321, 523526 ] );
} );
} );

it( "can call fetch methods on the relationship builder", () => {
var elpete = getInstance( "User" ).findOrFail( 1 );
var elpeteFavoritePost = elpete.favoritePost().first();
expect( elpeteFavoritePost ).notToBeNull();
expect( elpeteFavoritePost ).toBeInstanceOf( "Post" );
expect( elpeteFavoritePost.isLoaded() ).toBeTrue();
expect( elpeteFavoritePost.getPost_Pk() ).toBe( 1245 );

var johndoe = getInstance( "User" ).findOrFail( 2 );
expect( johndoe.favoritePost().first() ).toBeNull();

var janedoe = getInstance( "User" ).findOrFail( 3 );
var janedoeFavoritePost = janedoe.favoritePost().firstOrNew();
expect( janedoeFavoritePost ).notToBeNull();
expect( janedoeFavoritePost ).toBeInstanceOf( "Post" );
expect( janedoeFavoritePost.isLoaded() ).toBeFalse();

var elpete2 = getInstance( "User" ).findOrFail( 4 );
var elpete2FavoritePost = elpete2
.favoritePost()
.firstOrCreate( { "user_id" : 4, "body" : "test body" } );
expect( elpete2FavoritePost ).notToBeNull();
expect( elpete2FavoritePost ).toBeInstanceOf( "Post" );
expect( elpete2FavoritePost.isLoaded() ).toBeTrue();
expect( elpete2FavoritePost.getUser_Id() ).toBe( 4 );
expect( elpete2FavoritePost.getBody() ).toBe( "test body" );
} );

it( "can call exists methods on a relationship class", () => {
var elpete = getInstance( "User" ).findOrFail( 1 );
expect( elpete.favoritePost().exists() ).toBeTrue();

var johndoe = getInstance( "User" ).findOrFail( 2 );
expect( johndoe.favoritePost().exists() ).toBeFalse();

expect( function() {
var janedoe = getInstance( "User" ).findOrFail( 3 );
janedoe.favoritePost().existsOrFail();
} ).toThrow( type = "EntityNotFound" );
} );
} );
}

Expand Down

0 comments on commit 9709b2f

Please sign in to comment.