Search in sources :

Example 1 with SpannerPersistentProperty

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()));
    }
}
Also used : SpannerDataException(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerDataException) StringJoiner(java.util.StringJoiner) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty)

Example 2 with SpannerPersistentProperty

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);
}
Also used : IgnoreCaseType(org.springframework.data.repository.query.parser.Part.IgnoreCaseType) BiFunction(java.util.function.BiFunction) SpannerDataException(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerDataException) HashMap(java.util.HashMap) Function(java.util.function.Function) ConversionUtils(org.springframework.cloud.gcp.data.spanner.core.convert.ConversionUtils) ArrayList(java.util.ArrayList) Parameter(java.lang.reflect.Parameter) Map(java.util.Map) Key(com.google.cloud.spanner.Key) StreamSupport(java.util.stream.StreamSupport) SpannerTemplate(org.springframework.cloud.gcp.data.spanner.core.SpannerTemplate) Pageable(org.springframework.data.domain.Pageable) Sort(org.springframework.data.domain.Sort) SpannerPersistentEntity(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentEntity) SpannerMappingContext(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerMappingContext) SpannerPageableQueryOptions(org.springframework.cloud.gcp.data.spanner.core.SpannerPageableQueryOptions) Iterator(java.util.Iterator) PartTree(org.springframework.data.repository.query.parser.PartTree) ParameterAccessor(org.springframework.data.repository.query.ParameterAccessor) Collectors(java.util.stream.Collectors) KeySet(com.google.cloud.spanner.KeySet) Statement(com.google.cloud.spanner.Statement) List(java.util.List) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty) Where(org.springframework.cloud.gcp.data.spanner.core.mapping.Where) ParameterizedType(java.lang.reflect.ParameterizedType) Struct(com.google.cloud.spanner.Struct) StringJoiner(java.util.StringJoiner) ValueBinder(com.google.cloud.spanner.ValueBinder) ConverterAwareMappingSpannerEntityWriter(org.springframework.cloud.gcp.data.spanner.core.convert.ConverterAwareMappingSpannerEntityWriter) SpannerCustomConverter(org.springframework.cloud.gcp.data.spanner.core.convert.SpannerCustomConverter) StringUtils(org.springframework.util.StringUtils) ArrayList(java.util.ArrayList) Iterator(java.util.Iterator) ArrayList(java.util.ArrayList) List(java.util.List) Key(com.google.cloud.spanner.Key) StringJoiner(java.util.StringJoiner) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty)

Example 3 with SpannerPersistentProperty

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;
}
Also used : SpannerDataException(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerDataException) ParameterValueProvider(org.springframework.data.mapping.model.ParameterValueProvider) Set(java.util.Set) PersistentPropertyAccessor(org.springframework.data.mapping.PersistentPropertyAccessor) PropertyHandler(org.springframework.data.mapping.PropertyHandler) EntityInstantiator(org.springframework.data.convert.EntityInstantiator) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty) Struct(com.google.cloud.spanner.Struct) EntityInstantiators(org.springframework.data.convert.EntityInstantiators) PersistentEntityParameterValueProvider(org.springframework.data.mapping.model.PersistentEntityParameterValueProvider) SpannerPersistentEntity(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentEntity) SpannerMappingContext(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerMappingContext) PreferredConstructor(org.springframework.data.mapping.PreferredConstructor) PersistentPropertyAccessor(org.springframework.data.mapping.PersistentPropertyAccessor) EntityInstantiator(org.springframework.data.convert.EntityInstantiator) PersistentEntityParameterValueProvider(org.springframework.data.mapping.model.PersistentEntityParameterValueProvider) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty) SpannerPersistentEntity(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentEntity)

Example 4 with SpannerPersistentProperty

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;
}
Also used : Date(com.google.cloud.Date) AbstractStructReader(com.google.cloud.spanner.AbstractStructReader) CustomConversions(org.springframework.data.convert.CustomConversions) ImmutableMap(com.google.common.collect.ImmutableMap) BiFunction(java.util.function.BiFunction) SpannerDataException(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerDataException) Set(java.util.Set) Type(com.google.cloud.spanner.Type) Timestamp(com.google.cloud.Timestamp) Constructor(java.lang.reflect.Constructor) PersistentPropertyAccessor(org.springframework.data.mapping.PersistentPropertyAccessor) PropertyHandler(org.springframework.data.mapping.PropertyHandler) EntityReader(org.springframework.data.convert.EntityReader) List(java.util.List) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty) Struct(com.google.cloud.spanner.Struct) Map(java.util.Map) ByteArray(com.google.cloud.ByteArray) SpannerPersistentEntity(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentEntity) SpannerMappingContext(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerMappingContext) PersistentPropertyAccessor(org.springframework.data.mapping.PersistentPropertyAccessor) SpannerDataException(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerDataException) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty)

Example 5 with SpannerPersistentProperty

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);
    });
}
Also used : Date(com.google.cloud.Date) CustomConversions(org.springframework.data.convert.CustomConversions) ImmutableMap(com.google.common.collect.ImmutableMap) BiFunction(java.util.function.BiFunction) SpannerDataException(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerDataException) Set(java.util.Set) WriteBuilder(com.google.cloud.spanner.Mutation.WriteBuilder) Timestamp(com.google.cloud.Timestamp) PersistentPropertyAccessor(org.springframework.data.mapping.PersistentPropertyAccessor) PropertyHandler(org.springframework.data.mapping.PropertyHandler) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty) Map(java.util.Map) ValueBinder(com.google.cloud.spanner.ValueBinder) BiConsumer(java.util.function.BiConsumer) ByteArray(com.google.cloud.ByteArray) SpannerPersistentEntity(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentEntity) SpannerMappingContext(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerMappingContext) EntityWriter(org.springframework.data.convert.EntityWriter) PersistentPropertyAccessor(org.springframework.data.mapping.PersistentPropertyAccessor) SpannerPersistentProperty(org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty)

Aggregations

SpannerPersistentProperty (org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentProperty)8 SpannerDataException (org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerDataException)6 SpannerMappingContext (org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerMappingContext)5 SpannerPersistentEntity (org.springframework.cloud.gcp.data.spanner.core.mapping.SpannerPersistentEntity)5 Set (java.util.Set)4 StringJoiner (java.util.StringJoiner)4 BiFunction (java.util.function.BiFunction)4 PropertyHandler (org.springframework.data.mapping.PropertyHandler)4 Struct (com.google.cloud.spanner.Struct)3 List (java.util.List)3 Map (java.util.Map)3 PersistentPropertyAccessor (org.springframework.data.mapping.PersistentPropertyAccessor)3 ByteArray (com.google.cloud.ByteArray)2 Date (com.google.cloud.Date)2 Timestamp (com.google.cloud.Timestamp)2 Key (com.google.cloud.spanner.Key)2 Type (com.google.cloud.spanner.Type)2 ValueBinder (com.google.cloud.spanner.ValueBinder)2 ImmutableMap (com.google.common.collect.ImmutableMap)2 ArrayList (java.util.ArrayList)2