io.stargate.db.query.builder.Value Maven / Gradle / Ivy
/*
* Copyright DataStax, Inc. and/or The Stargate Authors
*
* 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 io.stargate.db.query.builder;
import com.datastax.oss.driver.shaded.guava.common.base.Preconditions;
import io.stargate.db.query.TypedValue;
import java.util.Objects;
import javax.annotation.Nullable;
/** A concrete value, or a bind marker. */
public abstract class Value {
private int internalIndex = -1;
public static Value marker() {
return new Marker<>();
}
public static Value of(T value) {
return new Concrete<>(value);
}
public abstract boolean isMarker();
public abstract T get();
void setInternalIndex(int index) {
Preconditions.checkArgument(index >= 0);
this.internalIndex = index;
}
/**
* The query build internally prepare every value and pass them as bound values. This is the index
* of the marker in the query internally generated by the builder.
*
* @return a positive integer corresponding to the index of the marker in the internal query that
* this is the value of, or a negative integer if this value is not associated to a marker in
* the internal query.
*/
int internalIndex() {
return internalIndex;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Value)) return false;
Value> that = (Value>) obj;
if (this.isMarker() != that.isMarker()) return false;
return this.isMarker() || Objects.equals(this.get(), that.get());
}
@Override
public int hashCode() {
return Objects.hash(isMarker(), isMarker() ? null : get());
}
private static class Concrete extends Value {
private final @Nullable T value;
private Concrete(T value) {
// Explicitly using an UNSET value kind of don't make sense: just don't include whatever
// you're setting to this value in the statement in the first place. UNSET is only truly
// useful for prepared statements/bound values. So make sure no-one pass it here thinking this
// may work, as it doesn't (we "could" make it work technically, as the query builder actually
// prepare all values, even the ones that set at the time of the query construction. It adds
// unnecessary complexity though).
Preconditions.checkArgument(
value != TypedValue.UNSET,
"Cannot set a column to . should only be used when binding value to prepared bind marker");
this.value = value;
}
@Override
public boolean isMarker() {
return false;
}
@Override
public @Nullable T get() {
return value;
}
@Override
public String toString() {
return value == null ? "null" : value.toString();
}
}
static class Marker extends Value {
private int externalIndex = -1;
private Marker() {}
void setExternalIndex(int externalIndex) {
this.externalIndex = externalIndex;
}
/** Index of the marker, as an "external" (to the query building) marker. */
int externalIndex() {
Preconditions.checkState(externalIndex >= 0, "Marker has not bet set properly");
return externalIndex;
}
@Override
public boolean isMarker() {
return true;
}
@Override
public T get() {
throw new UnsupportedOperationException("Cannot get the value of a marker");
}
@Override
public String toString() {
return "?";
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy