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

nl.topicus.jdbc.shaded.com.google.cloud.spanner.Key Maven / Gradle / Ivy

There is a newer version: 1.1.6
Show newest version
/*
 * Copyright 2017 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 nl.topicus.jdbc.shaded.com.google.cloud.spanner;

import static nl.topicus.jdbc.shaded.com.google.common.base.Preconditions.checkNotNull;

import nl.topicus.jdbc.shaded.com.google.cloud.ByteArray;
import nl.topicus.jdbc.shaded.com.google.cloud.Date;
import nl.topicus.jdbc.shaded.com.google.cloud.Timestamp;
import nl.topicus.jdbc.shaded.com.google.common.base.Joiner;
import nl.topicus.jdbc.shaded.com.google.protobuf.ListValue;
import nl.topicus.jdbc.shaded.com.google.protobuf.NullValue;
import nl.topicus.jdbc.shaded.com.google.protobuf.Value;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import nl.topicus.jdbc.shaded.javax.annotation.Nullable;

/**
 * Represents a row key in a Cloud Spanner table or index. A key is a tuple of values constrained to
 * the scalar Cloud Spanner types: currently these are {@code BOOLEAN}, {@code INT64}, {@code
 * FLOAT64}, {@code STRING}, {@code BYTES} and {@code TIMESTAMP}. Values may be null where the table
 * definition permits it.
 *
 * 

{@code Key} is used to define the row, or endpoints of a range of rows, to retrieve in read * operations or to delete in a mutation. * *

{@code Key} instances are immutable. */ public final class Key implements Serializable { private static final Joiner joiner = Joiner.on(',').useForNull(""); private static final nl.topicus.jdbc.shaded.com.google.protobuf.Value NULL_PROTO = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(); private static final long serialVersionUID = 4433485671785063530L; private final List parts; private Key(List parts) { this.parts = Collections.unmodifiableList(parts); } /** * Construct a key with parts specified by {@code values}. Each object in {@code values} must be * either {@code null} or one of the following supported types: * *
    *
  • {@code Boolean} for the {@code BOOL} Cloud Spanner type *
  • {@code Integer}, {@code Long} for {@code INT64} *
  • {@code Float}, {@code Double} for {@code FLOAT64} *
  • {@code String} for {@code STRING} *
  • {@link ByteArray} for {@code BYTES} *
* * @throws IllegalArgumentException if any member of {@code values} is not a supported type */ public static Key of(Object... values) { // A literal Key.of(null) results in a null array being passed. Provide a clearer error. checkNotNull( values, "'values' cannot be null. For a literal key containing a single null value, " + "call Key.of((Object) null)."); Builder b = new Builder(false /* builder never leaves this scope */); for (Object value : values) { b.appendObject(value); } return b.build(); } /** Returns a new builder for constructing a key. */ public static Builder newBuilder() { return new Builder(true /* escaped */); } /** Builder for {@link Key} instances. */ public static class Builder { /** * Indicates whether this builder can escape the scope of this class. If so, we must assume that * the builder can be modified after {@code build()} is called and so we perform a defensive * copy. */ private final boolean canEscape; private final ArrayList buffer = new ArrayList<>(); private Builder(boolean canEscape) { this.canEscape = canEscape; } private Builder(Key key) { canEscape = true; buffer.addAll(key.parts); } /** Appends a {@code BOOL} value to the key. */ public Builder append(@Nullable Boolean value) { buffer.add(value); return this; } /** Appends an {@code INT64} value to the key. */ public Builder append(long value) { buffer.add(value); return this; } /** Appends an {@code INT64} value to the key. */ public Builder append(@Nullable Long value) { buffer.add(value); return this; } /** Appends a {@code FLOAT64} value to the key. */ public Builder append(double value) { buffer.add(value); return this; } /** Appends a {@code FLOAT64} value to the key. */ public Builder append(@Nullable Double value) { buffer.add(value); return this; } /** Appends a {@code STRING} value to the key. */ public Builder append(@Nullable String value) { buffer.add(value); return this; } /** Appends a {@code BYTES} value to the key. */ public Builder append(@Nullable ByteArray value) { buffer.add(value); return this; } /** Appends a {@code TIMESTAMP} value to the key */ public Builder append(@Nullable Timestamp value) { buffer.add(value); return this; } /** Appends a {@code DATE} value to the key */ public Builder append(@Nullable Date value) { buffer.add(value); return this; } /** * Appends an object following the same conversion rules as {@link Key#of(Object...)}. When * using the {@code Builder}, most code should prefer using the strongly typed {@code * append(...)} methods, for both performance and the benefit of compile-time checking. */ public Builder appendObject(@Nullable Object value) { if (value == null) { append((Boolean) null); } else if (value instanceof Boolean) { append((Boolean) value); } else if (value instanceof Integer) { append((Integer) value); } else if (value instanceof Long) { append((Long) value); } else if (value instanceof Float) { append((Float) value); } else if (value instanceof Double) { append((Double) value); } else if (value instanceof String) { append((String) value); } else if (value instanceof ByteArray) { append((ByteArray) value); } else if (value instanceof Timestamp) { append((Timestamp) value); } else if (value instanceof Date) { append((Date) value); } else { throw new IllegalArgumentException( "Unsupported type [" + value.getClass().getCanonicalName() + "] for argument: " + value); } return this; } public Key build() { if (canEscape) { // Copy buffer to preserve immutability contract. return new Key(new ArrayList<>(buffer)); } else { // Internal use of builder that does not escape; no need for defensive copy. return new Key(buffer); } } } /** Returns the number of parts in this key, including {@code null} values. */ public int size() { return parts.size(); } /** * Returns the parts in this key. Each part is represented by the corresponding Cloud Spanner * type's canonical Java type, as listed below. Note that other types supported by {@link * #of(Object...)} are converted to one of the canonical types. * *
    *
  • {@code BOOL} is represented by {@code Boolean} *
  • {@code INT64} is represented by {@code Long} *
  • {@code FLOAT64} is represented by {@code Double} *
  • {@code STRING} is represented by {@code String} *
  • {@code BYTES} is represented by {@link ByteArray} *
  • {@code TIMESTAMP} is represented by {@link Timestamp} *
  • {@code DATE} is represented by {@link Date} *
* * @return an unmodifiable list containing the key parts */ public Iterable getParts() { return parts; } /** Returns a builder initialized with the value of this key. */ public Builder toBuilder() { return new Builder(this); } void toString(StringBuilder b) { // TODO(user): Consider limiting the length of string output. // Note: the format produced should match that used for keys in error messages yielded by the // backend. b.append('['); joiner.appendTo(b, parts); b.append(']'); } @Override public String toString() { StringBuilder b = new StringBuilder(); toString(b); return b.toString(); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Key that = (Key) o; return parts.equals(that.parts); } @Override public int hashCode() { return parts.hashCode(); } ListValue toProto() { ListValue.Builder builder = ListValue.newBuilder(); for (Object part : parts) { if (part == null) { builder.addValues(NULL_PROTO); } else if (part instanceof Boolean) { builder.addValuesBuilder().setBoolValue((Boolean) part); } else if (part instanceof Long) { builder.addValuesBuilder().setStringValue(part.toString()); } else if (part instanceof Double) { builder.addValuesBuilder().setNumberValue((Double) part); } else if (part instanceof String) { builder.addValuesBuilder().setStringValue((String) part); } else if (part instanceof ByteArray) { builder.addValuesBuilder().setStringValue(((ByteArray) part).toBase64()); } else if (part instanceof Timestamp) { builder.addValuesBuilder().setStringValue(((Timestamp) part).toString()); } else { throw new AssertionError("Illegal key part: " + part.getClass()); } } return builder.build(); } }