use of org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty in project spring-cloud-gcp by spring-cloud.
the class SpannerStatementQueryExecutor method buildWhere.
private static void buildWhere(PartTree tree, SpannerPersistentEntity<?> persistentEntity, List<String> tags, StringBuilder stringBuilder) {
if (tree.hasPredicate()) {
stringBuilder.append("WHERE ");
StringJoiner orStrings = new StringJoiner(" OR ");
tree.iterator().forEachRemaining((orPart) -> {
String orString = "( ";
StringJoiner andStrings = new StringJoiner(" AND ");
orPart.forEach((part) -> {
String segment = part.getProperty().getSegment();
String tag = "tag" + tags.size();
tags.add(tag);
SpannerPersistentProperty spannerPersistentProperty = persistentEntity.getPersistentProperty(segment);
if (spannerPersistentProperty.isEmbedded()) {
throw new SpannerDataException("Embedded class properties are not currently supported in query method names: " + segment);
}
String andString = spannerPersistentProperty.getColumnName();
String insertedTag = "@" + tag;
if (part.shouldIgnoreCase() == IgnoreCaseType.ALWAYS) {
andString = "LOWER(" + andString + ")";
insertedTag = "LOWER(" + insertedTag + ")";
} else if (part.shouldIgnoreCase() != IgnoreCaseType.NEVER) {
throw new SpannerDataException("Only ignore-case types ALWAYS and NEVER are supported, " + "because the underlying table schema is not retrieved at query time to" + " check that the column is the STRING or BYTES Cloud Spanner " + " type supported for ignoring case.");
}
switch(part.getType()) {
case LIKE:
andString += " LIKE " + insertedTag;
break;
case NOT_LIKE:
andString += " NOT LIKE " + insertedTag;
break;
case CONTAINING:
andString = " REGEXP_CONTAINS(" + andString + "," + insertedTag + ") =TRUE";
break;
case NOT_CONTAINING:
andString = " REGEXP_CONTAINS(" + andString + "," + insertedTag + ") =FALSE";
break;
case SIMPLE_PROPERTY:
andString += "=" + insertedTag;
break;
case TRUE:
andString += "=TRUE";
break;
case FALSE:
andString += "=FALSE";
break;
case IS_NULL:
andString += "=NULL";
break;
case LESS_THAN:
andString += "<" + insertedTag;
break;
case IS_NOT_NULL:
andString += "<>NULL";
break;
case LESS_THAN_EQUAL:
andString += "<=" + insertedTag;
break;
case GREATER_THAN:
andString += ">" + insertedTag;
break;
case GREATER_THAN_EQUAL:
andString += ">=" + insertedTag;
break;
case IN:
andString += " IN UNNEST(" + insertedTag + ")";
break;
case NOT_IN:
andString += " NOT IN UNNEST(" + insertedTag + ")";
break;
default:
throw new UnsupportedOperationException("The statement type: " + part.getType() + " is not supported.");
}
andStrings.add(andString);
});
orString += andStrings.toString();
orString += " )";
orStrings.add(orString);
});
stringBuilder.append(combineWithAnd(orStrings.toString(), persistentEntity.getWhere()));
}
}
use of org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty in project spring-cloud-gcp by spring-cloud.
the class SpannerStatementQueryExecutor method buildQuery.
/**
* Builds a query that returns the rows associated with a key set with additional SQL-where.
* The {@link org.springframework.cloud.gcp.data.spanner.core.mapping.Where} of the {@code persistentEntity} parameter
* is ignored, you should pass the SQL-where as a {@code whereClause} parameter.
* The secondary {@code index} will be used instead of the table name when the corresponding parameter is not null.
* @param keySet the key set whose members to get.
* @param persistentEntity the persistent entity of the table.
* @param <T> the type of the persistent entity
* @param writeConverter a converter to convert key values as needed to bind to the query statement.
* @param mappingContext mapping context
* @param whereClause SQL where clause
* @param index the secondary index name
* @return the Spanner statement to perform the retrieval.
*/
public static <T> Statement buildQuery(KeySet keySet, SpannerPersistentEntity<T> persistentEntity, SpannerCustomConverter writeConverter, SpannerMappingContext mappingContext, String whereClause, String index) {
List<String> orParts = new ArrayList<>();
List<String> tags = new ArrayList<>();
List keyParts = new ArrayList();
int tagNum = 0;
List<SpannerPersistentProperty> keyProperties = persistentEntity.getFlattenedPrimaryKeyProperties();
for (Key key : keySet.getKeys()) {
StringJoiner andJoiner = new StringJoiner(" AND ");
Iterator parentKeyParts = key.getParts().iterator();
while (parentKeyParts.hasNext()) {
SpannerPersistentProperty keyProp = keyProperties.get(tagNum % keyProperties.size());
String tagName = "tag" + tagNum;
andJoiner.add(keyProp.getColumnName() + " = @" + tagName);
tags.add(tagName);
keyParts.add(parentKeyParts.next());
tagNum++;
}
orParts.add(andJoiner.toString());
}
String keyClause = orParts.stream().map(s -> "(" + s + ")").collect(Collectors.joining(" OR "));
String condition = combineWithAnd(keyClause, whereClause);
String sb = "SELECT " + getColumnsStringForSelect(persistentEntity, mappingContext, true) + " FROM " + (StringUtils.isEmpty(index) ? persistentEntity.tableName() : String.format("%s@{FORCE_INDEX=%s}", persistentEntity.tableName(), index)) + (condition.isEmpty() ? "" : " WHERE " + condition);
return buildStatementFromSqlWithArgs(sb, tags, null, writeConverter, keyParts.toArray(), null);
}
use of org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty in project spring-cloud-gcp by spring-cloud.
the class ConverterAwareMappingSpannerEntityReader method read.
/**
* Reads a single POJO from a Cloud Spanner row.
* @param type the type of POJO
* @param source the Cloud Spanner row
* @param includeColumns the columns to read. If null then all columns will be read.
* @param allowMissingColumns if true, then properties with no corresponding column are
* not mapped. If false, then an exception is thrown.
* @param <R> the type of the POJO.
* @return the POJO
*/
@SuppressWarnings("unchecked")
public <R> R read(Class<R> type, Struct source, Set<String> includeColumns, boolean allowMissingColumns) {
boolean readAllColumns = includeColumns == null;
SpannerPersistentEntity<R> persistentEntity = (SpannerPersistentEntity<R>) this.spannerMappingContext.getPersistentEntity(type);
StructAccessor structAccessor = new StructAccessor(source);
StructPropertyValueProvider propertyValueProvider = new StructPropertyValueProvider(structAccessor, this.converter, this, allowMissingColumns);
PreferredConstructor<?, SpannerPersistentProperty> persistenceConstructor = persistentEntity.getPersistenceConstructor();
// @formatter:off
ParameterValueProvider<SpannerPersistentProperty> parameterValueProvider = new PersistentEntityParameterValueProvider<>(persistentEntity, propertyValueProvider, null);
// @formatter:on
EntityInstantiator instantiator = this.instantiators.getInstantiatorFor(persistentEntity);
R instance = instantiator.createInstance(persistentEntity, parameterValueProvider);
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(instance);
persistentEntity.doWithProperties((PropertyHandler<SpannerPersistentProperty>) (spannerPersistentProperty) -> {
if (spannerPersistentProperty.isEmbedded()) {
accessor.setProperty(spannerPersistentProperty, read(spannerPersistentProperty.getType(), source, includeColumns, allowMissingColumns));
} else {
if (!shouldSkipProperty(structAccessor, spannerPersistentProperty, includeColumns, readAllColumns, allowMissingColumns, persistenceConstructor)) {
Object value = propertyValueProvider.getPropertyValue(spannerPersistentProperty);
accessor.setProperty(spannerPersistentProperty, value);
}
}
});
return instance;
}
use of org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty in project spring-cloud-gcp by spring-cloud.
the class MappingSpannerReadConverter method read.
/**
* Reads a single POJO from a Spanner row.
* @param type the type of POJO
* @param source the Spanner row
* @param includeColumns the columns to read. If null then all columns will be read.
* @param <R> the type of the POJO.
* @return the POJO
*/
public <R> R read(Class<R> type, Struct source, Set<String> includeColumns) {
boolean readAllColumns = includeColumns == null;
R object = instantiate(type);
SpannerPersistentEntity<?> persistentEntity = this.spannerMappingContext.getPersistentEntity(type);
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(object);
persistentEntity.doWithProperties((PropertyHandler<SpannerPersistentProperty>) spannerPersistentProperty -> {
String columnName = spannerPersistentProperty.getColumnName();
try {
if ((!readAllColumns && !includeColumns.contains(columnName)) || source.isNull(columnName)) {
return;
}
} catch (IllegalArgumentException e) {
throw new SpannerDataException("Unable to read column from Spanner results: " + columnName, e);
}
Class propType = spannerPersistentProperty.getType();
boolean valueSet;
if (ConversionUtils.isIterableNonByteArrayType(propType)) {
valueSet = attemptReadIterableValue(spannerPersistentProperty, source, columnName, accessor);
} else {
Class sourceType = this.spannerColumnTypeToJavaTypeMapping.get(source.getColumnType(columnName));
if (sourceType != null && canConvert(sourceType, propType)) {
valueSet = attemptReadSingleItemValue(spannerPersistentProperty, source, sourceType, columnName, accessor);
} else {
valueSet = false;
}
}
if (!valueSet) {
throw new SpannerDataException(String.format("The value in column with name %s" + " could not be converted to the corresponding property in the entity." + " The property's type is %s.", columnName, propType));
}
});
return object;
}
use of org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty in project spring-cloud-gcp by spring-cloud.
the class MappingSpannerWriteConverter method write.
/**
* Writes an object's properties to the sink.
* @param source the object to write
* @param sink the sink to which to write
* @param includeColumns the properties/columns to write. If null, then all columns
* are written.
*/
public void write(Object source, WriteBuilder sink, Set<String> includeColumns) {
boolean writeAllColumns = includeColumns == null;
SpannerPersistentEntity<?> persistentEntity = this.spannerMappingContext.getPersistentEntity(source.getClass());
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(source);
persistentEntity.doWithProperties((PropertyHandler<SpannerPersistentProperty>) spannerPersistentProperty -> {
if (!writeAllColumns && !includeColumns.contains(spannerPersistentProperty.getColumnName())) {
return;
}
writeProperty(sink, accessor, spannerPersistentProperty);
});
}
Aggregations