Querying by composite key with a timestamp as a clustering column - spring-data-cassandra

I have a composite key with a partition key that is a uuid and a composite key that is a timestamp. Here's my entity.
#Table("send")
class Send(
#PrimaryKey val key: SendKey,
#Column("activity_id")
var activityId: UUID
) : Serializable
#PrimaryKeyClass
class SendKey(
#PrimaryKeyColumn(name = "user_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
val senderId: UUID,
#PrimaryKeyColumn(name = "created_at", ordinal = 3, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
val createdAt: Instant,
#PrimaryKeyColumn(name = "target_post_id", ordinal = 1, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
val targetUserId: UUID
): Serializable
Now, I'm trying to retrieve the unique record using sendRepository.findById(SendKey(userId = userId, createdAt = createdAt!!, targetUserId = postId)) but I don't get any results.
Here's the Repository
#Repository
interface SendRepository: ReactiveCassandraRepository<Send, SendKey> {
}
Where did I go wrong?
I'm using Jackson for parsing a default date format. Why can't I find a matching record when I specify the right format and timestamp down to microsecond precision?

Related

Drop column Room migration android

I have a table Server
#Entity(tableName = "servers")
data class ServerDto(
#PrimaryKey
#ColumnInfo(name = "server_id")
var serverId: Long,
#ColumnInfo(name = "address", defaultValue = "")
var serverAddress: String,
#ColumnInfo(name = "description", defaultValue = "")
var serverDescription: String,
#ColumnInfo(name = "file_segment")
var fileSegment: Int
) : Serializable
and a table accounts
#Entity(tableName = "accounts", primaryKeys = ["server_id", "account_id"])
data class AccountDto(
#ColumnInfo(name = "server_id")
val serverId: Long,
#ColumnInfo(name = "account_id")
val accountId: Int,
#ColumnInfo(name = "username", defaultValue = "")
val username: String,
#ColumnInfo(name = "password", defaultValue = "")
val password: String,
#ColumnInfo(name = "first_name", defaultValue = "")
var firstname: String,
#ColumnInfo(name = "last_name", defaultValue = "")
var lastname: String,
#ColumnInfo(name = "email", defaultValue = "")
var email: String,
#ColumnInfo(name = "active")
var active: Int
) : Serializable
I want to transfer 2 columns (username, password) from accounts to server and then remove them from accounts. I wrote the Migrations but i see that Android Studio does not allow to write DROP COLUMN since it underlines it with red. What is wrong with that??
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE servers ADD COLUMN username VARCHAR")
database.execSQL("ALTER TABLE servers ADD COLUMN password VARCHAR")
database.execSQL("UPDATE servers SET username = (SELECT a.username FROM accounts a where a.server_id = servers.server_id and a.active = 1)")
database.execSQL("UPDATE servers SET password = (SELECT a.password FROM accounts a where a.server_id = servers.server_id and a.active = 1)")
database.execSQL("ALTER TABLE accounts ***DROP*** COLUMN username")
database.execSQL("ALTER TABLE accounts ***DROP*** COLUMN password")
}
SQLite doesn't support column deletion straight away.
You will have to do migration steps as follows:
Source: https://www.sqlite.org/faq.html#q11
CREATE TABLE accounts_backup(serverId VARCHAR, accountId VARCHAR, firstname VARCHAR, lastname VARCHAR, email VARCHAR, active VARCHAR);
INSERT INTO accounts_backup SELECT serverId, accountId, firstname, lastname, email, active FROM accounts;
DROP TABLE accounts;
CREATE TABLE accounts(serverId VARCHAR, accountId VARCHAR, firstname VARCHAR, lastname VARCHAR, email VARCHAR, active VARCHAR);
INSERT INTO accounts SELECT serverId, accountId, firstname, lastname, email, active FROM accounts_backup;
DROP TABLE accounts_backup;
Here's a combination of the previous two answers, written in Kotlin for Android:
private val MIGRATION_3_2 = object : Migration(3,2) {
override fun migrate(database: SupportSQLiteDatabase) {
//Drop column isn't supported by SQLite, so the data must manually be moved
with(database) {
execSQL("CREATE TABLE Users_Backup (id INTEGER, name TEXT, PRIMARY KEY (id))")
execSQL("INSERT INTO Users_Backup SELECT id, name FROM Users")
execSQL("DROP TABLE Users")
execSQL("ALTER TABLE Users_Backup RENAME to Users")
}
}
}

Cassandra quill Codec not found for requested operation

I followed the example given in the docs but the following fails with Codec not found for requested operation: [varchar <-> java.util.UUID]. How is one supposed to provide a custom Cassandra codec with Quill?
import java.util.UUID
import javax.inject.Inject
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future}
import io.getquill.{CassandraAsyncContext, LowerCase, MappedEncoding}
import scala.concurrent.duration._
object Main extends App {
case class MyOrder(id: String, uuid: UUID)
trait OrderRepository {
implicit val encodeUUID: MappedEncoding[UUID, String] = MappedEncoding[UUID, String](_.toString)
implicit val decodeUUID: MappedEncoding[String, UUID] = MappedEncoding[String, UUID](UUID.fromString)
def list(): Future[Iterable[MyOrder]]
def get(id: String): Future[Option[MyOrder]]
}
class OrderRepositoryImpl(db: CassandraAsyncContext[LowerCase]) extends OrderRepository {
import db._
override def list(): Future[Iterable[MyOrder]] = {
run(quote(query[MyOrder]))
}
override def get(id: String): Future[Option[MyOrder]] = {
val q = quote {
(id: String) =>
query[MyOrder].filter(_.id == id)
}
val res = run(q(lift(id.toString)))
res.map(_.headOption)
}
}
val db = new CassandraAsyncContext[LowerCase]("db")
val repo = new OrderRepositoryImpl(db)
val maybeOrder = Await.result(repo.get("id1"), 2 seconds)
println(s"maybeOrder $maybeOrder")
}
and the Cassandra ddl:
CREATE TABLE myorder (
id text,
uuid text,
PRIMARY KEY (id)
);
INSERT INTO myorder (
id,
uuid
) values (
'id1',
'a8a8a416-2436-4e18-82b3-d5881c8fec1a'
);
Obviously I can just create a class whose uuid field is of type String but the goal here is to figure out how to use custom decoders.

Typesafe Slick 2.0.1-RC insert into database

I have problem when inserting into database. I use slick version 2.0.1-RC. I have used SourceCodeGenerator for generating source code. I have got this for table MAIN_TC_USER:
case class MainTcUserRow(id: Int, name: Option[String], surname: Option[String], username: Option[String], password: Option[String])
/** GetResult implicit for fetching MainTcUserRow objects using plain SQL queries */
implicit def GetResultMainTcUserRow(implicit e0: GR[Int], e1: GR[Option[String]]): GR[MainTcUserRow] = GR{
prs => import prs._
MainTcUserRow.tupled((<<[Int], <<?[String], <<?[String], <<?[String], <<?[String]))
}
/** Table description of table main_tc_user. Objects of this class serve as prototypes for rows in queries. */
class MainTcUser(tag: Tag) extends Table[MainTcUserRow](tag, "main_tc_user") {
def * = (id, name, surname, username, password) <> (MainTcUserRow.tupled, MainTcUserRow.unapply)
/** Maps whole row to an option. Useful for outer joins. */
def ? = (id.?, name, surname, username, password).shaped.<>({r=>import r._; _1.map(_=> MainTcUserRow.tupled((_1.get, _2, _3, _4, _5)))}, (_:Any) => throw new Exception("Inserting into ? projection not supported."))
/** Database column id PrimaryKey */
val id: Column[Int] = column[Int]("id", O.PrimaryKey)
/** Database column name */
val name: Column[Option[String]] = column[Option[String]]("name")
/** Database column surname */
val surname: Column[Option[String]] = column[Option[String]]("surname")
/** Database column username */
val username: Column[Option[String]] = column[Option[String]]("username")
/** Database column password */
val password: Column[Option[String]] = column[Option[String]]("password")
}
/** Collection-like TableQuery object for table MainTcUser */
lazy val MainTcUser = new TableQuery(tag => new MainTcUser(tag))
I have tried to insert into MainTcUser table
new DBConnection(Tables.profile).connect.withSession{
implicit session =>
Tables.MainTcUser += user
}
or
new DBConnection(Tables.profile).connect.withSession{
implicit session =>
Tables.MainTcUser.map(s => s) += user
}
In both cases I've got error:
Multiple markers at this line
- value += is not a member of
scala.slick.lifted.TableQuery[com.bsi.xpay.Tables.MainTcUser]
- value += is not a member of
scala.slick.lifted.TableQuery[com.bsi.xpay.Tables.MainTcUser]
Thanks for any help
You probably forgot to import .simple._ from you driver.
If that's not it also see Can't access delete method on Slick query which is related.

Retrieving data from composite key via astyanax

I am very naive in cassandra & am using astyanax
CREATE TABLE employees (empID int, deptID int, first_name varchar,
last_name varchar, PRIMARY KEY (empID, deptID));
i want to get the values of query:
select * from employees where empID =2 and deptID = 800;
public void read(Integer empID, String deptID) {
OperationResult<ColumnList<String>> result;
try {
columnFamilies = ColumnFamily.newColumnFamily("employees", IntegerSerializer.get(), StringSerializer.get());
result = keyspace.prepareQuery(columnFamilies).getKey(empID).execute();
ColumnList<String> cols = result.getResult();
//Other stuff
}
how should i achieve this
As far as I can find, there isn't a super clean way to do this. You have to do it by executing a cql query and then iterating through the rows. This code is taken from the astynax examples file
public void read(int empId) {
logger.debug("read()");
try {
OperationResult<CqlResult<Integer, String>> result
= keyspace.prepareQuery(EMP_CF)
.withCql(String.format("SELECT * FROM %s WHERE %s=%d;", EMP_CF_NAME, COL_NAME_EMPID, empId))
.execute();
for (Row<Integer, String> row : result.getResult().getRows()) {
logger.debug("row: "+row.getKey()+","+row); // why is rowKey null?
ColumnList<String> cols = row.getColumns();
logger.debug("emp");
logger.debug("- emp id: "+cols.getIntegerValue(COL_NAME_EMPID, null));
logger.debug("- dept: "+cols.getIntegerValue(COL_NAME_DEPTID, null));
logger.debug("- firstName: "+cols.getStringValue(COL_NAME_FIRST_NAME, null));
logger.debug("- lastName: "+cols.getStringValue(COL_NAME_LAST_NAME, null));
}
} catch (ConnectionException e) {
logger.error("failed to read from C*", e);
throw new RuntimeException("failed to read from C*", e);
}
}
You just have to tune the cql query to return what you want. This is a bit frustrating because according to the documentation, you can do
Column<String> result = keyspace.prepareQuery(CF_COUNTER1)
.getKey(rowKey)
.getColumn("Column1")
.execute().getResult();
Long counterValue = result.getLongValue();
However I don't know what rowkey is. I've posted a question about what rowkey can be. Hopefully that will help

Grails 2.1 How Can i add value in join table

I create 2 tables one Category and one Manufacturer, and There relationship is Many-to-Many,
So i use a join table,
I insert values into two tables individually. Now i want to join two table by their id, but i cannot do, Can you help me....
When i try to insert value in join table give an exception, here is the exception:
Cannot invoke method addToManufacturers() on null object. Stacktrace follows:
java.lang.NullPointerException: Cannot invoke method addToManufacturers() on null object
here is my domain class for Category
static hasMany = [manufacturers: Manufacturer]
static constraints = {
name blank: false, size: 0..60, unique: false
}
static mapping = {
table 't01i001'
id column: 'f_category_id'
name column: 'f_name', length: 30
version column: 'f_revision'
manufacturers joinTable: [name: 't01j001', key: 'k_category_id', column: 'k_manufacturer_id']
}
here is my domain class for manufacturer
static belongsTo = Category
static hasMany = [categories: Category]
static constraints = {
name blank: false, size: 0..60, unique: false
}
static mapping = {
table 't01i002'
id column: 'f_manufacturer_id'
name column: 'f_name', length: 30
version column: 'f_revision'
categories joinTable: [name: 't01j001', key: 'k_manufacturer_id', column: 'k_category_id']
}
add my controller where i try to insert
def manuInsertInCat(){
def message, flag,count=0,categories = []
int catid = params.containsKey("catid") ? params.catid : '0'
int manuid = params.containsKey("manuid") ? params.manuid : '0'
def category = Category.get(catid);
def manufacture = Manufacturer.get(manuid)
category.addToManufacturers(manufacture)
message = "Successfully Loaded"
count++
flag =true
render Category.getJsonData(categories, count, flag, message)
}
At last i complete my job by this process its works fine.
def catInsertInManu(){
def message, flag,count=0,manufacturers = []
String catid = params.containsKey("catid") ? params.catid : '0'
String manuid = params.containsKey("manuid") ? params.manuid : '0'
def category = Category.get(catid)
def manufacture = Manufacturer.get(manuid)
manufacture.addToCategories(category)
def m01i001001s = []
manufacture.categories.each{ cat ->
m01i001001s << [id:cat.id, name:cat.name]
}
manufacturers << [id: manufacture.id, name:manufacture.name, m01i001001s:m01i001001s]
message = "Successfully Loaded"
count++
flag =true
render Manufacturer.getJsonData(manufacturers, count, flag, message)
}

Resources