Skip to content

Commit

Permalink
EntityLoad - Work on filter, option support for entityLoad
Browse files Browse the repository at this point in the history
This is still not fully working - the criteria list returns an array of empty/null results, which is odd. Need to look into this.
  • Loading branch information
michaelborn committed Jan 6, 2025
1 parent d228e24 commit 216e0a7
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 16 deletions.
32 changes: 30 additions & 2 deletions src/main/java/ortus/boxlang/modules/orm/ORMApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
import org.hibernate.metadata.ClassMetadata;

import ortus.boxlang.modules.orm.config.ORMConfig;
import ortus.boxlang.modules.orm.config.ORMKeys;
import ortus.boxlang.modules.orm.mapping.EntityRecord;
import ortus.boxlang.modules.orm.mapping.MappingGenerator;
import ortus.boxlang.runtime.BoxRuntime;
import ortus.boxlang.runtime.context.IBoxContext;
import ortus.boxlang.runtime.context.IJDBCCapableContext;
import ortus.boxlang.runtime.context.RequestBoxContext;
import ortus.boxlang.runtime.dynamic.casters.BooleanCaster;
import ortus.boxlang.runtime.dynamic.casters.GenericCaster;
import ortus.boxlang.runtime.jdbc.ConnectionManager;
import ortus.boxlang.runtime.jdbc.DataSource;
Expand Down Expand Up @@ -253,8 +255,9 @@ public IClassRunnable loadEntityById( RequestBoxContext context, String entityNa
* @param context Context in which the BIF was invoked.
* @param entityName The name of the entity to load.
* @param filter Struct of filter criteria.
* @param options Struct of options, including maxResults, offset, order, etc.
*/
public Array loadEntitiesByFilter( RequestBoxContext context, String entityName, IStruct filter ) {
public Array loadEntitiesByFilter( RequestBoxContext context, String entityName, IStruct filter, IStruct options ) {
EntityRecord entityRecord = this.lookupEntity( entityName, true );
Session session = ORMRequestContext.getForContext( context ).getSession( entityRecord.getDatasource() );

Expand All @@ -266,8 +269,33 @@ public Array loadEntitiesByFilter( RequestBoxContext context, String entityName,
}
}

if ( options.containsKey( ORMKeys.cacheable ) ) {
criteria.setCacheable( BooleanCaster.cast( options.get( ORMKeys.cacheable ) ) );
}
if ( options.containsKey( Key.timeout ) ) {
Integer timeout = options.getAsInteger( Key.timeout );
if ( timeout != null ) {
criteria.setTimeout( timeout );
}
}
if ( options.containsKey( ORMKeys.maxResults ) ) {
Integer maxResults = options.getAsInteger( ORMKeys.maxResults );
if ( maxResults != null ) {
criteria.setMaxResults( maxResults );
}
}
if ( options.containsKey( Key.offset ) ) {
Integer offset = options.getAsInteger( Key.offset );
if ( offset != null && offset > 0 ) {
criteria.setFirstResult( offset );
}
}

// @TODO: Order.

List results = criteria.list();
return Array.of(
criteria.list()
results
.stream()
.map( entity -> ( IClassRunnable ) entity )
.toArray()
Expand Down
69 changes: 56 additions & 13 deletions src/main/java/ortus/boxlang/modules/orm/bifs/EntityLoad.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,31 @@
import ortus.boxlang.runtime.types.Argument;
import ortus.boxlang.runtime.types.Array;
import ortus.boxlang.runtime.types.IStruct;
import ortus.boxlang.runtime.types.Struct;

@BoxBIF
public class EntityLoad extends BaseORMBIF {

/**
* Default options for loading entities.
*/
private final IStruct DEFAULT_OPTIONS = Struct.of(
// Specifies whether to retrieve a single, unique item. Default is false.
"unique", Boolean.FALSE,
// Ignores the case of sort order when set to true. Use only if you specify the sortorder parameter.
"ignorecase", Boolean.FALSE,
// Specifies the position from which to retrieve the objects.
"offset", 0,
// Specifies the maximum number of objects to be retrieved.
"maxresults", null,
// Whether the result has to be cached in the secondary cache. Default is false.
"cacheable", Boolean.FALSE,
// Name of the cache in secondary cache.
"cachename", null,
// Specifies the timeout value (in seconds) for the query.
"timeout", null
);

/**
* Constructor
*/
Expand All @@ -50,15 +71,14 @@ public EntityLoad() {
* @param arguments Argument scope for the BIF.
*/
public Object _invoke( IBoxContext context, ArgumentsScope arguments ) {
if ( !arguments.containsKey( ORMKeys.idOrFilter ) ) {
// No filter or ID provided, load all entities as an array.
return loadEntitiesByFilter( context, arguments );
if ( arguments.containsKey( ORMKeys.idOrFilter ) ) {
boolean idIsSimpleValue = StringCaster.attempt( arguments.get( ORMKeys.idOrFilter ) ).wasSuccessful();
if ( idIsSimpleValue ) {
return loadEntityById( context, arguments );
}
}
boolean idIsSimpleValue = StringCaster.attempt( arguments.get( ORMKeys.idOrFilter ) ).wasSuccessful();
if ( idIsSimpleValue ) {
return loadEntityById( context, arguments );
}
// assume struct filter...
// EITHER: No filter or was ID provided, so load all entities as an array...
// OR a non-simple value was provided (i.e. a struct or array), so load by filter.
return loadEntitiesByFilter( context, arguments );
}

Expand All @@ -85,11 +105,34 @@ private Object loadEntityById( IBoxContext context, ArgumentsScope arguments ) {
* @param arguments Arguments scope of the BIF.
*/
private Object loadEntitiesByFilter( IBoxContext context, ArgumentsScope arguments ) {
IStruct filter = arguments.containsKey( ORMKeys.idOrFilter ) ? arguments.getAsStruct( ORMKeys.idOrFilter ) : null;
if ( BooleanCaster.cast( arguments.getOrDefault( ORMKeys.uniqueOrOrder, "false" ) ) ) {
// @TODO: Unique is true; return a single entity.
return null;
IStruct options = buildCriteriaOptions( arguments );
IStruct filter = arguments.getAsStruct( ORMKeys.idOrFilter );

Array results = this.ormApp.loadEntitiesByFilter( context.getRequestContext(), arguments.getAsString( ORMKeys.entityName ), filter, options );
if ( options.getAsBoolean( ORMKeys.unique ) ) {
return results.isEmpty() ? null : results.getFirst();
}
return results;
}

private IStruct buildCriteriaOptions( ArgumentsScope arguments ) {
IStruct options = Struct.of();
options.putAll( DEFAULT_OPTIONS );
if ( arguments.containsKey( ORMKeys.options ) && arguments.get( ORMKeys.options ) != null ) {
options.putAll( arguments.getAsStruct( ORMKeys.options ) );
}
if ( arguments.containsKey( ORMKeys.uniqueOrOrder ) ) {
Object uniqueOrOrder = arguments.get( ORMKeys.uniqueOrOrder );
if ( uniqueOrOrder instanceof String ) {
options.put( "order", uniqueOrOrder );
} else {
boolean unique = BooleanCaster.cast( uniqueOrOrder );
if ( unique ) {
options.put( "unique", Boolean.TRUE );
options.put( "maxresults", 1 );
}
}
}
return this.ormApp.loadEntitiesByFilter( context.getRequestContext(), arguments.getAsString( ORMKeys.entityName ), filter );
return options;
}
}
2 changes: 2 additions & 0 deletions src/main/java/ortus/boxlang/modules/orm/config/ORMKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ public class ORMKeys {
public static final Key idOrFilter = Key.of( "idOrFilter" );
public static final Key uniqueOrOrder = Key.of( "uniqueOrOrder" );
public static final Key options = Key.of( "options" );
public static final Key maxResults = Key.of( "maxResults" );
public static final Key cacheable = Key.of( "cacheable" );

/**
* ORM event keys
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void testEntityLoadFilterUnique() {
// @formatter:on
assertThat( variables.get( result ) ).isNotNull();
assertThat( variables.get( result ) ).isInstanceOf( IClassRunnable.class );
assertThat( ( ( IClassRunnable ) variables.get( result ) ).get( "vin" ) ).isEqualTo( "load" );
assertThat( ( ( IClassRunnable ) variables.get( result ) ).get( "vin" ) ).isEqualTo( "1HGCM82633A123456" );
}

@Disabled( "Unimplemented" )
Expand Down

0 comments on commit 216e0a7

Please sign in to comment.