Skip to content

Commit

Permalink
Merge pull request #648 from fbarthez/ERXSQLQueryWithBindingsUtilities
Browse files Browse the repository at this point in the history
Additional documentation for ERXSQLQueryWithBindingsUtilities
  • Loading branch information
darkv committed May 19, 2015
2 parents cb70065 + 0e14de6 commit 377416c
Showing 1 changed file with 54 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Enumeration;

import com.webobjects.eoaccess.EOAdaptorChannel;
import com.webobjects.eoaccess.EOAttribute;
import com.webobjects.eoaccess.EODatabaseChannel;
import com.webobjects.eoaccess.EODatabaseContext;
import com.webobjects.eoaccess.EOEntity;
Expand All @@ -18,10 +19,50 @@
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;


/**
* This class allows SQL queries with binded variables to be run against the database. It's possible
* to obtain EOs or raw rows, depending on the used method.
* to obtain EOs, raw rows or a batch iterator, depending on the used method.
* <p>
* Binded values are passed in using {@link ERXSQLBinding} implementations. Currently, there are two available
* implementations: {@link ERXKeyValueBinding} and {@link ERXObjectBinding}. The first one should be used if
* the binding matches a column modeled in an EOModel. This way, any data type conversions that would happen
* on normal EOF usage are also applied when generating the SQL query. An example of this can be converting a
* boolean value to a string or an integer. {@link ERXObjectBinding} can be used for non-modeled columns.
* Please read the {@link ERXObjectBinding} class documentation for important notes regarding some databases
* that expect SQL queries with binding typification.
* </p>
* <p>
* This class is used by calling the most appropriate static method for the intended usage. Specific requirements
* for the SQL query resulting columns are detailed on each of the method's documentation. Generally, you need
* to provide a query returning the appropriate columns and using the '?' character for each binded value.
* Depending on the database plug-in being used, the '?' character will be automatically replaced by a different
* expression if the {@link ERXKeyValueBinding} class is used to wrap the binded value. In PostgreSQL, for instance,
* the '?' character could be replaced by '?::varchar(1000)'.
* </p>
* <p>
* Here are some sample uses of this class:
* </p>
* <pre>
* // Obtains EOs that match the query
* ERXSQLQueryWithBindingsUtilities.selectObjectsOfEntityForSqlWithBindings(editingContext(), Song.ENTITY_NAME,
* "SELECT * FROM SONG WHERE FAVORITE = ? AND DURATION > ? ORDER BY NUMBER ASC", true,
* new ERXKeyValueBinding("favorite", true), new ERXKeyValueBinding("duration", 120));
*
* // Obtains raw rows for query
* ERXSQLQueryWithBindingsUtilities.rawRowsForSqlWithBindings(editingContext(), Song.ENTITY_NAME,
* "SELECT t0.NAME, t0.DURATION FROM SONG t0 WHERE COMPOSER = ?", new ERXKeyValueBinding("composer", "Mozart"));
*
* // Runs a query that returns no objects
* ERXSQLQueryWithBindingsUtilities.runSqlQueryWithBindings(editingContext(), "SongsModel",
* "DELETE FROM SONG WHERE FAVORITE = ?", new ERXKeyValueBinding("favorite", false));
*
* // Obtains ERXFetchSpecificationBatchIterator
* // Note the query must obtain the primary key!
* ERXSQLQueryWithBindingsUtilities.batchIteratorForObjectsWithSqlWithBindings(editingContext(), Employee.ENTITY_NAME,
* "SELECT ID FROM EMPLOYEE WHERE HEIGHT < ? AND FIRST_NAME = ? ORDER BY NUMBER DESC", false, 100,
* new NSArray<EOSortOrdering>(new EOSortOrdering[] {new EOSortOrdering("number", EOSortOrdering.CompareDescending)}),
* new ERXObjectBinding(190), new ERXKeyValueBinding("firstName", "John"));
* </pre>
*/
public class ERXSQLQueryWithBindingsUtilities {

Expand Down Expand Up @@ -178,7 +219,7 @@ public static ERXFetchSpecificationBatchIterator batchIteratorForObjectsWithSqlW

NSArray pkDicts = ec.objectsWithFetchSpecification(pkSpec);
NSMutableArray pks = new NSMutableArray();
String pkAtttributeName = entity.primaryKeyAttributes().lastObject().name();
String pkAtttributeName = ((EOAttribute) entity.primaryKeyAttributes().lastObject()).name();

for ( Enumeration rowEnumerator = pkDicts.objectEnumerator(); rowEnumerator.hasMoreElements(); ) {
NSDictionary row = (NSDictionary) rowEnumerator.nextElement();
Expand All @@ -201,8 +242,7 @@ public static ERXFetchSpecificationBatchIterator batchIteratorForObjectsWithSqlW
* @param ec
* The current editing context (used to obtain the correct OSC)
* @param modelName
* The name of a model affected by the query. This does not necessarily have to be accurate,
* as this value is only used to find out the correct database that the query will be run against.
* The name of the model (used to apply the query on the correct DB)
* @param query
* The SQL query
* @param bindings
Expand Down Expand Up @@ -292,7 +332,7 @@ public static NSArray rawRowsForSqlWithBindings( EOEditingContext ec, String ent
protected static String processedQueryString(String query, EOSQLExpression expression, ERXSQLBinding... bindings) {
int currentOffset = 0;
int bindingCount = 0;
StringBuilder processedQueryBuffer = new StringBuilder();
StringBuffer processedQueryBuffer = new StringBuffer();
NSArray positions = varPositionsForQuery( query );

if( positions.count() != bindings.length ) {
Expand Down Expand Up @@ -365,10 +405,11 @@ private static NSArray varPositionsForQuery(String query) {
private static EODatabaseContext databaseContextForEntityName( EOEditingContext ec, String entityName ) {
EOModelGroup group = EOUtilities.modelGroup( ec );
EOModel model = group.entityNamed(entityName).model();
if (model == null) {
if( model != null ) {
return EODatabaseContext.registeredDatabaseContextForModel(model, ec);
} else {
throw new RuntimeException("Entity named " + entityName + " not found in the model group.");
}
return EODatabaseContext.registeredDatabaseContextForModel(model, ec);
}

/**
Expand All @@ -383,9 +424,12 @@ private static EODatabaseContext databaseContextForEntityName( EOEditingContext
private static EODatabaseContext databaseContextForModelName(EOEditingContext ec, String modelName) {
EOModelGroup group = EOUtilities.modelGroup( ec );
EOModel model = group.modelNamed(modelName);
if (model == null) {
if( model != null ) {
return EODatabaseContext.registeredDatabaseContextForModel(model, ec);
} else {
throw new RuntimeException("Model " + modelName + " not found in the model group.");
}
return EODatabaseContext.registeredDatabaseContextForModel(model, ec);
}


}

0 comments on commit 377416c

Please sign in to comment.