Phantom-DSL cassandra with frozen type

夙愿已清 提交于 2019-12-13 06:59:56

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!