* Added queryBy(QueryCriteria) Vault API and Junit tests. * Minor fix following rebase. * Spit out Vault Query tests into separate source file. * WIP * Enable composition of QueryCriteria specifications. Additional JUnit test cases to validate API. * Added Deprecating annotations. Added QueryCriteria for set of contractStateTypes * Minor tweaks and additional JUnit test cases (chain of linear id) * Added Java Junit tests and QueryCriteria builder support. * Added API documentation (including coding snippets and examples). * Added @JvmOverloads to QueryCriteria classes for easy of use from Java. * Refactored QueryCriteria API to use composition via sealed data classes. * Enable infix notation. * Fixed typo. * Clarified future work to enforce DB level permissioning. * Moved PageSpec and Order from QueryCriteria to become parameters of Query itself. * Moved PageSpec and Order from QueryCriteria to become parameters of Query itself. * TokenType now specified as set of <Class> (was non extensible enum). * Exposed new Vault Query API functions via RPC. * Fixed compiler error in java test. * Addressed a couple of minor PR review scomments from MH. * Major updates following PR discussion and recommendations. * All pagination and sorting arguments are optional (and constructed with sensible defaults). Added Java helper functions for queryBy and trackBy interfaces. Added Java trackBy unit tests. Miscellaneous cleanup. * Added Generic Index schema mapping and query support. * Query criteria referencing Party now references a String (until Identity framework built out). Added participants attribute to general query criteria. * Fleshed our IndexCriteria including PR recommendation to define column aliases for index mappings. * Removed all directly exposed API dependencies on requery. * Updated documentation. * Provide sensible defaults for all Query arguments. Add RPC Java helpers and increase range of Vault Service helpers. * Further improvements (upgrading notes) and updates to documentation. * RST documentation updates. * Updates to address RP latest set of review comments. * Updates to address MH latest set of review comments. * Updated to highlight use of VaultIndexQueryCriteria to directly reference a JPA-annotated entity (versus the indirect, explicitly mapped attribute to GenericIndexSchema approach) * Aesthetic updates requested by MH * Reverted Indexing approach: removed all references to VaultIndexedQueryCriteria and GenericVaultIndexSchemaV1 scheme. * Final clean-up and minor updates prior to merge. * Fixed compiler warnings (except deprecation warnings) * Reverted all changes to Vault Schemas (except simple illustrative VaultLinearState used in VaultQueryTests) * Reverted all changes to Vault Schemas (except simple illustrative VaultLinearState used in VaultQueryTests) * Commented out @Deprecated annotations (as a hedge against us releasing M12 with the work half-done) * Renamed RPC JavaHelper functions as RPCDispatcher does not allow more than one method with same name.
15 KiB
Vault Query
Corda has been architected from the ground up to encourage usage of industry standard, proven query frameworks and libraries for accessing RDBMS backed transactional stores (including the Vault).
Corda provides a number of flexible query mechanisms for accessing the Vault:
- Vault Query API
- custom JPA/JPQL queries
- custom 3rd party Data Access frameworks such as Spring Data
The majority of query requirements can be satified by using the Vault Query API, which is exposed via the VaultService
for use directly by flows:
../../core/src/main/kotlin/net/corda/core/node/services/Services.kt
and via CordaRPCOps
for use by RPC client applications:
../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt
../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt
Java helper methods are also provided with default values for arguments:
../../core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt
The API provides both static (snapshot) and dynamic (snapshot with streaming updates) methods for a defined set of filter criteria.
- Use
queryBy
to obtain a only current snapshot of data (for a givenQueryCriteria
) - Use
trackBy
to obtain a both a current snapshot and a future stream of updates (for a givenQueryCriteria
)
Simple pagination (page number and size) and sorting (directional ordering, null handling, custom property sort) is also specifiable. Defaults are defined for Paging (pageNumber = 0, pageSize = 200) and Sorting (direction = ASC, nullHandling = NULLS_LAST).
The QueryCriteria
interface provides a flexible mechanism for specifying different filtering criteria, including and/or composition and a rich set of logical operators. There are four implementations of this interface which can be chained together to define advanced filters.
VaultQueryCriteria
provides filterable criteria on attributes within the Vault states table: status (UNCONSUMED, CONSUMED), state reference(s), contract state type(s), notaries, soft locked states, timestamps (RECORDED, CONSUMED).Note
Sensible defaults are defined for frequently used attributes (status = UNCONSUMED, includeSoftlockedStates = true).
FungibleAssetQueryCriteria
provides filterable criteria on attributes defined in the Corda CoreFungibleAsset
contract state interface, used to represent assets that are fungible, countable and issued by a specific party (eg.Cash.State
andCommodityContract.State
in the Corda finance module).Note
Contract states that extend the
FungibleAsset
interface now automatically persist associated state attributes.
LinearStateQueryCriteria
provides filterable criteria on attributes defined in the Corda CoreLinearState
andDealState
contract state interfaces, used to represent entities that continuously supercede themselves, all of which share the same linearId (eg. trade entity states such as theIRSState
defined in the SIMM valuation demo)Note
Contract states that extend the
LinearState
orDealState
interfaces now automatically persist associated state attributes.4.
VaultCustomQueryCriteria
provides the means to specify one or many arbitrary expressions on attributes defined by a custom contract state that implements its own schema as described in the Persistence documentation and associated examples. Custom criteria expressions are expressed as JPA Query like WHERE clauses as follows: [JPA entityAttributeName] [Operand] [Value]An example is illustrated here:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
All QueryCriteria
implementations are composable using and
and or
operators, as also illustrated above.
Additional notes
Note
Custom contract states that implement the
Queryable
interface may now extend theFungiblePersistentState
,LinearPersistentState
orDealPersistentState
classes when implementing theirMappedSchema
. Previously, all custom contracts extended the rootPersistentState
class and defined repeated mappings ofFungibleAsset
,LinearState
andDealState
attributes.
Examples of these QueryCriteria
objects are presented below for Kotlin and Java.
The Vault Query API leverages the rich semantics of the underlying Requery persistence framework adopted by Corda.
Note
Permissioning at the database level will be enforced at a later date to ensure authenticated, role-based, read-only access to underlying Corda tables.
Note
API's now provide ease of use calling semantics from both Java and Kotlin.
Note
Current queries by Party
specify only a party name as the underlying identity framework is being re-designed. In future it may be possible to query on specific elements of a parties identity such as a CompositeKey
hierarchy (parent and child nodes, weightings).
Example usage
Kotlin
General snapshot queries using VaultQueryCriteria
Query for all unconsumed states:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for unconsumed states for some state references:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for unconsumed states for several contract state types:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for unconsumed states for a given notary:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for unconsumed states for a given set of participants:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for unconsumed states recorded between two time intervals:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for all states with pagination specification:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
LinearState and DealState queries using LinearStateQueryCriteria
Query for unconsumed linear states for given linear ids:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Note
This example was previously executed using the deprecated extension method:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for all linear states associated with a linear id:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Note
This example was previously executed using the deprecated method:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for unconsumed deal states with deals references:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for unconsumed deal states with deals parties:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
FungibleAsset and DealState queries using FungibleAssetQueryCriteria
Query for fungible assets for a given currency:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for fungible assets for a given currency and minimum quantity:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for fungible assets for a specifc issuer party:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Query for consumed fungible assets with a specific exit key:
../../node/src/test/kotlin/net/corda/node/services/vault/VaultQueryTests.kt
Java examples
Query for all consumed contract states:
../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java
Note
This example was previously executed using the deprecated method:
../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java
Query for all deal states:
../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java
Note
This example was previously executed using the deprecated method:
../../node/src/test/java/net/corda/node/services/vault/VaultQueryJavaTests.java
Dynamic queries (also using VaultQueryCriteria
) are an extension to the snapshot queries by returning an additional QueryResults
return type in the form of an Observable<Vault.Update>
. Refer to ReactiveX Observable for a detailed understanding and usage of this type.
Other use case scenarios
For advanced use cases that require sophisticated pagination, sorting, grouping, and aggregation functions, it is recommended that the CorDapp developer utilise one of the many proven frameworks that ship with this capability out of the box. Namely, implementations of JPQL (JPA Query Language) such as Hibernate for advanced SQL access, and Spring Data for advanced pagination and ordering constructs.
The Corda Tutorials provide examples satisfying these additional Use Cases:
- Template / Tutorial CorDapp service using Vault API Custom Query to access attributes of IOU State
- Template / Tutorial CorDapp service query extension executing Named Queries via JPQL
- Advanced pagination queries using Spring Data JPA
Upgrading from previous releases
Here follows a selection of the most common upgrade scenarios:
ServiceHub usage to obtain Unconsumed states for a given contract state type
Previously:
val yoStates = b.vault.unconsumedStates<Yo.State>()
This query returned an Iterable<StateAndRef<T>>
Now:
val yoStates = b.vault.queryBy<Yo.State>().states
The query returns a Vault.Page
result containing:
- states as a
List<StateAndRef<T : ContractState>>
sized according to the default Page specification ofDEFAULT_PAGE_NUM
(0) andDEFAULT_PAGE_SIZE
(200).- states metadata as a
List<Vault.StateMetadata>
containing Vault State metadata held in the Vault states table.- the
PagingSpecification
used in the query- a
total
number of results available. This value can be used issue subsequent queries with appropriately specifiedPageSpecification
(according to your paging needs and/or maximum memory capacity for holding large data sets). Note it is your responsibility to manage page numbers and sizes.
ServiceHub usage obtaining linear heads for a given contract state type
Previously:
val iouStates = serviceHub.vaultService.linearHeadsOfType<IOUState>()
val iouToSettle = iouStates[linearId] ?: throw Exception("IOUState with linearId $linearId not found.")
Now:
val criteria = QueryCriteria.LinearStateQueryCriteria(linearId = listOf(linearId))
val iouStates = serviceHub.vaultService.queryBy<IOUState>(criteria).states
val iouToSettle = iouStates.singleOrNull() ?: throw Exception("IOUState with linearId $linearId not found.")
RPC usage was limited to using the
vaultAndUpdates
RPC method, which returned a snapshot and streaming updates as an Observable. In many cases, queries were not interested in the streaming updates.Previously:
val iouStates = services.vaultAndUpdates().first.filter { it.state.data is IOUState }
Now:
val iouStates = services.vaultQueryBy<IOUState>()