mirror of
https://github.com/corda/corda.git
synced 2024-12-20 21:43:14 +00:00
CORDA-3182: Added additional property on VaultQueryCriteria for querying by account (#5423)
* Added an additional property on VaultQueryCriteria to specify an externalId/accountId when performing a vault query. Added logic in hibernate query criteria parser to handle the exernalId join and lookup. Added a test. * Fixed error in test. Fixed backwards incompatible changes. * Updated changelog. * Updated docs to remove incorrect instructions for querying by external ID.
This commit is contained in:
parent
c2057e0893
commit
99f4e4aac2
@ -81,6 +81,7 @@ sealed class QueryCriteria : GenericQueryCriteria<QueryCriteria, IQueryCriteriaP
|
|||||||
open val constraints: Set<Vault.ConstraintInfo> = emptySet()
|
open val constraints: Set<Vault.ConstraintInfo> = emptySet()
|
||||||
open val participants: List<AbstractParty>? = null
|
open val participants: List<AbstractParty>? = null
|
||||||
abstract val contractStateTypes: Set<Class<out ContractState>>?
|
abstract val contractStateTypes: Set<Class<out ContractState>>?
|
||||||
|
open val externalIds: List<UUID> = emptyList()
|
||||||
override fun visit(parser: IQueryCriteriaParser): Collection<Predicate> {
|
override fun visit(parser: IQueryCriteriaParser): Collection<Predicate> {
|
||||||
return parser.parseCriteria(this)
|
return parser.parseCriteria(this)
|
||||||
}
|
}
|
||||||
@ -99,8 +100,24 @@ sealed class QueryCriteria : GenericQueryCriteria<QueryCriteria, IQueryCriteriaP
|
|||||||
override val relevancyStatus: Vault.RelevancyStatus = Vault.RelevancyStatus.ALL,
|
override val relevancyStatus: Vault.RelevancyStatus = Vault.RelevancyStatus.ALL,
|
||||||
override val constraintTypes: Set<Vault.ConstraintInfo.Type> = emptySet(),
|
override val constraintTypes: Set<Vault.ConstraintInfo.Type> = emptySet(),
|
||||||
override val constraints: Set<Vault.ConstraintInfo> = emptySet(),
|
override val constraints: Set<Vault.ConstraintInfo> = emptySet(),
|
||||||
override val participants: List<AbstractParty>? = null
|
override val participants: List<AbstractParty>? = null,
|
||||||
|
override val externalIds: List<UUID> = emptyList()
|
||||||
) : CommonQueryCriteria() {
|
) : CommonQueryCriteria() {
|
||||||
|
// V4 constructors.
|
||||||
|
@DeprecatedConstructorForDeserialization(version = 7)
|
||||||
|
constructor(
|
||||||
|
status: Vault.StateStatus = Vault.StateStatus.UNCONSUMED,
|
||||||
|
contractStateTypes: Set<Class<out ContractState>>? = null,
|
||||||
|
stateRefs: List<StateRef>? = null,
|
||||||
|
notary: List<AbstractParty>? = null,
|
||||||
|
softLockingCondition: SoftLockingCondition? = null,
|
||||||
|
timeCondition: TimeCondition? = null,
|
||||||
|
relevancyStatus: Vault.RelevancyStatus = Vault.RelevancyStatus.ALL,
|
||||||
|
constraintTypes: Set<Vault.ConstraintInfo.Type> = emptySet(),
|
||||||
|
constraints: Set<Vault.ConstraintInfo> = emptySet(),
|
||||||
|
participants: List<AbstractParty>? = null
|
||||||
|
) : this(status, contractStateTypes, stateRefs, notary, softLockingCondition, timeCondition, relevancyStatus, constraintTypes, constraints, participants, emptyList())
|
||||||
|
|
||||||
// V3 c'tors
|
// V3 c'tors
|
||||||
// These have to be manually specified as @JvmOverloads for some reason causes declaration clashes
|
// These have to be manually specified as @JvmOverloads for some reason causes declaration clashes
|
||||||
@DeprecatedConstructorForDeserialization(version = 6)
|
@DeprecatedConstructorForDeserialization(version = 6)
|
||||||
@ -144,6 +161,34 @@ sealed class QueryCriteria : GenericQueryCriteria<QueryCriteria, IQueryCriteriaP
|
|||||||
fun withConstraintTypes(constraintTypes: Set<Vault.ConstraintInfo.Type>): VaultQueryCriteria = copy(constraintTypes = constraintTypes)
|
fun withConstraintTypes(constraintTypes: Set<Vault.ConstraintInfo.Type>): VaultQueryCriteria = copy(constraintTypes = constraintTypes)
|
||||||
fun withConstraints(constraints: Set<Vault.ConstraintInfo>): VaultQueryCriteria = copy(constraints = constraints)
|
fun withConstraints(constraints: Set<Vault.ConstraintInfo>): VaultQueryCriteria = copy(constraints = constraints)
|
||||||
fun withParticipants(participants: List<AbstractParty>): VaultQueryCriteria = copy(participants = participants)
|
fun withParticipants(participants: List<AbstractParty>): VaultQueryCriteria = copy(participants = participants)
|
||||||
|
fun withExternalIds(externalIds: List<UUID>): VaultQueryCriteria = copy(externalIds = externalIds)
|
||||||
|
|
||||||
|
fun copy(
|
||||||
|
status: Vault.StateStatus = Vault.StateStatus.UNCONSUMED,
|
||||||
|
contractStateTypes: Set<Class<out ContractState>>? = null,
|
||||||
|
stateRefs: List<StateRef>? = null,
|
||||||
|
notary: List<AbstractParty>? = null,
|
||||||
|
softLockingCondition: SoftLockingCondition? = null,
|
||||||
|
timeCondition: TimeCondition? = null,
|
||||||
|
relevancyStatus: Vault.RelevancyStatus = Vault.RelevancyStatus.ALL,
|
||||||
|
constraintTypes: Set<Vault.ConstraintInfo.Type> = emptySet(),
|
||||||
|
constraints: Set<Vault.ConstraintInfo> = emptySet(),
|
||||||
|
participants: List<AbstractParty>? = null
|
||||||
|
): VaultQueryCriteria {
|
||||||
|
return VaultQueryCriteria(
|
||||||
|
status,
|
||||||
|
contractStateTypes,
|
||||||
|
stateRefs,
|
||||||
|
notary,
|
||||||
|
softLockingCondition,
|
||||||
|
timeCondition,
|
||||||
|
relevancyStatus,
|
||||||
|
constraintTypes,
|
||||||
|
constraints,
|
||||||
|
participants,
|
||||||
|
externalIds
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun copy(
|
fun copy(
|
||||||
status: Vault.StateStatus = this.status,
|
status: Vault.StateStatus = this.status,
|
||||||
@ -163,7 +208,8 @@ sealed class QueryCriteria : GenericQueryCriteria<QueryCriteria, IQueryCriteriaP
|
|||||||
relevancyStatus,
|
relevancyStatus,
|
||||||
constraintTypes,
|
constraintTypes,
|
||||||
constraints,
|
constraints,
|
||||||
participants
|
participants,
|
||||||
|
externalIds
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -654,24 +654,5 @@ a view which maps each state to one or more external IDs. The entity relationshi
|
|||||||
|
|
||||||
.. image:: resources/state-to-external-id.png
|
.. image:: resources/state-to-external-id.png
|
||||||
|
|
||||||
When performing a vault query, it is now possible to query for states by external ID using a custom query criteria.
|
When performing a vault query, it is now possible to query for states by external ID using the ``externalIds`` parameter in
|
||||||
|
``VaultQueryCriteria``.
|
||||||
.. container:: codeset
|
|
||||||
|
|
||||||
.. sourcecode:: java
|
|
||||||
|
|
||||||
UUID id = someExternalId;
|
|
||||||
FieldInfo externalIdField = getField("externalId", VaultSchemaV1.StateToExternalId.class);
|
|
||||||
CriteriaExpression externalId = Builder.equal(externalIdField, id);
|
|
||||||
QueryCriteria query = new VaultCustomQueryCriteria(externalId);
|
|
||||||
Vault.Page<StateType> results = vaultService.queryBy(StateType.class, query);
|
|
||||||
|
|
||||||
.. sourcecode:: kotlin
|
|
||||||
|
|
||||||
val id: UUID = someExternalId
|
|
||||||
val externalId = builder { VaultSchemaV1.StateToExternalId::externalId.equal(id) }
|
|
||||||
val queryCriteria = QueryCriteria.VaultCustomQueryCriteria(externalId)
|
|
||||||
val results = vaultService.queryBy<StateType>(queryCriteria).states
|
|
||||||
|
|
||||||
The ``VaultCustomQueryCriteria`` can also be combined with other query criteria, like custom schemas, for instance. See the vault query API
|
|
||||||
examples above for how to combine ``QueryCriteria``.
|
|
@ -7,6 +7,9 @@ release, see :doc:`app-upgrade-notes`.
|
|||||||
Unreleased
|
Unreleased
|
||||||
----------
|
----------
|
||||||
|
|
||||||
|
* Introduced a new parameter ``externalIds: List<UUID>`` to ``VaultQueryCriteria`` which allows CorDapp developers to constrain queries
|
||||||
|
to a specified set of external IDs.
|
||||||
|
|
||||||
* Introduced a new API on ``KeyManagementService`` which facilitates lookups of ``PublicKey`` s to ``externalId`` s (Account IDs).
|
* Introduced a new API on ``KeyManagementService`` which facilitates lookups of ``PublicKey`` s to ``externalId`` s (Account IDs).
|
||||||
|
|
||||||
* Introduced a new low level flow diagnostics tool: checkpoint agent (that can be used standalone or in conjunction with the ``dumpCheckpoints`` shell command).
|
* Introduced a new low level flow diagnostics tool: checkpoint agent (that can be used standalone or in conjunction with the ``dumpCheckpoints`` shell command).
|
||||||
|
@ -659,6 +659,25 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External IDs.
|
||||||
|
if (criteria.externalIds.isNotEmpty()) {
|
||||||
|
val ids = criteria.externalIds
|
||||||
|
|
||||||
|
// Get the state to external id entity.
|
||||||
|
val persistentStateToExternalIdEntity = VaultSchemaV1.StateToExternalId::class.java
|
||||||
|
val entityRoot = rootEntities.getOrElse(persistentStateToExternalIdEntity) {
|
||||||
|
val entityRoot = criteriaQuery.from(persistentStateToExternalIdEntity)
|
||||||
|
rootEntities[persistentStateToExternalIdEntity] = entityRoot
|
||||||
|
entityRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the join and external id predicates.
|
||||||
|
val externalIdJoin = criteriaBuilder.equal(vaultStates.get<VaultSchemaV1.VaultStates>("stateRef"), entityRoot.get<VaultSchemaV1.StateToExternalId>("compositeKey").get<PersistentStateRef>("stateRef"))
|
||||||
|
val externalIdPredicate = criteriaBuilder.and(entityRoot.get<VaultSchemaV1.StateToExternalId>("externalId").`in`(ids))
|
||||||
|
constraintPredicates.add(externalIdJoin)
|
||||||
|
constraintPredicates.add(externalIdPredicate)
|
||||||
|
}
|
||||||
|
|
||||||
return emptySet()
|
return emptySet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,47 @@ class ExternalIdMappingTest {
|
|||||||
assertEquals(setOf(dummyStateOne, dummyStateTwo), resultTwo.map { it.state.data }.toSet())
|
assertEquals(setOf(dummyStateOne, dummyStateTwo), resultTwo.map { it.state.data }.toSet())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `externalIds query criteria test`() {
|
||||||
|
val vaultService = services.vaultService
|
||||||
|
|
||||||
|
// Create new external ID and two keys mapped to it.
|
||||||
|
val id = UUID.randomUUID()
|
||||||
|
val idTwo = UUID.randomUUID()
|
||||||
|
val keyOne = services.keyManagementService.freshKeyAndCert(myself.identity, false, id)
|
||||||
|
val keyTwo = services.keyManagementService.freshKeyAndCert(myself.identity, false, id)
|
||||||
|
val keyThree = services.keyManagementService.freshKeyAndCert(myself.identity, false, idTwo)
|
||||||
|
|
||||||
|
// Create states with a public key assigned to the new external ID.
|
||||||
|
val dummyStateOne = createDummyState(listOf(AnonymousParty(keyOne.owningKey)))
|
||||||
|
val dummyStateTwo = createDummyState(listOf(AnonymousParty(keyTwo.owningKey)))
|
||||||
|
val dummyStateThree = createDummyState(listOf(AnonymousParty(keyThree.owningKey)))
|
||||||
|
|
||||||
|
// This query should return two states!
|
||||||
|
val result = database.transaction {
|
||||||
|
vaultService.queryBy<DummyState>(QueryCriteria.VaultQueryCriteria(externalIds = listOf(id))).states
|
||||||
|
}
|
||||||
|
assertEquals(setOf(dummyStateOne, dummyStateTwo), result.map { it.state.data }.toSet())
|
||||||
|
|
||||||
|
// Should return nothing.
|
||||||
|
val resultTwo = database.transaction {
|
||||||
|
vaultService.queryBy<DummyState>(QueryCriteria.VaultQueryCriteria(externalIds = listOf(UUID.randomUUID()))).states
|
||||||
|
}
|
||||||
|
assertEquals(emptyList(), resultTwo)
|
||||||
|
|
||||||
|
// Should return one state.
|
||||||
|
val resultThree = database.transaction {
|
||||||
|
vaultService.queryBy<DummyState>(QueryCriteria.VaultQueryCriteria(externalIds = listOf(idTwo))).states
|
||||||
|
}
|
||||||
|
assertEquals(setOf(dummyStateThree), resultThree.map { it.state.data }.toSet())
|
||||||
|
|
||||||
|
// Should return all states.
|
||||||
|
val resultFour = database.transaction {
|
||||||
|
vaultService.queryBy<DummyState>(QueryCriteria.VaultQueryCriteria(externalIds = listOf())).states
|
||||||
|
}
|
||||||
|
assertEquals(setOf(dummyStateOne, dummyStateTwo, dummyStateThree), resultFour.map { it.state.data }.toSet())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `One state can be mapped to multiple externalIds`() {
|
fun `One state can be mapped to multiple externalIds`() {
|
||||||
val vaultService = services.vaultService
|
val vaultService = services.vaultService
|
||||||
|
Loading…
Reference in New Issue
Block a user