mirror of
https://github.com/corda/corda.git
synced 2025-02-22 02:06:45 +00:00
Merge branch 'release/os/4.9' into shams-4.10-merge-c8135331
This commit is contained in:
commit
46914a2b35
@ -272,7 +272,7 @@ class HibernateAttachmentQueryCriteriaParser<T,R>(override val criteriaBuilder:
|
||||
class HibernateQueryCriteriaParser(val contractStateType: Class<out ContractState>,
|
||||
val contractStateTypeMappings: Map<String, Set<String>>,
|
||||
override val criteriaBuilder: CriteriaBuilder,
|
||||
val criteriaQuery: CriteriaQuery<Tuple>,
|
||||
val criteriaQuery: CriteriaQuery<*>,
|
||||
val vaultStates: Root<VaultSchemaV1.VaultStates>) : AbstractQueryCriteriaParser<QueryCriteria, IQueryCriteriaParser, Sort>(), IQueryCriteriaParser {
|
||||
private companion object {
|
||||
private val log = contextLogger()
|
||||
|
@ -35,7 +35,6 @@ import net.corda.core.node.services.vault.PageSpecification
|
||||
import net.corda.core.node.services.vault.QueryCriteria
|
||||
import net.corda.core.node.services.vault.Sort
|
||||
import net.corda.core.node.services.vault.SortAttribute
|
||||
import net.corda.core.node.services.vault.builder
|
||||
import net.corda.core.observable.internal.OnResilientSubscribe
|
||||
import net.corda.core.schemas.PersistentStateRef
|
||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||
@ -69,17 +68,21 @@ import java.security.PublicKey
|
||||
import java.sql.SQLException
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.util.Arrays
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArraySet
|
||||
import java.util.stream.Stream
|
||||
import javax.persistence.PersistenceException
|
||||
import javax.persistence.Tuple
|
||||
import javax.persistence.criteria.CriteriaBuilder
|
||||
import javax.persistence.criteria.CriteriaQuery
|
||||
import javax.persistence.criteria.CriteriaUpdate
|
||||
import javax.persistence.criteria.Predicate
|
||||
import javax.persistence.criteria.Root
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.LinkedHashSet
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
|
||||
/**
|
||||
* The vault service handles storage, retrieval and querying of states.
|
||||
@ -706,10 +709,8 @@ class NodeVaultService(
|
||||
paging: PageSpecification,
|
||||
sorting: Sort,
|
||||
contractStateType: Class<out T>): Vault.Page<T> {
|
||||
// calculate total results where a page specification has been defined
|
||||
val totalStatesAvailable = if (paging.isDefault) -1 else queryTotalStateCount(criteria, contractStateType)
|
||||
|
||||
val (query, stateTypes) = createQuery(criteria, contractStateType, sorting)
|
||||
val (criteriaQuery, criteriaParser) = buildCriteriaQuery<Tuple>(criteria, contractStateType, sorting)
|
||||
val query = getSession().createQuery(criteriaQuery)
|
||||
query.setResultWindow(paging)
|
||||
|
||||
val statesMetadata: MutableList<Vault.StateMetadata> = mutableListOf()
|
||||
@ -732,7 +733,14 @@ class NodeVaultService(
|
||||
ArrayList()
|
||||
)
|
||||
|
||||
return Vault.Page(states, statesMetadata, totalStatesAvailable, stateTypes, otherResults)
|
||||
val totalStatesAvailable = when {
|
||||
paging.isDefault -> -1L
|
||||
// If the first page isn't full then we know that's all the states that are available
|
||||
paging.pageNumber == DEFAULT_PAGE_NUM && states.size < paging.pageSize -> states.size.toLong()
|
||||
else -> queryTotalStateCount(criteria, contractStateType)
|
||||
}
|
||||
|
||||
return Vault.Page(states, statesMetadata, totalStatesAvailable, criteriaParser.stateTypes, otherResults)
|
||||
}
|
||||
|
||||
private fun <R> Query<R>.resultStream(paging: PageSpecification): Stream<R> {
|
||||
@ -761,19 +769,17 @@ class NodeVaultService(
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : ContractState> queryTotalStateCount(baseCriteria: QueryCriteria, contractStateType: Class<out T>): Long {
|
||||
val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() }
|
||||
val countCriteria = QueryCriteria.VaultCustomQueryCriteria(count, Vault.StateStatus.ALL)
|
||||
val criteria = baseCriteria.and(countCriteria)
|
||||
val (query) = createQuery(criteria, contractStateType, null)
|
||||
val results = query.resultList
|
||||
return results.last().toArray().last() as Long
|
||||
private fun <T : ContractState> queryTotalStateCount(criteria: QueryCriteria, contractStateType: Class<out T>): Long {
|
||||
val (criteriaQuery, criteriaParser) = buildCriteriaQuery<Long>(criteria, contractStateType, null)
|
||||
criteriaQuery.select(criteriaBuilder.countDistinct(criteriaParser.vaultStates))
|
||||
val query = getSession().createQuery(criteriaQuery)
|
||||
return query.singleResult
|
||||
}
|
||||
|
||||
private fun <T : ContractState> createQuery(criteria: QueryCriteria,
|
||||
contractStateType: Class<out T>,
|
||||
sorting: Sort?): Pair<Query<Tuple>, Vault.StateStatus> {
|
||||
val criteriaQuery = criteriaBuilder.createQuery(Tuple::class.java)
|
||||
private inline fun <reified T> buildCriteriaQuery(criteria: QueryCriteria,
|
||||
contractStateType: Class<out ContractState>,
|
||||
sorting: Sort?): Pair<CriteriaQuery<T>, HibernateQueryCriteriaParser> {
|
||||
val criteriaQuery = criteriaBuilder.createQuery(T::class.java)
|
||||
val criteriaParser = HibernateQueryCriteriaParser(
|
||||
contractStateType,
|
||||
contractStateTypeMappings,
|
||||
@ -782,8 +788,7 @@ class NodeVaultService(
|
||||
criteriaQuery.from(VaultSchemaV1.VaultStates::class.java)
|
||||
)
|
||||
criteriaParser.parse(criteria, sorting)
|
||||
val query = getSession().createQuery(criteriaQuery)
|
||||
return Pair(query, criteriaParser.stateTypes)
|
||||
return Pair(criteriaQuery, criteriaParser)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@ class VaultQueryExceptionsTests : VaultQueryParties by rule {
|
||||
|
||||
@ClassRule
|
||||
@JvmField
|
||||
val rule = object : VaultQueryTestRule() {
|
||||
val rule = object : VaultQueryTestRule(persistentServices = false) {
|
||||
override val cordappPackages = listOf(
|
||||
"net.corda.testing.contracts",
|
||||
"net.corda.finance.contracts",
|
||||
|
@ -4,6 +4,7 @@ import com.nhaarman.mockito_kotlin.mock
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.AnonymousParty
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.packageName
|
||||
@ -37,6 +38,7 @@ import net.corda.testing.internal.configureDatabase
|
||||
import net.corda.testing.internal.vault.*
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndPersistentServices
|
||||
import net.corda.testing.node.makeTestIdentityService
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatCode
|
||||
@ -102,7 +104,7 @@ interface VaultQueryParties {
|
||||
val cordappPackages: List<String>
|
||||
}
|
||||
|
||||
open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
|
||||
open class VaultQueryTestRule(private val persistentServices: Boolean) : ExternalResource(), VaultQueryParties {
|
||||
override val alice = TestIdentity(ALICE_NAME, 70)
|
||||
override val bankOfCorda = TestIdentity(BOC_NAME)
|
||||
override val bigCorp = TestIdentity(CordaX500Name("BigCorporation", "New York", "US"))
|
||||
@ -135,12 +137,22 @@ open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
|
||||
|
||||
|
||||
override fun before() {
|
||||
// register additional identities
|
||||
val databaseAndServices = makeTestDatabaseAndMockServices(
|
||||
cordappPackages,
|
||||
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity),
|
||||
megaCorp,
|
||||
moreKeys = *arrayOf(DUMMY_NOTARY_KEY))
|
||||
val databaseAndServices = if (persistentServices) {
|
||||
makeTestDatabaseAndPersistentServices(
|
||||
cordappPackages,
|
||||
megaCorp,
|
||||
moreKeys = setOf(DUMMY_NOTARY_KEY),
|
||||
moreIdentities = setOf(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity)
|
||||
)
|
||||
} else {
|
||||
@Suppress("SpreadOperator")
|
||||
makeTestDatabaseAndMockServices(
|
||||
cordappPackages,
|
||||
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity),
|
||||
megaCorp,
|
||||
moreKeys = *arrayOf(DUMMY_NOTARY_KEY)
|
||||
)
|
||||
}
|
||||
database = databaseAndServices.first
|
||||
services = databaseAndServices.second
|
||||
vaultFiller = VaultFiller(services, dummyNotary)
|
||||
@ -2832,9 +2844,8 @@ abstract class VaultQueryTestsBase : VaultQueryParties {
|
||||
}
|
||||
|
||||
class VaultQueryTests : VaultQueryTestsBase(), VaultQueryParties by delegate {
|
||||
|
||||
companion object {
|
||||
val delegate = VaultQueryTestRule()
|
||||
val delegate = VaultQueryTestRule(persistentServices = false)
|
||||
}
|
||||
|
||||
@Rule
|
||||
@ -3137,4 +3148,34 @@ class VaultQueryTests : VaultQueryTestsBase(), VaultQueryParties by delegate {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PersistentServicesVaultQueryTests : VaultQueryParties by delegate {
|
||||
companion object {
|
||||
val delegate = VaultQueryTestRule(persistentServices = true)
|
||||
|
||||
@ClassRule
|
||||
@JvmField
|
||||
val testSerialization = SerializationEnvironmentRule()
|
||||
}
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val vaultQueryTestRule = delegate
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
fun `query on externalId which maps to multiple keys`() {
|
||||
val externalId = UUID.randomUUID()
|
||||
val page = database.transaction {
|
||||
val keys = Array(2) { services.keyManagementService.freshKey(externalId) }
|
||||
vaultFiller.fillWithDummyState(participants = keys.map(::AnonymousParty))
|
||||
services.vaultService.queryBy<ContractState>(
|
||||
VaultQueryCriteria(externalIds = listOf(externalId)),
|
||||
paging = PageSpecification(DEFAULT_PAGE_NUM, 10)
|
||||
)
|
||||
}
|
||||
assertThat(page.states).hasSize(1)
|
||||
assertThat(page.totalStatesAvailable).isEqualTo(1)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user