Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.basho.riak.client.api.commands.timeseries;

import com.basho.riak.client.api.RiakCommand;
import com.basho.riak.client.core.RiakCluster;
import com.basho.riak.client.core.RiakFuture;
import com.basho.riak.client.core.operations.ts.DescribeTableOperation;
import com.basho.riak.client.core.query.timeseries.TableDefinition;

/**
* Time Series DescribeTable Command
* Allows you to fetch a table definition from Riak Time Series.
*
* @author Alex Moore <amoore at basho dot com>
* @since 2.0.4
*/
public class DescribeTable extends RiakCommand<TableDefinition, String>
{
private final String tableName;

/**
* Create a new DescribeTable command.
* No Builder is required.
*
* @param tableName The name of the table to fetch a definition for. Required, must not be empty or null.
*/
public DescribeTable(String tableName)
{
if(tableName == null || tableName.isEmpty())
{
throw new IllegalArgumentException("Table Name must not be null or empty.");
}

this.tableName = tableName;
}

@Override
protected RiakFuture<TableDefinition, String> executeAsync(RiakCluster cluster)
{
RiakFuture<TableDefinition, String> future =
cluster.execute(buildCoreOperation());

return future;
}

private DescribeTableOperation buildCoreOperation()
{
return new DescribeTableOperation(this.tableName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.basho.riak.client.core.operations.ts;

import com.basho.riak.client.core.operations.PBFutureOperation;
import com.basho.riak.client.core.query.timeseries.PbResultFactory;
import com.basho.riak.client.core.query.timeseries.TableDefinition;
import com.basho.riak.protobuf.RiakMessageCodes;
import com.basho.riak.protobuf.RiakTsPB;
import com.google.protobuf.ByteString;

import java.util.List;

/**
* An operation to query a table definition from Riak Time Series.
*
* @author Alex Moore <amoore at basho dot com>
* @since 2.0.4
*/
public class DescribeTableOperation extends PBFutureOperation<TableDefinition, RiakTsPB.TsQueryResp, String>
{
private final String tableName;
private final String queryText;

public DescribeTableOperation(String tableName)
{
this(new Builder(tableName));
}

private DescribeTableOperation(Builder builder)
{
super(RiakMessageCodes.MSG_TsQueryReq,
RiakMessageCodes.MSG_TsQueryResp,
RiakTsPB.TsQueryReq.newBuilder().setQuery(builder.interpolationBuilder),
RiakTsPB.TsQueryResp.PARSER);

this.queryText = builder.queryText;
this.tableName = builder.tableName;
}

@Override
protected TableDefinition convert(List<RiakTsPB.TsQueryResp> responses)
{
// This is not a streaming op, there will only be one response
final RiakTsPB.TsQueryResp response = checkAndGetSingleResponse(responses);
return PbResultFactory.convertDescribeResp(this.tableName, response);
}

@Override
public String getQueryInfo()
{
return this.queryText;
}

public static class Builder
{
private final String tableName;
private final String queryText;
private final RiakTsPB.TsInterpolation.Builder interpolationBuilder = RiakTsPB.TsInterpolation.newBuilder();

public Builder(String tableName)
{
if (tableName == null || tableName.length() == 0)
{
throw new IllegalArgumentException("Table Name cannot be null or empty");
}

this.tableName = tableName;
this.queryText = String.format("DESCRIBE %s", tableName);
this.interpolationBuilder.setBase(ByteString.copyFromUtf8(queryText));
}

public DescribeTableOperation build()
{
return new DescribeTableOperation(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,60 @@ private static ColumnDescription convertPBColumnDescription(RiakTsPB.TsColumnDes

return new ColumnDescription(name, type);
}

public static List<FullColumnDescription> convertDescribeQueryResultToColumnDescriptions(QueryResult queryResult)
{
final List<FullColumnDescription> fullColumnDescriptions = new ArrayList<>(queryResult.getRowsCount());

for (Row row : queryResult)
{
fullColumnDescriptions.add(convertDescribeResultRowToFullColumnDescription(row));
}

return fullColumnDescriptions;
}

private static FullColumnDescription convertDescribeResultRowToFullColumnDescription(Row row)
{
/*
* Expected Format for the DESCRIBE function is 5 columns:
*
* "Column" (non-null Varchar)
* "Type" (non-null Varchar)
* "Is Null" (non-null Boolean)
* "Partition Key" (nullable SInt64)
* "Local Key" (nullable SInt64)
*/

final List<Cell> cells = row.getCellsCopy();

assert(DescribeFnRowResultIsValid(cells));

final String name = cells.get(0).getVarcharAsUTF8String();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to add kinda sanity check of the row, just in case.. Maybe check number of cells or something like this.. As well as add a comment describes expected format

final String typeString = cells.get(1).getVarcharAsUTF8String();
final boolean isNullable = cells.get(2).getBoolean();
final boolean isPartitionKeyMember = cells.get(3) != null;
final boolean isLocalKeyMember = cells.get(4) != null;
final Integer partitionKeyOrdinal = isPartitionKeyMember ? new Long(cells.get(3).getLong()).intValue() : null;
final Integer localKeyOrdinal = isLocalKeyMember ? new Long(cells.get(4).getLong()).intValue() : null;

final ColumnDescription.ColumnType type =
ColumnDescription.ColumnType.valueOf(typeString.toUpperCase(Locale.ENGLISH));

return new FullColumnDescription(name,
type,
isNullable,
partitionKeyOrdinal,
localKeyOrdinal);
}

private static boolean DescribeFnRowResultIsValid(List<Cell> cells)
{
return cells.size() == 5 &&
cells.get(0).hasVarcharValue() &&
cells.get(1).hasVarcharValue() &&
cells.get(2).hasBoolean() &&
cells.get(3) != null ? cells.get(3).hasLong() : true &&
cells.get(4) != null ? cells.get(4).hasLong() : true;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.basho.riak.client.core.query.timeseries;

/**
* A Metadata description of a column in Riak Time Series.
* A minimal metadata description of a column in Riak Time Series.
* Contains a column name and column type.
*
* @author Alex Moore <amoore at basho dot com>
Expand All @@ -13,17 +13,41 @@ public class ColumnDescription
private final String name;
private final ColumnType type;

/**
* Create a new ColumnDescription.
* @param name The name of the column. Required - must not be null or an empty string.
* @param type The type of the column. Required - must not be null.
* @throws IllegalArgumentException if Column Name or Column Type are null or empty.
*/
public ColumnDescription(String name, ColumnType type)
{
if(name == null || name.isEmpty())
{
throw new IllegalArgumentException("Column Name must not be null or empty.");
}

if(type == null)
{
throw new IllegalArgumentException("Column Type must not be null.");
}

this.name = name;
this.type = type;
}

/**
* Get the Column Name.
* @return the column name String.
*/
public String getName()
{
return name;
}

/**
* Get the Column Type.
* @return the ColumnType value.
*/
public ColumnType getType()
{
return type;
Expand All @@ -40,4 +64,34 @@ public enum ColumnType
TIMESTAMP,
BOOLEAN
}

@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}

ColumnDescription that = (ColumnDescription) o;

if (!name.equals(that.name))
{
return false;
}
return type == that.type;

}

@Override
public int hashCode()
{
int result = name.hashCode();
result = 31 * result + type.hashCode();
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.basho.riak.client.core.query.timeseries;

/**
* Holds a complete definition for a Table Column in Time Series Riak.
* Immutable once created.
*
* @author Alex Moore <amoore at basho dot com>
* @since 2.0.4
*/
public class FullColumnDescription extends ColumnDescription
{
private final boolean isNullable;
private final Integer partitionKeyOrdinal;
private final Integer localKeyOrdinal;

/**
* Creates a basic FullColumnDescription, for non-key columns.
* @param name The name of the column. Required - must not be null or an empty string.
* @param type The type of the column. Required - must not be null.
* @param isNullable The nullability of the column.
* @throws IllegalArgumentException if Column Name or Column Type are null or empty.
*/
public FullColumnDescription(String name,
ColumnDescription.ColumnType type,
boolean isNullable)
{
this(name, type, isNullable, null, null);
}

/**
* Creates a FullColumnDescription. Useful for key columns where the partition and local key oridinals are the same.
* @param name The name of the column. Required - must not be null or an empty string.
* @param type The type of the column. Required - must not be null.
* @param isNullable The nullability of the column.
* @param keyOrdinal The ordinal number of where this column appears in the ordered Local Key column set.
* <b>Use null if not a key column.</b>
* @throws IllegalArgumentException if Column Name or Column Type are null or empty.
*/
public FullColumnDescription(String name,
ColumnDescription.ColumnType type,
boolean isNullable,
Integer keyOrdinal)
{
this(name, type, isNullable, keyOrdinal, keyOrdinal);
}

/**
* Creates a FullColumnDescription.
* Useful for automating creation of FullColumnDescriptions where the values can vary.
* @param name The name of the column. Required - must not be null or an empty string.
* @param type The type of the column. Required - must not be null.
* @param isNullable The nullability of the column.
* @param partitionKeyOrdinal The ordinal number of where this column appears in
* the ordered Partition Key column set.
* <b>Use null if not a key column.</b>
* @param localKeyOrdinal The ordinal number of where this column appears in
* the ordered Local Key column set.
* <b>Use null if not a key column.</b>
* @throws IllegalArgumentException if Column Name or Column Type are null or empty.
*/
public FullColumnDescription(String name,
ColumnDescription.ColumnType type,
boolean isNullable,
Integer partitionKeyOrdinal,
Integer localKeyOrdinal)
{
super(name, type);
this.isNullable = isNullable;
this.partitionKeyOrdinal = partitionKeyOrdinal;
this.localKeyOrdinal = localKeyOrdinal;
}

/**
* Whether this column's values are nullable.
* @return boolean
*/
public boolean isNullable()
{
return isNullable;
}

/**
* Whether this column is a member of the Partition Key column set.
* @return boolean.
*/
public boolean isPartitionKeyMember()
{
return partitionKeyOrdinal != null;
}

/**
* Whether this column is a member of the Local Key column set.
* @return boolean.
*/
public boolean isLocalKeyMember()
{
return localKeyOrdinal != null;
}

/**
* Get the ordinal number of where this column appears in the ordered Partition Key column set.
* @return Integer if {@link #isPartitionKeyMember()} is <i>true</i>,
* <b>null</b> if {@link #isPartitionKeyMember()} is <i>false</i>.
*/
public Integer getPartitionKeyOrdinal()
{
return partitionKeyOrdinal;
}

/**
* Get the ordinal number of where this column appears in the ordered Local Key column set.
* @return Integer if {@link #isLocalKeyMember()} is <i>true</i>,
* <b>null</b> if {@link #isLocalKeyMember()} is <i>false</i>.
*/
public Integer getLocalKeyOrdinal()
{
return localKeyOrdinal;
}
}
Loading