Corda - Queries on QueryableState Child Tables

Viewed 105

Background

I have a problem with being able to query child data in a sample Corda application, demonstrating how to persisnt hierarchical data using QueryableState.

For reference:

The car insurance sample demonstrates how to set up:

  • a One-to-One relationship between PersistentInsurance and PersistentVehicle
  • a One-to-Many relationship between PersistentInsurance and PersistentClaim

Problem

What the car insurance sample doesn't demonstrate is how to query that data. Building vault queries from PersistentInsurance is fairly trivial as we can use VaultCustomQueryCriteria to build custom query expressions over the properties of PersistentInsurance, however the same is not true for the child tables in the hierarchy. This is because PersistentInsurance extends PersistentState, whereas PersistentVehicle and PersistentClaim don't.

For Reference, the underlying type hierarchy for PersistentState is as follows:

StatePersistable > DirectStatePersistable > PersistentState

interface StatePersistable

interface DirectStatePersistable : StatePersistable {
    val stateRef: PersistentStateRef?
}

class PersistentState(@EmbeddedId override var stateRef: PersistentStateRef? = null) : DirectStatePersistable

data class PersistentStateRef(
        @Suppress("MagicNumber") // column width
        @Column(name = "transaction_id", length = 144, nullable = false)
        var txId: String,

        @Column(name = "output_index", nullable = false)
        var index: Int
) : Serializable {
    constructor(stateRef: StateRef) : this(stateRef.txhash.toString(), stateRef.index)
}

Going back to the car insurance sample, we can't use VaultCustomQueryCriteria for PersistentVehicle or PersistentClaim as VaultCustomQueryCriteria::expression has a generic constraint on StatePersistable:

data class VaultCustomQueryCriteria<L : StatePersistable>(
    val expression: CriteriaExpression<L, Boolean>,
    ...
) : CommonQueryCriteria() { ... }

What I've Tried

Implementing StatePersistable on PersistentVehicle and/or PersistentClaim causes the following error when you create a VaultCustomQueryCriteria using any of the properties from those classes:

net.corda.core.node.services.VaultQueryException: Parsing error: Unable to locate Attribute with the the given name [stateRef] on this ManagedType [...$PersistentClaim]

Implementing DirectStatePersistable or PersistentState on PersistentVehicle and/or PersistentClaim causes an internal error when finalizing the transaction. The flow hangs and eventually times out. I wasn't able to determine exactly where the error occurs as the code is buried inside internal implementations for underlying Corda services.

What Does Work (In a Limited Capacity)

I'm aware that we can execute custom SQL queries; for example:

val sqlQuery = buildString {
    appendln("SELECT TRANSACTION_ID, OUTPUT_INDEX")
    appendln("FROM CLAIM_DETAIL")
    appendln("WHERE claimNumber = '123'")
}

val stateRefs = serviceHub.jdbcSession().executeCaseInsensitiveQuery(sqlQuery).map {
    val txId = SecureHash.parse(it.getString("TRANSACTION_ID")
    val index = it.getInt("OUTPUT_INDEX")
    StateRef(txId, index)
}.toList().toBlocking().first()

VaultQueryCriteria(stateRefs = stateRefs)

Needless to say, that's hideous compared to:

VaultCustomQueryCriteria(PersistentClaim::claimNumber.equal("123"))

As for why it works in a limited capacity, this works fine for queries inside the node, which access to the service hub, but doesn't work over RPC as there's no access to a jdbcSession.

So, any ideas (if it's at all possible), on how we can improve the query capability of child tables?

1 Answers

@Matthew Layton I have put your concerns to the engineering team. The team has looked into this.

To address/fix this issue, requires lot of platform changes.

For time being I would suggest you to manage with using native queries. We are planning to prioritise this issue. I will keep you posted on this.

Related