All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.cloud.bigquery.QueryParameterValue Maven / Gradle / Ivy

There is a newer version: 2.44.0
Show newest version
/*
 * Copyright 2016 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.cloud.bigquery;

import static org.threeten.bp.temporal.ChronoField.HOUR_OF_DAY;
import static org.threeten.bp.temporal.ChronoField.MINUTE_OF_HOUR;
import static org.threeten.bp.temporal.ChronoField.NANO_OF_SECOND;
import static org.threeten.bp.temporal.ChronoField.SECOND_OF_MINUTE;

import com.google.api.services.bigquery.model.QueryParameterType;
import com.google.api.services.bigquery.model.RangeValue;
import com.google.auto.value.AutoValue;
import com.google.cloud.Timestamp;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
import com.google.gson.JsonObject;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.threeten.bp.Instant;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.DateTimeFormatterBuilder;
import org.threeten.bp.format.DateTimeParseException;
import org.threeten.extra.PeriodDuration;

/**
 * A value for a QueryParameter along with its type.
 *
 * 

A static factory method is provided for each of the possible types (e.g. {@link #int64(Long)} * for StandardSQLTypeName.INT64). Alternatively, an instance can be constructed by calling {@link * #of(Object, Class)} with the value and a Class object, which will use these mappings: * *

    *
  • Boolean: StandardSQLTypeName.BOOL *
  • String: StandardSQLTypeName.STRING *
  • Integer: StandardSQLTypeName.INT64 *
  • Long: StandardSQLTypeName.INT64 *
  • Double: StandardSQLTypeName.FLOAT64 *
  • Float: StandardSQLTypeName.FLOAT64 *
  • BigDecimal: StandardSQLTypeName.NUMERIC *
  • BigNumeric: StandardSQLTypeName.BIGNUMERIC *
  • JSON: StandardSQLTypeName.JSON *
  • INTERVAL: StandardSQLTypeName.INTERVAL *
* *

No other types are supported through that entry point. The other types can be created by * calling {@link #of(Object, StandardSQLTypeName)} with the value and a particular * StandardSQLTypeName enum value. * *

Struct parameters are currently not supported. */ @AutoValue public abstract class QueryParameterValue implements Serializable { private static final DateTimeFormatter timestampFormatter = new DateTimeFormatterBuilder() .parseLenient() .append(DateTimeFormatter.ISO_LOCAL_DATE) .appendLiteral(' ') .appendValue(HOUR_OF_DAY, 2) .appendLiteral(':') .appendValue(MINUTE_OF_HOUR, 2) .optionalStart() .appendLiteral(':') .appendValue(SECOND_OF_MINUTE, 2) .optionalStart() .appendFraction(NANO_OF_SECOND, 6, 9, true) .optionalStart() .appendOffset("+HHMM", "+00:00") .optionalEnd() .toFormatter() .withZone(ZoneOffset.UTC); private static final DateTimeFormatter timestampValidator = new DateTimeFormatterBuilder() .parseLenient() .append(timestampFormatter) .optionalStart() .appendOffsetId() .optionalEnd() .toFormatter() .withZone(ZoneOffset.UTC); private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSSSSS"); private static final DateTimeFormatter datetimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"); static final Function< QueryParameterValue, com.google.api.services.bigquery.model.QueryParameterValue> TO_VALUE_PB_FUNCTION = new Function< QueryParameterValue, com.google.api.services.bigquery.model.QueryParameterValue>() { @Override public com.google.api.services.bigquery.model.QueryParameterValue apply( QueryParameterValue value) { return value.toValuePb(); } }; private static final long serialVersionUID = -5620695863123562896L; @AutoValue.Builder public abstract static class Builder { /** Sets the value to the given scalar value. */ public abstract Builder setValue(String value); /** Sets array values. The type must set to ARRAY. */ public Builder setArrayValues(List arrayValues) { return setArrayValuesInner(ImmutableList.copyOf(arrayValues)); } abstract Builder setArrayValuesInner(ImmutableList arrayValues); /** Sets struct values. The type must set to STRUCT. */ public Builder setStructValues(Map structValues) { setStructTypes(ImmutableMap.copyOf(structValues)); return setStructValuesInner(ImmutableMap.copyOf(structValues)); } abstract Builder setStructValuesInner(Map structValues); /** Sets range values. The type must set to RANGE. */ public Builder setRangeValues(Range range) { return setRangeValuesInner(range); } abstract Builder setRangeValuesInner(Range range); /** Sets the parameter data type. */ public abstract Builder setType(StandardSQLTypeName type); /** Sets the data type of the array elements. The type must set to ARRAY. */ public abstract Builder setArrayType(StandardSQLTypeName arrayType); /** Sets the data type of the struct elements. The type must set to STRUCT. */ public Builder setStructTypes(Map structTypes) { return setStructTypesInner(structTypes); } abstract Builder setStructTypesInner(Map structTypes); /** Creates a {@code QueryParameterValue} object. */ public abstract QueryParameterValue build(); } QueryParameterValue() { // Package-private so it's extensible by AutoValue but not users. } /** Returns the value of this parameter. */ @Nullable public abstract String getValue(); /** Returns the array values of this parameter. The returned list, if not null, is immutable. */ @Nullable public List getArrayValues() { return getArrayValuesInner(); } @Nullable abstract ImmutableList getArrayValuesInner(); /** Returns the struct values of this parameter. The returned map, if not null, is immutable. */ @Nullable public Map getStructValues() { return getStructValuesInner(); } @Nullable abstract Map getStructValuesInner(); /** Returns the struct values of this parameter. The returned map, if not null, is immutable. */ @Nullable public Range getRangeValues() { return getRangeValuesInner(); } @Nullable abstract Range getRangeValuesInner(); /** Returns the data type of this parameter. */ public abstract StandardSQLTypeName getType(); /** Returns the data type of the array elements. */ @Nullable public abstract StandardSQLTypeName getArrayType(); /** Returns the data type of the struct elements. */ @Nullable public Map getStructTypes() { return getStructTypesInner(); } @Nullable abstract Map getStructTypesInner(); /** * Creates a {@code QueryParameterValue} object with the given value and type. Note: this does not * support BigNumeric */ public static QueryParameterValue of(T value, Class type) { return of(value, classToType(type)); } /** Creates a {@code QueryParameterValue} object with the given value and type. */ public static QueryParameterValue of(T value, StandardSQLTypeName type) { return QueryParameterValue.newBuilder() .setValue(valueToStringOrNull(value, type)) .setType(type) .build(); } /** Creates a {@code QueryParameterValue} object with a type of BOOL. */ public static QueryParameterValue bool(Boolean value) { return of(value, StandardSQLTypeName.BOOL); } /** Creates a {@code QueryParameterValue} object with a type of INT64. */ public static QueryParameterValue int64(Long value) { return of(value, StandardSQLTypeName.INT64); } /** Creates a {@code QueryParameterValue} object with a type of INT64. */ public static QueryParameterValue int64(Integer value) { return of(value, StandardSQLTypeName.INT64); } /** Creates a {@code QueryParameterValue} object with a type of FLOAT64. */ public static QueryParameterValue float64(Double value) { return of(value, StandardSQLTypeName.FLOAT64); } /** Creates a {@code QueryParameterValue} object with a type of FLOAT64. */ public static QueryParameterValue float64(Float value) { return of(value, StandardSQLTypeName.FLOAT64); } /** Creates a {@code QueryParameterValue} object with a type of NUMERIC. */ public static QueryParameterValue numeric(BigDecimal value) { return of(value, StandardSQLTypeName.NUMERIC); } /** Creates a {@code QueryParameterValue} object with a type of BIGNUMERIC. */ public static QueryParameterValue bigNumeric(BigDecimal value) { return of(value, StandardSQLTypeName.BIGNUMERIC); } /** Creates a {@code QueryParameterValue} object with a type of STRING. */ public static QueryParameterValue string(String value) { return of(value, StandardSQLTypeName.STRING); } /** Creates a {@code QueryParameterValue} object with a type of GEOGRAPHY. */ public static QueryParameterValue geography(String value) { return of(value, StandardSQLTypeName.GEOGRAPHY); } /** * Creates a {@code QueryParameterValue} object with a type of JSON. Currently, this is only * supported in INSERT, not in query as a filter */ public static QueryParameterValue json(String value) { return of(value, StandardSQLTypeName.JSON); } /** * Creates a {@code QueryParameterValue} object with a type of JSON. Currently, this is only * supported in INSERT, not in query as a filter */ public static QueryParameterValue json(JsonObject value) { return of(value, StandardSQLTypeName.JSON); } /** Creates a {@code QueryParameterValue} object with a type of BYTES. */ public static QueryParameterValue bytes(byte[] value) { return of(value, StandardSQLTypeName.BYTES); } /** Creates a {@code QueryParameterValue} object with a type of TIMESTAMP. */ public static QueryParameterValue timestamp(Long value) { return of(value, StandardSQLTypeName.TIMESTAMP); } /** * Creates a {@code QueryParameterValue} object with a type of TIMESTAMP. Must be in the format * "yyyy-MM-dd HH:mm:ss.SSSSSSZZ", e.g. "2014-08-19 12:41:35.220000+00:00". */ public static QueryParameterValue timestamp(String value) { return of(value, StandardSQLTypeName.TIMESTAMP); } /** * Creates a {@code QueryParameterValue} object with a type of DATE. Must be in the format * "yyyy-MM-dd", e.g. "2014-08-19". */ public static QueryParameterValue date(String value) { return of(value, StandardSQLTypeName.DATE); } /** * Creates a {@code QueryParameterValue} object with a type of TIME. Must be in the format * "HH:mm:ss.SSSSSS", e.g. "12:41:35.220000". */ public static QueryParameterValue time(String value) { return of(value, StandardSQLTypeName.TIME); } /** * Creates a {@code QueryParameterValue} object with a type of DATETIME. Must be in the format * "yyyy-MM-dd HH:mm:ss.SSSSSS", e.g. "2014-08-19 12:41:35.220000". */ public static QueryParameterValue dateTime(String value) { return of(value, StandardSQLTypeName.DATETIME); } /** * Creates a {@code QueryParameterValue} object with a type of INTERVAL. Must be in the canonical * format "[sign]Y-M [sign]D [sign]H:M:S[.F]", e.g. "123-7 -19 0:24:12.000006" or ISO 8601 * duration format, e.g. "P123Y7M-19DT0H24M12.000006S" */ public static QueryParameterValue interval(String value) { return of(value, StandardSQLTypeName.INTERVAL); } /** Creates a {@code QueryParameterValue} object with a type of INTERVAL. */ public static QueryParameterValue interval(PeriodDuration value) { return of(value, StandardSQLTypeName.INTERVAL); } /** Creates a {@code QueryParameterValue} object with a type of RANGE. */ public static QueryParameterValue range(Range value) { return QueryParameterValue.newBuilder() .setRangeValues(value) .setType(StandardSQLTypeName.RANGE) .build(); } /** * Creates a {@code QueryParameterValue} object with a type of ARRAY, and an array element type * based on the given class. */ public static QueryParameterValue array(T[] array, Class clazz) { return array(array, classToType(clazz)); } /** * Creates a {@code QueryParameterValue} object with a type of ARRAY the given array element type. */ public static QueryParameterValue array(T[] array, StandardSQLTypeName type) { List listValues = new ArrayList<>(); for (T obj : array) { if (type == StandardSQLTypeName.STRUCT) { listValues.add((QueryParameterValue) obj); } else { listValues.add(QueryParameterValue.of(obj, type)); } } return QueryParameterValue.newBuilder() .setArrayValues(listValues) .setType(StandardSQLTypeName.ARRAY) .setArrayType(type) .build(); } /** * Creates a map with {@code QueryParameterValue} object and a type of STRUCT the given struct * element type. */ public static QueryParameterValue struct(Map struct) { return QueryParameterValue.newBuilder() .setStructValues(struct) .setType(StandardSQLTypeName.STRUCT) .build(); } private static StandardSQLTypeName classToType(Class type) { if (Boolean.class.isAssignableFrom(type)) { return StandardSQLTypeName.BOOL; } else if (String.class.isAssignableFrom(type)) { return StandardSQLTypeName.STRING; } else if (String.class.isAssignableFrom(type)) { return StandardSQLTypeName.GEOGRAPHY; } else if (Integer.class.isAssignableFrom(type)) { return StandardSQLTypeName.INT64; } else if (Long.class.isAssignableFrom(type)) { return StandardSQLTypeName.INT64; } else if (Double.class.isAssignableFrom(type)) { return StandardSQLTypeName.FLOAT64; } else if (Float.class.isAssignableFrom(type)) { return StandardSQLTypeName.FLOAT64; } else if (BigDecimal.class.isAssignableFrom(type)) { return StandardSQLTypeName.NUMERIC; } else if (Date.class.isAssignableFrom(type)) { return StandardSQLTypeName.DATE; } else if (String.class.isAssignableFrom(type)) { return StandardSQLTypeName.JSON; } else if (JsonObject.class.isAssignableFrom(type)) { return StandardSQLTypeName.JSON; } throw new IllegalArgumentException("Unsupported object type for QueryParameter: " + type); } private static String valueToStringOrNull(T value, StandardSQLTypeName type) { if (value == null) { return null; } switch (type) { case BOOL: if (value instanceof Boolean) { return value.toString(); } break; case INT64: if (value instanceof Integer || value instanceof Long) { return value.toString(); } break; case FLOAT64: if (value instanceof Double || value instanceof Float) { return value.toString(); } break; case NUMERIC: case BIGNUMERIC: if (value instanceof BigDecimal) { return value.toString(); } break; case BYTES: if (value instanceof byte[]) { return BaseEncoding.base64().encode((byte[]) value); } break; case STRING: return value.toString(); case GEOGRAPHY: return value.toString(); case JSON: if (value instanceof String || value instanceof JsonObject) return value.toString(); case INTERVAL: if (value instanceof String || value instanceof PeriodDuration) return value.toString(); break; case STRUCT: throw new IllegalArgumentException("Cannot convert STRUCT to String value"); case ARRAY: throw new IllegalArgumentException("Cannot convert ARRAY to String value"); case RANGE: throw new IllegalArgumentException("Cannot convert RANGE to String value"); case TIMESTAMP: if (value instanceof Long) { Timestamp timestamp = Timestamp.ofTimeMicroseconds((Long) value); return timestampFormatter.format( Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos())); } else if (value instanceof String) { // verify that the String is in the right format checkFormat(value, timestampValidator); return (String) value; } break; case DATE: if (value instanceof String) { // verify that the String is in the right format checkFormat(value, dateFormatter); return (String) value; } else if (value instanceof Date) { com.google.cloud.Date date = com.google.cloud.Date.fromJavaUtilDate((Date) value); return date.toString(); } break; case TIME: if (value instanceof String) { // verify that the String is in the right format checkFormat(value, timeFormatter); return (String) value; } break; case DATETIME: if (value instanceof String) { // verify that the String is in the right format checkFormat(value, datetimeFormatter); return (String) value; } break; default: throw new UnsupportedOperationException("Implementation error - Unsupported type: " + type); } throw new IllegalArgumentException( "Type " + type + " incompatible with " + value.getClass().getCanonicalName()); } private static void checkFormat(Object value, DateTimeFormatter formatter) { try { formatter.parse((String) value); } catch (DateTimeParseException e) { throw new IllegalArgumentException(e.getMessage(), e); } } /** Returns a builder for a QueryParameterValue object with given value. */ public abstract Builder toBuilder(); /** Returns a builder for the {@code QueryParameterValue} object. */ public static Builder newBuilder() { return new AutoValue_QueryParameterValue.Builder(); } com.google.api.services.bigquery.model.QueryParameterValue toValuePb() { com.google.api.services.bigquery.model.QueryParameterValue valuePb = new com.google.api.services.bigquery.model.QueryParameterValue(); valuePb.setValue(getValue()); if (getArrayValues() != null) { valuePb.setArrayValues( Lists.transform(getArrayValues(), QueryParameterValue.TO_VALUE_PB_FUNCTION)); } if (getStructValues() != null) { Map structValues = new HashMap<>(); for (Map.Entry structValue : getStructValues().entrySet()) { structValues.put(structValue.getKey(), structValue.getValue().toValuePb()); } valuePb.setStructValues(structValues); } if (getType() == StandardSQLTypeName.RANGE) { RangeValue rangeValue = new RangeValue(); if (!getRangeValues().getStart().isNull()) { com.google.api.services.bigquery.model.QueryParameterValue startValue = new com.google.api.services.bigquery.model.QueryParameterValue(); startValue.setValue(getRangeValues().getStart().getStringValue()); rangeValue.setStart(startValue); } if (!getRangeValues().getEnd().isNull()) { com.google.api.services.bigquery.model.QueryParameterValue endValue = new com.google.api.services.bigquery.model.QueryParameterValue(); endValue.setValue(getRangeValues().getEnd().getStringValue()); rangeValue.setEnd(endValue); } valuePb.setRangeValue(rangeValue); } return valuePb; } QueryParameterType toTypePb() { QueryParameterType typePb = new QueryParameterType(); typePb.setType(getType().toString()); if (getArrayType() != null) { List values = getArrayValues(); if (getArrayType() == StandardSQLTypeName.STRUCT && values != null && values.size() != 0) { QueryParameterType structType = values.get(0).toTypePb(); typePb.setArrayType(structType); } else { QueryParameterType arrayTypePb = new QueryParameterType(); arrayTypePb.setType(getArrayType().toString()); typePb.setArrayType(arrayTypePb); } } if (getStructTypes() != null) { List structTypes = new ArrayList<>(); for (Map.Entry entry : getStructTypes().entrySet()) { QueryParameterType.StructTypes structType = new QueryParameterType.StructTypes(); structType.setName(entry.getKey()); structType.setType(entry.getValue().toTypePb()); structTypes.add(structType); } typePb.setStructTypes(structTypes); } if (getType() == StandardSQLTypeName.RANGE && getRangeValues() != null && getRangeValues().getType() != null) { QueryParameterType rangeTypePb = new QueryParameterType(); rangeTypePb.setType(getRangeValues().getType().getType()); typePb.setRangeElementType(rangeTypePb); } return typePb; } static QueryParameterValue fromPb( com.google.api.services.bigquery.model.QueryParameterValue valuePb, QueryParameterType typePb) { Builder valueBuilder = newBuilder(); Map parameterTypes = new HashMap<>(); StandardSQLTypeName type = StandardSQLTypeName.valueOf(typePb.getType()); valueBuilder.setType(type); if (type == StandardSQLTypeName.ARRAY) { valueBuilder.setArrayType(StandardSQLTypeName.valueOf(typePb.getArrayType().getType())); if (valuePb == null || valuePb.getArrayValues() == null) { valueBuilder.setArrayValues(ImmutableList.of()); } else { ImmutableList.Builder arrayValues = ImmutableList.builder(); for (com.google.api.services.bigquery.model.QueryParameterValue elementValuePb : valuePb.getArrayValues()) { arrayValues.add(fromPb(elementValuePb, typePb.getArrayType())); } valueBuilder.setArrayValues(arrayValues.build()); } } else if (type == StandardSQLTypeName.STRUCT) { Map structTypes = new HashMap<>(); for (QueryParameterType.StructTypes types : typePb.getStructTypes()) { structTypes.put( types.getName(), QueryParameterValue.newBuilder() .setType(StandardSQLTypeName.valueOf(types.getType().getType())) .build()); } valueBuilder.setStructTypes(structTypes); if (valuePb == null || valuePb.getStructValues() == null) { valueBuilder.setStructValues(ImmutableMap.of()); } else { Map structValues = new HashMap<>(); for (QueryParameterType.StructTypes structType : typePb.getStructTypes()) { parameterTypes.put(structType.getName(), structType.getType()); } for (Map.Entry structValue : valuePb.getStructValues().entrySet()) { structValues.put( structValue.getKey(), QueryParameterValue.fromPb( structValue.getValue(), parameterTypes.get(structValue.getKey()))); } valueBuilder.setStructValues(structValues); } } else if (type == StandardSQLTypeName.RANGE) { Range.Builder range = Range.newBuilder(); if (valuePb.getRangeValue() != null) { com.google.api.services.bigquery.model.RangeValue rangeValuePb = valuePb.getRangeValue(); if (rangeValuePb.getStart() != null && rangeValuePb.getStart().getValue() != null) { range.setStart(valuePb.getRangeValue().getStart().getValue()); } if (rangeValuePb.getEnd() != null && rangeValuePb.getEnd().getValue() != null) { range.setEnd(valuePb.getRangeValue().getEnd().getValue()); } } if (typePb.getRangeElementType() != null && typePb.getRangeElementType().getType() != null) { range.setType(FieldElementType.fromPb(typePb)); } valueBuilder.setRangeValues(range.build()); } else { valueBuilder.setValue(valuePb == null ? "" : valuePb.getValue()); } return valueBuilder.build(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy