Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for ranged fetch specifications #385

Merged
merged 4 commits into from
Feb 12, 2013
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
Original file line number Diff line number Diff line change
Expand Up @@ -686,22 +686,26 @@ public static <T extends EOEnterpriseObject> NSArray<T> objectsInRange(EOEditing

/**
* Returns an {@link com.webobjects.foundation.NSArray NSArray} containing the primary keys from the resulting rows starting
* at start and stopping at end using a custom SQL, derived from the SQL
* at <i>start</i> and stopping at <i>end</i> using a custom SQL, derived from the SQL
* which the {@link com.webobjects.eocontrol.EOFetchSpecification EOFetchSpecification} would use normally {@link com.webobjects.eocontrol.EOFetchSpecification#setHints(NSDictionary) setHints()}
*
* @param ec editing context to fetch objects into
* @param spec fetch specification for the fetch
* @param start
* @param end
* @param start the starting row number
* @param end the last row number
*
* @return primary keys in the given range
*/
public static NSArray primaryKeyValuesInRange(EOEditingContext ec, EOFetchSpecification spec, int start, int end) {
public static NSArray<NSDictionary<String, Object>> primaryKeyValuesInRange(EOEditingContext ec, EOFetchSpecification spec, int start, int end) {
EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, spec.entityName());
NSArray<String> pkNames = entity.primaryKeyAttributeNames();
spec.setFetchesRawRows(true);
spec.setRawRowKeyPaths(pkNames);
EOFetchSpecification clonedFetchSpec = (EOFetchSpecification)spec.clone();
EOFetchSpecification clonedFetchSpec = (EOFetchSpecification)spec.clone();
clonedFetchSpec.setFetchesRawRows(true);
clonedFetchSpec.setRawRowKeyPaths(pkNames);
if (clonedFetchSpec instanceof ERXFetchSpecification) {
// remove any range setting as we will explicitly set start and end limit
((ERXFetchSpecification)clonedFetchSpec).setFetchRange(null);
}
EOSQLExpression sql = ERXEOAccessUtilities.sqlExpressionForFetchSpecification(ec, clonedFetchSpec, start, end);
NSDictionary<String, EOSQLExpression> hints = new NSDictionary<String, EOSQLExpression>(sql, EODatabaseContext.CustomQueryExpressionHintKey);
clonedFetchSpec.setHints(hints);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.sql.Blob;
import java.sql.Clob;
Expand All @@ -22,6 +23,8 @@
import com.webobjects.eoaccess.synchronization.EOSchemaGenerationOptions;
import com.webobjects.eoaccess.synchronization.EOSchemaSynchronization;
import com.webobjects.eoaccess.synchronization.EOSchemaSynchronizationFactory;
import com.webobjects.eocontrol.EOFetchSpecification;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSBundle;
import com.webobjects.foundation.NSData;
Expand All @@ -32,6 +35,8 @@
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSMutableSet;
import com.webobjects.foundation.NSPropertyListSerialization;
import com.webobjects.foundation.NSRange;
import com.webobjects.foundation.NSSelector;
import com.webobjects.foundation.NSTimestamp;
import com.webobjects.foundation._NSStringUtilities;

Expand Down Expand Up @@ -141,6 +146,16 @@ public Object fetchCLOB(ResultSet rs, int column, EOAttribute attribute, boolean
}

public static class H2Expression extends JDBCExpression {
/**
* Fetch spec limit ivar
*/
private int _fetchLimit;

/**
* Fetch spec range ivar
*/
private NSRange _fetchRange;
private final NSSelector<NSRange> _fetchRangeSelector = new NSSelector<NSRange>("fetchRange");

public H2Expression(final EOEntity entity) {
super(entity);
Expand Down Expand Up @@ -308,6 +323,98 @@ private boolean isDateAttribute(final EOAttribute eoattribute) {
private boolean isTimestampAttribute(final EOAttribute eoattribute) {
return eoattribute != null && "T".equals(eoattribute.valueType());
}

/**
* Overridden so we can get the fetch limit from the fetchSpec.
*
* @param attributes the array of attributes
* @param lock locking flag
* @param fetchSpec the fetch specification
*/
@Override
public void prepareSelectExpressionWithAttributes(NSArray<EOAttribute> attributes, boolean lock, EOFetchSpecification fetchSpec) {
try {
_fetchRange = _fetchRangeSelector.invoke(fetchSpec);
// We will get an error when not using our custom ERXFetchSpecification subclass
// We could have added ERExtensions to the classpath and checked for instanceof, but I thought
// this is a little cleaner since people may be using this PlugIn and not Wonder in some legacy apps.
} catch (IllegalArgumentException e) {
// ignore
} catch (IllegalAccessException e) {
// ignore
} catch (InvocationTargetException e) {
// ignore
} catch (NoSuchMethodException e) {
// ignore
}
// Only check for fetchLimit if fetchRange is not provided.
if (_fetchRange == null && !fetchSpec.promptsAfterFetchLimit()) {
_fetchLimit = fetchSpec.fetchLimit();
}
if (_fetchRange != null) {
// if we have a fetch range disable the limit
fetchSpec.setFetchLimit(0);
}
super.prepareSelectExpressionWithAttributes(attributes, lock, fetchSpec);
}

@Override
public String assembleSelectStatementWithAttributes(NSArray attributes, boolean lock, EOQualifier qualifier, NSArray fetchOrder, String selectString, String columnList, String tableList, String whereClause, String joinClause, String orderByClause, String lockClause) {
int size = selectString.length() + columnList.length() + tableList.length() + 7;
if (lockClause != null && lockClause.length() != 0) {
size += lockClause.length() + 1;
}
if (whereClause != null && whereClause.length() != 0) {
size += whereClause.length() + 7;
}
if (joinClause != null && joinClause.length() != 0) {
size += joinClause.length() + 7;
}
if (orderByClause != null && orderByClause.length() != 0) {
size += orderByClause.length() + 10;
}
StringBuilder sb = new StringBuilder(size);
sb.append(selectString);
sb.append(columnList);
sb.append(" FROM ");
sb.append(tableList);

if (whereClause != null && whereClause.length() != 0) {
sb.append(" WHERE ");
sb.append(whereClause);
}
if (joinClause != null && joinClause.length() != 0) {
if (whereClause != null && whereClause.length() != 0) {
sb.append(" AND ");
} else {
sb.append(" WHERE ");
}
sb.append(joinClause);
}

if (orderByClause != null && orderByClause.length() != 0) {
sb.append(" ORDER BY ");
sb.append(orderByClause);
}

// fetchRange overrides fetchLimit
if (_fetchRange != null) {
sb.append(" LIMIT ");
sb.append(_fetchRange.length());
sb.append(" OFFSET ");
sb.append(_fetchRange.location());
} else if (_fetchLimit != 0) {
sb.append(" LIMIT ");
sb.append(_fetchLimit);
}

if (lockClause != null && lockClause.length() != 0) {
sb.append(' ');
sb.append(lockClause);
}

return sb.toString();
}
}

public static class H2SynchronizationFactory extends EOSchemaSynchronizationFactory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSRange;
import com.webobjects.foundation.NSSelector;
import com.webobjects.foundation.NSTimestamp;
import com.webobjects.foundation._NSStringUtilities;
Expand Down Expand Up @@ -113,7 +114,13 @@ protected SimpleDateFormat initialValue() {
* Fetch spec limit ivar
*/
private int _fetchLimit;


/**
* Fetch spec range ivar
*/
private NSRange _fetchRange;
private final NSSelector<NSRange> _fetchRangeSelector = new NSSelector<NSRange>("fetchRange");

private Boolean _enableIdentifierQuoting;

private Boolean _enableBooleanQuoting;
Expand Down Expand Up @@ -378,10 +385,16 @@ public String assembleSelectStatementWithAttributes(NSArray attributes,
sb.append(" ");
sb.append(lockClause);
}
if (_fetchLimit != 0) {
// fetchRange overrides fetchLimit
if (_fetchRange != null) {
sb.append(" LIMIT ");
sb.append(_fetchRange.length());
sb.append(" OFFSET ");
sb.append(_fetchRange.location());
} else if (_fetchLimit != 0) {
sb.append(" LIMIT ");
sb.append(_fetchLimit);
}
}
return sb.toString();
}

Expand Down Expand Up @@ -726,16 +739,35 @@ private String quoteIdentifier(String identifier) {
/**
* Overridden so we can get the fetch limit from the fetchSpec.
*
* @param attributes the array of attributes
* @param lock locking flag
* @param eofetchspecification the fetch specification
* @param attributes the array of attributes
* @param lock locking flag
* @param fetchSpec the fetch specification
*/
@Override
public void prepareSelectExpressionWithAttributes(NSArray<EOAttribute> attributes, boolean lock, EOFetchSpecification eofetchspecification) {
if(!eofetchspecification.promptsAfterFetchLimit()) {
_fetchLimit = eofetchspecification.fetchLimit();
public void prepareSelectExpressionWithAttributes(NSArray<EOAttribute> attributes, boolean lock, EOFetchSpecification fetchSpec) {
try {
_fetchRange = _fetchRangeSelector.invoke(fetchSpec);
// We will get an error when not using our custom ERXFetchSpecification subclass
// We could have added ERExtensions to the classpath and checked for instanceof, but I thought
// this is a little cleaner since people may be using this PlugIn and not Wonder in some legacy apps.
} catch (IllegalArgumentException e) {
// ignore
} catch (IllegalAccessException e) {
// ignore
} catch (InvocationTargetException e) {
// ignore
} catch (NoSuchMethodException e) {
// ignore
}
// Only check for fetchLimit if fetchRange is not provided.
if (_fetchRange == null && !fetchSpec.promptsAfterFetchLimit()) {
_fetchLimit = fetchSpec.fetchLimit();
}
if (_fetchRange != null) {
// if we have a fetch range disable the limit
fetchSpec.setFetchLimit(0);
}
super.prepareSelectExpressionWithAttributes(attributes, lock, eofetchspecification);
super.prepareSelectExpressionWithAttributes(attributes, lock, fetchSpec);
}

/**
Expand Down