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

com.datastax.driver.dse.search.DateRangeCodec Maven / Gradle / Ivy

/*
 * Copyright DataStax, Inc.
 *
 * This software can be used solely with DataStax Enterprise. Please consult the license at
 * http://www.datastax.com/terms/datastax-dse-driver-license-terms
 */
package com.datastax.driver.dse.search;

import static com.datastax.driver.dse.search.DateRange.DateRangeBound.UNBOUNDED;

import com.datastax.driver.core.DataType;
import com.datastax.driver.core.ParseUtils;
import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.exceptions.InvalidTypeException;
import com.datastax.driver.dse.search.DateRange.DateRangeBound;
import com.datastax.driver.dse.search.DateRange.DateRangeBound.Precision;
import java.nio.ByteBuffer;
import java.util.Date;

/**
 * A {@link TypeCodec codec} for {@link DateRange} instances.
 *
 * @since DSE 5.1
 */
public class DateRangeCodec extends TypeCodec {

  /** The name of the server-side type handled by this codec. */
  public static final String CLASS_NAME = "org.apache.cassandra.db.marshal.DateRangeType";

  /** The {@link DataType} handled by this codec. */
  public static final DataType.CustomType DATA_TYPE = DataType.custom(CLASS_NAME);

  /** The singleton instance of {@link DateRangeCodec}. */
  public static final DateRangeCodec INSTANCE = new DateRangeCodec();

  // e.g. [2001-01-01]
  private static final byte DATE_RANGE_TYPE_SINGLE_DATE = 0x00;
  // e.g. [2001-01-01 TO 2001-01-31]
  private static final byte DATE_RANGE_TYPE_CLOSED_RANGE = 0x01;
  // e.g. [2001-01-01 TO *]
  private static final byte DATE_RANGE_TYPE_OPEN_RANGE_HIGH = 0x02;
  // e.g. [* TO 2001-01-01]
  private static final byte DATE_RANGE_TYPE_OPEN_RANGE_LOW = 0x03;
  // [* TO *]
  private static final byte DATE_RANGE_TYPE_BOTH_OPEN_RANGE = 0x04;
  // *
  private static final byte DATE_RANGE_TYPE_SINGLE_DATE_OPEN = 0x05;

  private DateRangeCodec() {
    super(DATA_TYPE, DateRange.class);
  }

  @Override
  public ByteBuffer serialize(DateRange dateRange, ProtocolVersion protocolVersion)
      throws InvalidTypeException {
    if (dateRange == null) {
      return null;
    }
    byte rangeType = encodeType(dateRange);
    int bufferSize = 1;
    if (!dateRange.getLowerBound().isUnbounded()) {
      bufferSize += 9;
    }
    if (!dateRange.isSingleBounded() && !dateRange.getUpperBound().isUnbounded()) {
      bufferSize += 9;
    }
    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
    buffer.put(rangeType);
    DateRangeBound lowerBound = dateRange.getLowerBound();
    if (!lowerBound.isUnbounded()) {
      buffer.putLong(lowerBound.getTimestamp().getTime());
      buffer.put(lowerBound.getPrecision().encoding);
    }
    if (!dateRange.isSingleBounded()) {
      DateRangeBound upperBound = dateRange.getUpperBound();
      if (!upperBound.isUnbounded()) {
        buffer.putLong(upperBound.getTimestamp().getTime());
        buffer.put(upperBound.getPrecision().encoding);
      }
    }
    return (ByteBuffer) buffer.flip();
  }

  @Override
  public DateRange deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion)
      throws InvalidTypeException {
    if (bytes == null || bytes.remaining() == 0) {
      return null;
    }
    byte type = bytes.get();
    switch (type) {
      case DATE_RANGE_TYPE_SINGLE_DATE:
        return new DateRange(deserializeDateRangeLowerBound(bytes));
      case DATE_RANGE_TYPE_CLOSED_RANGE:
        return new DateRange(
            deserializeDateRangeLowerBound(bytes), deserializeDateRangeUpperBound(bytes));
      case DATE_RANGE_TYPE_OPEN_RANGE_HIGH:
        return new DateRange(deserializeDateRangeLowerBound(bytes), UNBOUNDED);
      case DATE_RANGE_TYPE_OPEN_RANGE_LOW:
        return new DateRange(UNBOUNDED, deserializeDateRangeUpperBound(bytes));
      case DATE_RANGE_TYPE_BOTH_OPEN_RANGE:
        return new DateRange(UNBOUNDED, UNBOUNDED);
      case DATE_RANGE_TYPE_SINGLE_DATE_OPEN:
        return new DateRange(UNBOUNDED);
    }
    throw new InvalidTypeException("Unknown date range type: " + type);
  }

  @Override
  public DateRange parse(String value) throws InvalidTypeException {
    if (value == null || value.isEmpty() || value.equalsIgnoreCase("NULL")) {
      return null;
    }
    try {
      return DateRange.parse(ParseUtils.unquote(value));
    } catch (Exception e) {
      throw new InvalidTypeException(String.format("Invalid date range literal: %s", value), e);
    }
  }

  @Override
  public String format(DateRange dateRange) throws InvalidTypeException {
    return dateRange == null ? "NULL" : ParseUtils.quote(dateRange.toString());
  }

  private byte encodeType(DateRange dateRange) {
    if (dateRange.isSingleBounded()) {
      return dateRange.getLowerBound().isUnbounded()
          ? DATE_RANGE_TYPE_SINGLE_DATE_OPEN
          : DATE_RANGE_TYPE_SINGLE_DATE;
    } else {
      if (dateRange.getLowerBound().isUnbounded()) {
        return dateRange.getUpperBound().isUnbounded()
            ? DATE_RANGE_TYPE_BOTH_OPEN_RANGE
            : DATE_RANGE_TYPE_OPEN_RANGE_LOW;
      } else {
        return dateRange.getUpperBound().isUnbounded()
            ? DATE_RANGE_TYPE_OPEN_RANGE_HIGH
            : DATE_RANGE_TYPE_CLOSED_RANGE;
      }
    }
  }

  private DateRangeBound deserializeDateRangeLowerBound(ByteBuffer bytes) {
    long epochMillis = bytes.getLong();
    Precision precision = Precision.fromEncoding(bytes.get());
    return DateRangeBound.lowerBound(new Date(epochMillis), precision);
  }

  private DateRangeBound deserializeDateRangeUpperBound(ByteBuffer bytes) {
    long epochMillis = bytes.getLong();
    Precision precision = Precision.fromEncoding(bytes.get());
    return DateRangeBound.upperBound(new Date(epochMillis), precision);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy