Merge branch 'release/os/4.4' into nnagy-os-4.4-os-4.5-20200511

This commit is contained in:
nikinagy 2020-05-11 16:32:53 +01:00
commit e0b5319515
4 changed files with 205 additions and 13 deletions

View File

@ -302,7 +302,13 @@ sealed class QueryCriteria : GenericQueryCriteria<QueryCriteria, IQueryCriteriaP
status: Vault.StateStatus = Vault.StateStatus.UNCONSUMED, status: Vault.StateStatus = Vault.StateStatus.UNCONSUMED,
contractStateTypes: Set<Class<out ContractState>>? = null, contractStateTypes: Set<Class<out ContractState>>? = null,
relevancyStatus: Vault.RelevancyStatus = Vault.RelevancyStatus.ALL relevancyStatus: Vault.RelevancyStatus = Vault.RelevancyStatus.ALL
) : this(participants, linearId?.map { it.id }, linearId?.mapNotNull { it.externalId }, status, contractStateTypes, relevancyStatus) ) : this(participants,
linearId?.map { it.id }.takeIf { it != null && it.isNotEmpty() },
linearId?.mapNotNull { it.externalId }.takeIf { it != null && it.isNotEmpty() },
status,
contractStateTypes,
relevancyStatus
)
// V3 c'tor // V3 c'tor
@DeprecatedConstructorForDeserialization(version = 1) @DeprecatedConstructorForDeserialization(version = 1)

View File

@ -153,6 +153,18 @@ abstract class AbstractQueryCriteriaParser<Q : GenericQueryCriteria<Q,P>, in P:
NOT_NULL -> criteriaBuilder.isNotNull(column) NOT_NULL -> criteriaBuilder.isNotNull(column)
} }
} }
/**
* Returns the given predicate if the provided `args` list is not empty
* If the list is empty it returns an always false predicate (1=0)
*/
protected fun checkIfListIsEmpty(args: List<Any>, criteriaBuilder: CriteriaBuilder, predicate: Predicate): Predicate {
return if (args.isEmpty()) {
criteriaBuilder.and(criteriaBuilder.equal(criteriaBuilder.literal(1), 0))
} else {
predicate
}
}
} }
class HibernateAttachmentQueryCriteriaParser<T,R>(override val criteriaBuilder: CriteriaBuilder, class HibernateAttachmentQueryCriteriaParser<T,R>(override val criteriaBuilder: CriteriaBuilder,
@ -215,7 +227,14 @@ class HibernateAttachmentQueryCriteriaParser<T,R>(override val criteriaBuilder:
(criteria.contractClassNamesCondition as EqualityComparison<List<ContractClassName>>).rightLiteral (criteria.contractClassNamesCondition as EqualityComparison<List<ContractClassName>>).rightLiteral
else emptyList() else emptyList()
val joinDBAttachmentToContractClassNames = root.joinList<NodeAttachmentService.DBAttachment, ContractClassName>("contractClassNames") val joinDBAttachmentToContractClassNames = root.joinList<NodeAttachmentService.DBAttachment, ContractClassName>("contractClassNames")
predicateSet.add(criteriaBuilder.and(joinDBAttachmentToContractClassNames.`in`(contractClassNames)))
predicateSet.add(
checkIfListIsEmpty(
args = contractClassNames,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(joinDBAttachmentToContractClassNames.`in`(contractClassNames))
)
)
} }
criteria.signersCondition?.let { criteria.signersCondition?.let {
@ -224,7 +243,14 @@ class HibernateAttachmentQueryCriteriaParser<T,R>(override val criteriaBuilder:
(criteria.signersCondition as EqualityComparison<List<PublicKey>>).rightLiteral (criteria.signersCondition as EqualityComparison<List<PublicKey>>).rightLiteral
else emptyList() else emptyList()
val joinDBAttachmentToSigners = root.joinList<NodeAttachmentService.DBAttachment, PublicKey>("signers") val joinDBAttachmentToSigners = root.joinList<NodeAttachmentService.DBAttachment, PublicKey>("signers")
predicateSet.add(criteriaBuilder.and(joinDBAttachmentToSigners.`in`(signers)))
predicateSet.add(
checkIfListIsEmpty(
args = signers,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(joinDBAttachmentToSigners.`in`(signers))
)
)
} }
criteria.isSignedCondition?.let { isSigned -> criteria.isSignedCondition?.let { isSigned ->
@ -290,14 +316,27 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
// notary names // notary names
criteria.notary?.let { criteria.notary?.let {
predicateSet.add(criteriaBuilder.and(vaultStates.get<AbstractParty>("notary").`in`(criteria.notary))) predicateSet.add(
checkIfListIsEmpty(
args = criteria.notary!!,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(vaultStates.get<AbstractParty>("notary").`in`(criteria.notary))
)
)
} }
// state references // state references
criteria.stateRefs?.let { criteria.stateRefs?.let {
val persistentStateRefs = (criteria.stateRefs as List<StateRef>).map(::PersistentStateRef) val persistentStateRefs = (criteria.stateRefs as List<StateRef>).map(::PersistentStateRef)
val compositeKey = vaultStates.get<PersistentStateRef>("stateRef") val compositeKey = vaultStates.get<PersistentStateRef>("stateRef")
predicateSet.add(criteriaBuilder.and(compositeKey.`in`(persistentStateRefs)))
predicateSet.add(
checkIfListIsEmpty(
args = persistentStateRefs,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(compositeKey.`in`(persistentStateRefs))
)
)
} }
// time constraints (recorded, consumed) // time constraints (recorded, consumed)
@ -447,7 +486,14 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
// owner // owner
criteria.owner?.let { criteria.owner?.let {
val owners = criteria.owner as List<AbstractParty> val owners = criteria.owner as List<AbstractParty>
predicateSet.add(criteriaBuilder.and(vaultFungibleStatesRoot.get<AbstractParty>("owner").`in`(owners)))
predicateSet.add(
checkIfListIsEmpty(
args = owners,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(vaultFungibleStatesRoot.get<AbstractParty>("owner").`in`(owners))
)
)
} }
// quantity // quantity
@ -458,13 +504,27 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
// issuer party // issuer party
criteria.issuer?.let { criteria.issuer?.let {
val issuerParties = criteria.issuer as List<AbstractParty> val issuerParties = criteria.issuer as List<AbstractParty>
predicateSet.add(criteriaBuilder.and(vaultFungibleStatesRoot.get<AbstractParty>("issuer").`in`(issuerParties)))
predicateSet.add(
checkIfListIsEmpty(
args = issuerParties,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(vaultFungibleStatesRoot.get<AbstractParty>("issuer").`in`(issuerParties))
)
)
} }
// issuer reference // issuer reference
criteria.issuerRef?.let { criteria.issuerRef?.let {
val issuerRefs = (criteria.issuerRef as List<OpaqueBytes>).map { it.bytes } val issuerRefs = (criteria.issuerRef as List<OpaqueBytes>).map { it.bytes }
predicateSet.add(criteriaBuilder.and(vaultFungibleStatesRoot.get<ByteArray>("issuerRef").`in`(issuerRefs)))
predicateSet.add(
checkIfListIsEmpty(
args = issuerRefs,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(vaultFungibleStatesRoot.get<ByteArray>("issuerRef").`in`(issuerRefs))
)
)
} }
if (criteria.participants != null && criteria.exactParticipants != null) if (criteria.participants != null && criteria.exactParticipants != null)
@ -498,14 +558,27 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
// linear ids UUID // linear ids UUID
criteria.uuid?.let { criteria.uuid?.let {
val uuids = criteria.uuid as List<UUID> val uuids = criteria.uuid as List<UUID>
predicateSet.add(criteriaBuilder.and(vaultLinearStatesRoot.get<UUID>("uuid").`in`(uuids)))
predicateSet.add(
checkIfListIsEmpty(
args = uuids,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(vaultLinearStatesRoot.get<UUID>("uuid").`in`(uuids))
)
)
} }
// linear ids externalId // linear ids externalId
criteria.externalId?.let { criteria.externalId?.let {
val externalIds = criteria.externalId as List<String> val externalIds = criteria.externalId as List<String>
if (externalIds.isNotEmpty())
predicateSet.add(criteriaBuilder.and(vaultLinearStatesRoot.get<String>("externalId").`in`(externalIds))) predicateSet.add(
checkIfListIsEmpty(
args = externalIds,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(vaultLinearStatesRoot.get<String>("externalId").`in`(externalIds))
)
)
} }
if (criteria.participants != null && criteria.exactParticipants != null) if (criteria.participants != null && criteria.exactParticipants != null)
@ -694,8 +767,11 @@ class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractStat
} }
else { else {
// Get the persistent party entity. // Get the persistent party entity.
commonPredicates[predicateID] = criteriaBuilder.and( commonPredicates[predicateID] = checkIfListIsEmpty(
getPersistentPartyRoot().get<VaultSchemaV1.PersistentParty>("x500Name").`in`(participants)) args = participants,
criteriaBuilder = criteriaBuilder,
predicate = criteriaBuilder.and(getPersistentPartyRoot().get<VaultSchemaV1.PersistentParty>("x500Name").`in`(participants))
)
} }
// Add the join for vault states to persistent entities (if this is not a Fungible nor Linear criteria query) // Add the join for vault states to persistent entities (if this is not a Fungible nor Linear criteria query)

View File

@ -258,6 +258,24 @@ class NodeAttachmentServiceTest {
) )
} }
@Test(timeout=300_000)
fun `AttachmentsQueryCriteria returns empty resultset without errors if there is an empty list after the 'in' clause`() {
SelfCleaningDir().use { file ->
val contractJar = makeTestContractJar(file.path, "com.example.MyContract")
contractJar.read { storage.importAttachment(it, "uploaderB", "contract.jar") }
assertEquals(
1,
storage.queryAttachments(AttachmentsQueryCriteria(contractClassNamesCondition = Builder.equal(listOf("com.example.MyContract")))).size
)
assertEquals(
0,
storage.queryAttachments(AttachmentsQueryCriteria(contractClassNamesCondition = Builder.equal(emptyList()))).size
)
}
}
@Test(timeout=300_000) @Test(timeout=300_000)
fun `contract class, versioning and signing metadata can be used to search`() { fun `contract class, versioning and signing metadata can be used to search`() {
SelfCleaningDir().use { file -> SelfCleaningDir().use { file ->

View File

@ -267,6 +267,31 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
} }
} }
@Test(timeout=300_000)
fun `VaultQueryCriteria returns empty resultset without errors if there is an empty list after the 'in' clause`() {
database.transaction {
val states = vaultFiller.fillWithSomeTestLinearStates(1, "TEST")
val stateRefs = states.states.map { it.ref }
val criteria = VaultQueryCriteria(notary = listOf(DUMMY_NOTARY))
val results = vaultService.queryBy<LinearState>(criteria)
assertThat(results.states).hasSize(1)
val emptyCriteria = VaultQueryCriteria(notary = emptyList())
val emptyResults = vaultService.queryBy<LinearState>(emptyCriteria)
assertThat(emptyResults.states).hasSize(0)
val stateCriteria = VaultQueryCriteria(stateRefs = stateRefs)
val stateResults = vaultService.queryBy<LinearState>(stateCriteria)
assertThat(stateResults.states).hasSize(1)
val emptyStateCriteria = VaultQueryCriteria(stateRefs = emptyList())
val emptyStateResults = vaultService.queryBy<LinearState>(emptyStateCriteria)
assertThat(emptyStateResults.states).hasSize(0)
}
}
/** Generic Query tests /** Generic Query tests
(combining both FungibleState and LinearState contract types) */ (combining both FungibleState and LinearState contract types) */
@ -1823,6 +1848,33 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
/** LinearState tests */ /** LinearState tests */
@Test(timeout=300_000)
fun `LinearStateQueryCriteria returns empty resultset without errors if there is an empty list after the 'in' clause`() {
database.transaction {
val uid = UniqueIdentifier("999")
vaultFiller.fillWithSomeTestLinearStates(numberToCreate = 1, uniqueIdentifier = uid)
vaultFiller.fillWithSomeTestLinearStates(numberToCreate = 1, externalId = "1234")
val uuidCriteria = LinearStateQueryCriteria(uuid = listOf(uid.id))
val externalIdCriteria = LinearStateQueryCriteria(externalId = listOf("1234"))
val uuidResults = vaultService.queryBy<ContractState>(uuidCriteria)
val externalIdResults = vaultService.queryBy<ContractState>(externalIdCriteria)
assertThat(uuidResults.states).hasSize(1)
assertThat(externalIdResults.states).hasSize(1)
val uuidCriteriaEmpty = LinearStateQueryCriteria(uuid = emptyList())
val externalIdCriteriaEmpty = LinearStateQueryCriteria(externalId = emptyList())
val uuidResultsEmpty = vaultService.queryBy<ContractState>(uuidCriteriaEmpty)
val externalIdResultsEmpty = vaultService.queryBy<ContractState>(externalIdCriteriaEmpty)
assertThat(uuidResultsEmpty.states).hasSize(0)
assertThat(externalIdResultsEmpty.states).hasSize(0)
}
}
@Test(timeout=300_000) @Test(timeout=300_000)
fun `unconsumed linear heads for linearId without external Id`() { fun `unconsumed linear heads for linearId without external Id`() {
database.transaction { database.transaction {
@ -2030,6 +2082,46 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
/** FungibleAsset tests */ /** FungibleAsset tests */
@Test(timeout=300_000)
fun `FungibleAssetQueryCriteria returns empty resultset without errors if there is an empty list after the 'in' clause`() {
database.transaction {
vaultFiller.fillWithSomeTestCash(100.DOLLARS, notaryServices, 1, MEGA_CORP.ref(0))
val ownerCriteria = FungibleAssetQueryCriteria(owner = listOf(MEGA_CORP))
val ownerResults = vaultService.queryBy<FungibleAsset<*>>(ownerCriteria)
assertThat(ownerResults.states).hasSize(1)
val emptyOwnerCriteria = FungibleAssetQueryCriteria(owner = emptyList())
val emptyOwnerResults = vaultService.queryBy<FungibleAsset<*>>(emptyOwnerCriteria)
assertThat(emptyOwnerResults.states).hasSize(0)
// Issuer field checks
val issuerCriteria = FungibleAssetQueryCriteria(issuer = listOf(MEGA_CORP))
val issuerResults = vaultService.queryBy<FungibleAsset<*>>(issuerCriteria)
assertThat(issuerResults.states).hasSize(1)
val emptyIssuerCriteria = FungibleAssetQueryCriteria(issuer = emptyList())
val emptyIssuerResults = vaultService.queryBy<FungibleAsset<*>>(emptyIssuerCriteria)
assertThat(emptyIssuerResults.states).hasSize(0)
// Issuer Ref field checks
val issuerRefCriteria = FungibleAssetQueryCriteria(issuerRef = listOf(MINI_CORP.ref(0).reference))
val issuerRefResults = vaultService.queryBy<FungibleAsset<*>>(issuerRefCriteria)
assertThat(issuerRefResults.states).hasSize(1)
val emptyIssuerRefCriteria = FungibleAssetQueryCriteria(issuerRef = emptyList())
val emptyIssuerRefResults = vaultService.queryBy<FungibleAsset<*>>(emptyIssuerRefCriteria)
assertThat(emptyIssuerRefResults.states).hasSize(0)
}
}
@Test(timeout=300_000) @Test(timeout=300_000)
fun `unconsumed fungible assets for specific issuer party and refs`() { fun `unconsumed fungible assets for specific issuer party and refs`() {
database.transaction { database.transaction {