问题
I'm trying to map a column which is a Map with frozen type
My column family has a field
batsmen_data map<text, frozen<bat_card>>
bat_card has two fields
bat_id int,
bat_name text,
Map the column field
object batsmenData extends MapColumn[ScoreCardData, ScoreCard, String ,Batting](this) {
override lazy val name="batsmen_data"
}
This is not an ideal way to do it. Because MapColumn Supports only primitive types. Can any one help me out on how to create a UDT Columns
回答1:
I've figured out a way to map the UDT using phantom. But not sure this is right way.
I have a column
batsmen_data map<text, frozen<bat_card>>
To map this, we write the below code
object batsmenData extends MapColumn[ScoreCardData, ScoreCard, String, Batting](this) with CustomPrimitives {
override lazy val name="batsmen_data"
}
When you compile, error will be shown No Primitive found for class Batting
This is because Phantom has defined Primitives for native types like String, Int etc. To avoid you have to define primitive for class Batting as shown below(You have to extend CustomPrimitives trait in the class, else you will get the same error).
trait CustomPrimitives extends Config {
implicit object BattingPrimitive extends Primitive[Batting]{
override type PrimitiveType = Batting
override def clz: Class[Batting] = classOf[Batting]
override def cassandraType: String = {
Connector.session.getCluster.getMetadata.getKeyspace(cassandraKeyspace).getUserType("bat_card").toString()
}
override def fromRow(column: String, row: dsl.Row): Try[Batting] = ???
override def fromString(value: String): Batting = ???
override def asCql(value: Batting): String = ???
}
After this one more error will be shown saying Codec not found for requested operation: [frozen <-> Batting]. This is because cassandra expects a codec for the custom UDT type to serialize and deserialze the data. To Avoid this you have to write a CodecClass which will help to deserialize(as i need only deserializing) the UDT value into custom object.
public class BattingCodec extends TypeCodec<Batting>{
protected BattingCodec(TypeCodec<UDTValue> innerCodec, Class<Batting> javaType) {
super(innerCodec.getCqlType(), javaType);
}
@Override
public ByteBuffer serialize(Batting value, ProtocolVersion protocolVersion) throws InvalidTypeException {
return null;
}
@Override
public Batting deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion) throws InvalidTypeException {
return null;
}
@Override
public Batting parse(String value) throws InvalidTypeException {
return null;
}
@Override
public String format(Batting value) throws InvalidTypeException {
return null;
}
}
Once the codec is defined last step is to register this codec into codec registry.
val codecRegistry = CodecRegistry.DEFAULT_INSTANCE
val bat_card = Connector.session.getCluster.getMetadata.getKeyspace(cassandraKeyspace).getUserType("bat_card")
val batCodec = new BattingCodec(TypeCodec.userType(bat_card), classOf[Batting])
codecRegistry.register(batCodec)
Now using deserialize function in BattingCodec, we can map the bytes to required object.
This method is working fine. But i'm not sure this is the ideal way to achieve the UDT functionality using Phantom
来源:https://stackoverflow.com/questions/34633440/phantom-dsl-cassandra-with-frozen-type