Marcos Pupo
Marcos Pupo

Reputation: 81

Corda - VaultQuery with aggregate SUM (field Double in MappedSchema)

I need to summarize a column of a state. I created a mappedSchema and defined the field as Double. If I list the states, the values for that field are correct. But if I use builder::sum(), the value returns with rounding problems and more decimal places than it should.

Here are excerpts from the code:

STATE

data class ConsumerMeteringState(val metering : ConsumerMetering,
                             val meteringParticipants : List<AbstractParty> = listOf(),
                             override val linearId: UniqueIdentifier = UniqueIdentifier()) :
    LinearState, QueryableState {
override val participants: List<AbstractParty> = meteringParticipants

override fun generateMappedObject(schema: MappedSchema): PersistentState {
    return when (schema) {
        is ConsumerMeteringSchemaV1 -> ConsumerMeteringSchemaV1.PersistentConsumerMetering(
                this.metering.dateTimeIni,
                this.metering.dateTimeEnd,
                this.metering.quantityKwh,
                this.linearId.id
        )
        else -> throw IllegalArgumentException("Unrecognised schema $schema")
    }
}

override fun supportedSchemas(): Iterable<MappedSchema> = listOf(ConsumerMeteringSchemaV1)

SCHEMA

object ConsumerMeteringSchemaV1 : MappedSchema(
    schemaFamily = ConsumerMeteringSchema.javaClass,
    version = 1,
    mappedTypes = listOf(PersistentConsumerMetering::class.java)) {
@Entity
@Table(name = "consumer_metering_states")
class PersistentConsumerMetering(
        @Column(name = "date_time_ini")
        var dateTimeIni: Instant,

        @Column(name = "date_time_end")
        var dateTimeEnd: Instant,

        @Column(name = "quantity_kwh")
        var quantityKwh: Double,

        @Column(name = "linear_id")
        var linearId: UUID
) : PersistentState() {
    // Default constructor required by hibernate.
    constructor(): this(Instant.now(), Instant.now(), 0.0, UUID.randomUUID())
}

}

VAULTQUERY CRITERIA

val criteriaAccount = QueryCriteria.VaultQueryCriteria(externalIds = listOf(accountId))
val sumQuantityKwh = builder { ConsumerMeteringSchemaV1
            .PersistentConsumerMetering::quantityKwh.sum() }
val sumQuantityKwhCriteria = QueryCriteria.VaultCustomQueryCriteria(sumQuantityKwh)
serviceHub.vaultService.queryBy(contractStateType = ConsumerMeteringState::class.java,
    criteria = criteriaAccount.and(sumQuantityKwhCriteria)).otherResults.singleOrNull()

States only (the values are OK):

[ConsumerMeteringState(metering=ConsumerMetering(dateTimeIni=2020-06-03T09:46:00Z, dateTimeEnd=2020-06-03T09:59:00Z, quantityKwh=10.55), meteringParticipants=[Anonymous(DL624i3ieTdLkPRBUvUgZnzn5jeG3Md2cvANt6sZNJiXwy), O=Distributor, L=Curitiba, C=BR], linearId=2e5009ad-56c3-4fed-ba36-deb0d48e668c), ConsumerMeteringState(metering=ConsumerMetering(dateTimeIni=2020-06-03T09:46:00Z, dateTimeEnd=2020-06-03T09:59:00Z, quantityKwh=50.18), meteringParticipants=[Anonymous(DLBep6kdDduaMKVrszQWa7N8i6YNnJLtA4WXsp4QmZiEjC), O=Distributor, L=Curitiba, C=BR], linearId=3b012984-676d-4e62-9b9f-1bb8158aaf4b)]

With builder sum:

I get the value 60.730000000000004

Why sum doesn't return 60.73 ?

Upvotes: 0

Views: 76

Answers (1)

Marcos Pupo
Marcos Pupo

Reputation: 81

It worked by changing the column type from Double to BigDecimal. It seems to be some question of precision of the Double type. I did a test just by retrieving the states and making a simple sum of the quantityKwh (Double) field and the precision was already strange. I didn't understand the reason for this behavior, but with BigDecimal it worked ok.

Upvotes: 1

Related Questions