diff --git a/Cargo.lock b/Cargo.lock index d9a753544374f..e66e4199dc1ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5291,6 +5291,12 @@ dependencies = [ "libc", ] +[[package]] +name = "markdown-gen" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034621d7f1258317ca1dfb9205e3925d27ee4aa2a46620a09c567daf0310562" + [[package]] name = "match_opt" version = "0.1.2" @@ -10612,6 +10618,7 @@ dependencies = [ name = "sui-graphql-rpc" version = "0.1.0" dependencies = [ + "anyhow", "async-graphql", "async-graphql-axum", "async-trait", @@ -10627,6 +10634,7 @@ dependencies = [ "hyper", "insta", "lru 0.10.0", + "markdown-gen", "move-binary-format", "move-bytecode-utils", "move-compiler", @@ -10642,6 +10650,7 @@ dependencies = [ "serde_with", "serde_yaml 0.8.26", "serial_test", + "similar", "simulacrum", "sui-indexer", "sui-json-rpc", @@ -14211,6 +14220,7 @@ dependencies = [ "lz4", "lz4-sys", "mach2", + "markdown-gen", "match_opt", "matchers", "matchit 0.5.0", diff --git a/Cargo.toml b/Cargo.toml index 9e7b6527a2edc..d3ed281ab73d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -333,6 +333,7 @@ json_to_table = { git = "https://github.com/zhiburt/tabled/", rev = "e449317a1c0 leb128 = "0.2.5" linked-hash-map = "0.5.6" lru = "0.10" +markdown-gen = "1.2.1" match_opt = "0.1.2" mime = "0.3" mockall = "0.11.4" diff --git a/crates/sui-graphql-rpc/Cargo.toml b/crates/sui-graphql-rpc/Cargo.toml index 86a736df90e55..6e864cd2130f6 100644 --- a/crates/sui-graphql-rpc/Cargo.toml +++ b/crates/sui-graphql-rpc/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] +anyhow.workspace = true async-graphql = {workspace = true, features = ["dataloader"] } async-graphql-axum.workspace = true async-trait.workspace = true @@ -21,6 +22,7 @@ hex.workspace = true hyper.workspace = true lru.workspace = true move-binary-format.workspace = true +markdown-gen.workspace = true mysten-metrics.workspace = true move-core-types.workspace = true once_cell.workspace = true @@ -33,6 +35,7 @@ serde.workspace = true serde_json.workspace = true serde_with.workspace = true serde_yaml.workspace = true +similar.workspace = true sui-types.workspace = true telemetry-subscribers.workspace = true tracing.workspace = true diff --git a/crates/sui-graphql-rpc/docs/examples.md b/crates/sui-graphql-rpc/docs/examples.md new file mode 100644 index 0000000000000..c2068ed559e70 --- /dev/null +++ b/crates/sui-graphql-rpc/docs/examples.md @@ -0,0 +1,1323 @@ +# Sui GraphQL Examples +### [Address](#0) +#### [Transaction Block Connection](#0) +### [Balance Connection](#1) +#### [Balance Connection](#65535) +### [Chain Id](#2) +#### [Chain Id](#131070) +### [Checkpoint](#3) +#### [At Digest](#196605) +#### [At Seq Num](#196606) +#### [First Two Tx Blocks For Checkpoint](#196607) +#### [Latest Checkpoint](#196608) +#### [Multiple Selections](#196609) +#### [With Timestamp Tx Block Live Objects](#196610) +#### [With Tx Sent Addr Filter](#196611) +### [Checkpoint Connection](#4) +#### [Ascending Fetch](#262140) +#### [First Ten After Checkpoint](#262141) +#### [Last Ten After Checkpoint](#262142) +### [Coin Connection](#5) +#### [Coin Connection](#327675) +### [Epoch](#6) +#### [Latest Epoch](#393210) +#### [Specific Epoch](#393211) +#### [With Checkpoint Connection](#393212) +#### [With Tx Block Connection](#393213) +#### [With Tx Block Connection Latest Epoch](#393214) +### [Event Connection](#7) +#### [Event Connection](#458745) +### [Name Service](#8) +#### [Name Service](#524280) +### [Object](#9) +#### [Object](#589815) +### [Object Connection](#10) +#### [Filter Object Ids](#655350) +#### [Filter Owner](#655351) +#### [Object Connection](#655352) +### [Owner](#11) +#### [Owner](#720885) +### [Protocol Configs](#12) +#### [Key Value](#786420) +#### [Key Value Feature Flag](#786421) +#### [Specific Config](#786422) +#### [Specific Feature Flag](#786423) +### [Stake Connection](#13) +#### [Stake Connection](#851955) +### [Sui System State Summary](#14) +#### [Sui System State Summary](#917490) +### [Transaction Block](#15) +#### [Transaction Block Kind](#983025) +### [Transaction Block Connection](#16) +#### [Before After Checkpoint](#1048560) +#### [Changed Object Filter](#1048561) +#### [Input Object Filter](#1048562) +#### [Input Object Sent Addr Filter](#1048563) +#### [Package Filter](#1048564) +#### [Package Module Filter](#1048565) +#### [Package Module Func Filter](#1048566) +#### [Recv Addr Filter](#1048567) +#### [Sent Addr Filter](#1048568) +#### [Tx Ids Filter](#1048569) +#### [Tx Kind Filter](#1048570) +#### [With Defaults Ascending](#1048571) +### [Transaction Block Effects](#17) +#### [Transaction Block Effects](#1114095) +## +## Address +### +### Transaction Block Connection +#### See examples in Query::transactionBlockConnection as this is +#### similar behavior to the `transactionBlockConnection` in Query but +#### supports additional `AddressTransactionBlockRelationship` filter +#### Filtering on package where the sender of the TX is the current address +#### and displaying the transaction's sender and the gas price and budget + +>
# See examples in Query::transactionBlockConnection as this is +># similar behavior to the `transactionBlockConnection` in Query but +># supports additional `AddressTransactionBlockRelationship` filter +> +># Filtering on package where the sender of the TX is the current address +># and displaying the transaction's sender and the gas price and budget +>query transaction_block_with_relation_filter { +> address(address: "0x2") { +> transactionBlockConnection(relation: SENT, filter: { package: "0x2" }) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +> } +>}+ +## +## Balance Connection +### +### Balance Connection +#### Query the balance for objects of type COIN and then for each coin +#### get the coin type, the number of objects, and the total balance + +>
{ +> address( +> address: "0x5094652429957619e6efa79a404a6714d1126e63f551f4b6c7fb76440f8118c9" +> ) { +> balance( +> type: "0xc060006111016b8a020ad5b33834984a437aaa7d3c74c18e09a95d48aceab08c::coin::COIN" +> ) { +> coinObjectCount +> totalBalance +> } +> balanceConnection { +> nodes { +> coinType +> coinObjectCount +> totalBalance +> } +> pageInfo { +> endCursor +> } +> } +> } +>}+ +## +## Chain Id +### +### Chain Id +#### Returns the chain identifier for the chain that the server is tracking + +>
{ +> chainIdentifier +>}+ +## +## Checkpoint +### +### At Digest +#### Get the checkpoint's information at a particular digest + +>
{ +> checkpoint(id: { digest: "GaDeWEfbSQCQ8FBQHUHVdm4KjrnbgMqEZPuhStoq5njU" }) { +> digest +> sequenceNumber +> validatorSignature +> previousCheckpointDigest +> networkTotalTransactions +> rollingGasSummary { +> computationCost +> storageCost +> storageRebate +> nonRefundableStorageFee +> } +> epoch { +> epochId +> referenceGasPrice +> startTimestamp +> endTimestamp +> } +> endOfEpoch { +> nextProtocolVersion +> } +> } +>}+ +### +### At Seq Num +#### Get the checkpoint's information at a particular sequence number + +>
{ +> checkpoint(id: { sequenceNumber: 10 }) { +> digest +> sequenceNumber +> validatorSignature +> previousCheckpointDigest +> networkTotalTransactions +> rollingGasSummary { +> computationCost +> storageCost +> storageRebate +> nonRefundableStorageFee +> } +> epoch { +> epochId +> referenceGasPrice +> startTimestamp +> endTimestamp +> } +> endOfEpoch { +> nextProtocolVersion +> } +> } +>}+ +### +### First Two Tx Blocks For Checkpoint +#### Get data for the first two transaction blocks of checkpoint at sequence number 10 + +>
{ +> checkpoint(id: { sequenceNumber: 10 }) { +> transactionBlockConnection(first: 2) { +> edges { +> node { +> kind { +> __typename +> } +> digest +> sender { +> location +> } +> expiration { +> epochId +> } +> } +> } +> pageInfo { +> startCursor +> hasNextPage +> hasPreviousPage +> endCursor +> } +> } +> } +>}+ +### +### Latest Checkpoint +#### Latest checkpoint's data + +>
{ +> checkpoint { +> digest +> sequenceNumber +> validatorSignature +> previousCheckpointDigest +> networkTotalTransactions +> rollingGasSummary { +> computationCost +> storageCost +> storageRebate +> nonRefundableStorageFee +> } +> epoch { +> epochId +> referenceGasPrice +> startTimestamp +> endTimestamp +> } +> endOfEpoch { +> nextProtocolVersion +> } +> } +>}+ +### +### Multiple Selections +#### Get the checkpoint at sequence 9769 and show +#### the new committe authority and stake units + +>
{ +> checkpoint(id: { sequenceNumber: 9769 }) { +> digest +> sequenceNumber +> timestamp +> validatorSignature +> previousCheckpointDigest +> liveObjectSetDigest +> networkTotalTransactions +> rollingGasSummary { +> computationCost +> storageCost +> storageRebate +> nonRefundableStorageFee +> } +> epoch { +> epochId +> } +> endOfEpoch { +> newCommittee { +> authorityName +> stakeUnit +> } +> nextProtocolVersion +> } +> transactionBlockConnection { +> edges { +> node { +> digest +> sender { +> location +> } +> expiration { +> epochId +> } +> } +> } +> } +> } +>}+ +### +### With Timestamp Tx Block Live Objects +#### Latest checkpoint's timestamp, liveObjectSetDigest, and transaction block data + +>
{ +> checkpoint { +> digest +> sequenceNumber +> timestamp +> liveObjectSetDigest +> transactionBlockConnection { +> edges { +> node { +> digest +> sender { +> location +> } +> expiration { +> epochId +> } +> } +> } +> } +> } +>}+ +### +### With Tx Sent Addr Filter +#### Select checkpoint at sequence number 14830285 for transactions from sentAddress + +>
{ +> checkpoint(id: { sequenceNumber: 14830285 }) { +> digest +> sequenceNumber +> timestamp +> liveObjectSetDigest +> transactionBlockConnection( +> filter: { +> sentAddress: "0x0000000000000000000000000000000000000000000000000000000000000000" +> } +> ) { +> edges { +> node { +> digest +> sender { +> location +> } +> expiration { +> epochId +> } +> } +> } +> } +> } +>}+ +## +## Checkpoint Connection +### +### Ascending Fetch +#### Use the checkpoint connection to fetch some default amount of checkpoints in an ascending order + +>
{ +> checkpointConnection { +> nodes { +> digest +> sequenceNumber +> validatorSignature +> previousCheckpointDigest +> networkTotalTransactions +> rollingGasSummary { +> computationCost +> storageCost +> storageRebate +> nonRefundableStorageFee +> } +> epoch { +> epochId +> referenceGasPrice +> startTimestamp +> endTimestamp +> } +> endOfEpoch { +> nextProtocolVersion +> } +> } +> } +>}+ +### +### First Ten After Checkpoint +#### Fetch the digest and sequence number of the first 10 checkpoints after the cursor, which in this example is set to be checkpoint 11. Note that cursor will be opaque + +>
{ +> checkpointConnection(first: 10, after: "11") { +> nodes { +> sequenceNumber +> digest +> } +> } +>}+ +### +### Last Ten After Checkpoint +#### Fetch the digest and the sequence number of the last 20 checkpoints before the cursor + +>
{ +> checkpointConnection(last: 20, before: "100") { +> nodes { +> sequenceNumber +> digest +> } +> } +>}+ +## +## Coin Connection +### +### Coin Connection +#### Get last 3 coins before coins at cursor 13034947 + +>
{ +> address( +> address: "0x0000000000000000000000000000000000000000000000000000000000000000" +> ) { +> coinConnection(last: 3, before: "0x13034947") { +> nodes { +> id +> balance +> } +> pageInfo { +> endCursor +> hasNextPage +> } +> } +> } +>}+ +## +## Epoch +### +### Latest Epoch +#### Latest epoch, since epoch omitted + +>
{ +> epoch { +> protocolConfigs { +> protocolVersion +> } +> epochId +> referenceGasPrice +> startTimestamp +> endTimestamp +> validatorSet { +> totalStake +> pendingActiveValidatorsSize +> stakePoolMappingsSize +> inactivePoolsSize +> validatorCandidatesSize +> activeValidators { +> name +> description +> imageUrl +> projectUrl +> exchangeRates { +> asObject { +> storageRebate +> bcs +> kind +> } +> hasPublicTransfer +> } +> exchangeRatesSize +> stakingPoolActivationEpoch +> stakingPoolSuiBalance +> rewardsPool +> poolTokenBalance +> pendingStake +> pendingTotalSuiWithdraw +> pendingPoolTokenWithdraw +> votingPower +> gasPrice +> commissionRate +> nextEpochStake +> nextEpochGasPrice +> nextEpochCommissionRate +> atRisk +> } +> } +> } +>}+ +### +### Specific Epoch +#### Selecting all fields for epoch 100 + +>
{ +> epoch(id: 100) { +> protocolConfigs { +> protocolVersion +> } +> epochId +> referenceGasPrice +> startTimestamp +> endTimestamp +> validatorSet { +> totalStake +> pendingActiveValidatorsSize +> stakePoolMappingsSize +> inactivePoolsSize +> validatorCandidatesSize +> activeValidators { +> name +> description +> imageUrl +> projectUrl +> exchangeRates { +> asObject { +> storageRebate +> bcs +> kind +> } +> hasPublicTransfer +> } +> exchangeRatesSize +> stakingPoolActivationEpoch +> stakingPoolSuiBalance +> rewardsPool +> poolTokenBalance +> pendingStake +> pendingTotalSuiWithdraw +> pendingPoolTokenWithdraw +> votingPower +> gasPrice +> commissionRate +> nextEpochStake +> nextEpochGasPrice +> nextEpochCommissionRate +> atRisk +> } +> } +> } +>}+ +### +### With Checkpoint Connection + +>
{ +> epoch { +> checkpointConnection { +> nodes { +> transactionBlockConnection(first: 10) { +> pageInfo { +> hasNextPage +> endCursor +> } +> edges { +> cursor +> node { +> sender { +> location +> } +> effects { +> gasEffects { +> gasObject { +> location +> } +> } +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +> } +> } +> } +> } +>}+ +### +### With Tx Block Connection +#### Fetch the first 20 transactions after 231220100 for epoch 97 + +>
{ +> epoch(id:97) { +> transactionBlockConnection(first: 20, after:"231220100") { +> pageInfo { +> hasNextPage +> endCursor +> } +> edges { +> cursor +> node { +> digest +> sender { +> location +> } +> effects { +> gasEffects { +> gasObject { +> location +> } +> } +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +> } +> } +>}+ +### +### With Tx Block Connection Latest Epoch +#### the last checkpoint of epoch 97 is 8097645 +#### last tx number of the checkpoint is 261225985 + +>
{ +> epoch { +> transactionBlockConnection(first: 20, after: "261225985") { +> pageInfo { +> hasNextPage +> endCursor +> } +> edges { +> cursor +> node { +> sender { +> location +> } +> effects { +> gasEffects { +> gasObject { +> location +> } +> } +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +> } +> } +>}+ +## +## Event Connection +### +### Event Connection + +>
{ +> eventConnection( +> filter: { +> eventType: "0x3164fcf73eb6b41ff3d2129346141bd68469964c2d95a5b1533e8d16e6ea6e13::Market::ChangePriceEvent<0x2::sui::SUI>" +> } +> ) { +> nodes { +> id +> sendingModuleId { +> name +> package { +> asObject { +> digest +> } +> } +> } +> eventType { +> repr +> } +> senders { +> location +> } +> timestamp +> json +> bcs +> } +> } +>}+ +## +## Name Service +### +### Name Service + +>
{ +> resolveNameServiceAddress(name: "example.sui") { +> location +> } +> address( +> address: "0x0b86be5d779fac217b41d484b8040ad5145dc9ba0cba099d083c6cbda50d983e" +> ) { +> location +> balance(type: "0x2::sui::SUI") { +> coinType +> coinObjectCount +> totalBalance +> } +> defaultNameServiceName +> } +>}+ +## +## Object +### +### Object + +>
{ +> object( +> address: "0x04e20ddf36af412a4096f9014f4a565af9e812db9a05cc40254846cf6ed0ad91" +> ) { +> location +> version +> digest +> storageRebate +> owner { +> defaultNameServiceName +> } +> previousTransactionBlock { +> digest +> } +> kind +> } +>}+ +## +## Object Connection +### +### Filter Object Ids +#### Filter on objectIds + +>
{ +> objectConnection( +> filter: { +> objectIds: [ +> "0x4bba2c7b9574129c272bca8f58594eba933af8001257aa6e0821ad716030f149" +> ] +> } +> ) { +> edges { +> node { +> storageRebate +> kind +> } +> } +> } +>}+ +### +### Filter Owner +#### Filter on owner + +>
{ +> objectConnection( +> filter: { +> owner: "0x23b7b0e2badb01581ba9b3ab55587d8d9fdae087e0cfc79f2c72af36f5059439" +> } +> ) { +> edges { +> node { +> storageRebate +> kind +> } +> } +> } +>}+ +### +### Object Connection + +>
{ +> objectConnection { +> nodes { +> version +> digest +> storageRebate +> previousTransactionBlock { +> digest +> sender { +> defaultNameServiceName +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +> pageInfo { +> endCursor +> } +> } +>}+ +## +## Owner +### +### Owner + +>
{ +> owner( +> address: "0x931f293ce7f65fd5ebe9542653e1fd92fafa03dda563e13b83be35da8a2eecbe" +> ) { +> location +> } +>}+ +## +## Protocol Configs +### +### Key Value +#### Select the key and value of the protocol configuration + +>
{ +> protocolConfig { +> configs { +> key +> value +> } +> } +>}+ +### +### Key Value Feature Flag +#### Select the key and value of the feature flag + +>
{ +> protocolConfig { +> featureFlags { +> key +> value +> } +> } +>}+ +### +### Specific Config +#### Select the key and value of the specific protocol configuration, in this case `max_move_identifier_len` + +>
{ +> protocolConfig { +> config(key: "max_move_identifier_len") { +> key +> value +> } +> } +>}+ +### +### Specific Feature Flag + +>
{ +> protocolConfig { +> protocolVersion +> featureFlag(key: "advance_epoch_start_time_in_safe_mode") { +> value +> } +> } +>}+ +## +## Stake Connection +### +### Stake Connection +#### Get all the staked objects for this address and all the active validators at the epoch when the stake became active + +>
{ +> address( +> address: "0xc0a5b916d0e406ddde11a29558cd91b29c49e644eef597b7424a622955280e1e" +> ) { +> location +> balance(type: "0x2::sui::SUI") { +> coinType +> totalBalance +> } +> stakeConnection { +> nodes { +> id +> status +> principal +> estimatedReward +> activeEpoch { +> epochId +> referenceGasPrice +> validatorSet { +> activeValidators { +> name +> description +> exchangeRatesSize +> } +> totalStake +> } +> } +> requestEpoch { +> epochId +> } +> } +> } +> } +>}+ +## +## Sui System State Summary +### +### Sui System State Summary + +>
{ +> latestSuiSystemState { +> systemStateVersion +> referenceGasPrice +> startTimestamp +> validatorSet { +> totalStake +> pendingActiveValidatorsSize +> stakePoolMappingsSize +> inactivePoolsSize +> validatorCandidatesSize +> activeValidators { +> name +> description +> imageUrl +> projectUrl +> exchangeRates { +> asObject { +> storageRebate +> bcs +> kind +> } +> hasPublicTransfer +> } +> exchangeRatesSize +> stakingPoolActivationEpoch +> stakingPoolSuiBalance +> rewardsPool +> poolTokenBalance +> pendingStake +> pendingTotalSuiWithdraw +> pendingPoolTokenWithdraw +> votingPower +> gasPrice +> commissionRate +> nextEpochStake +> nextEpochGasPrice +> nextEpochCommissionRate +> atRisk +> } +> } +> } +>}+ +## +## Transaction Block +### +### Transaction Block Kind + +>
{ +> object( +> address: "0xd6b9c261ab53d636760a104e4ab5f46c2a3e9cda58bd392488fc4efa6e43728c" +> ) { +> previousTransactionBlock { +> sender { +> location +> } +> kind { +> __typename +> ... on ConsensusCommitPrologueTransaction { +> timestamp +> round +> epoch { +> epochId +> referenceGasPrice +> } +> } +> ... on ChangeEpochTransaction { +> computationCharge +> storageCharge +> timestamp +> storageRebate +> } +> ... on GenesisTransaction { +> objects +> } +> } +> } +> } +>}+ +## +## Transaction Block Connection +### +### Before After Checkpoint +#### Filter on before_ and after_checkpoint. If both are provided, before must be greater than after + +>
{ +> transactionBlockConnection( +> filter: { afterCheckpoint: 10, beforeCheckpoint: 20 } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Changed Object Filter +#### Filter on changedObject + +>
{ +> transactionBlockConnection( +> filter: { +> changedObject: "0x0000000000000000000000000000000000000000000000000000000000000006" +> } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Input Object Filter +#### Filter on inputObject + +>
{ +> transactionBlockConnection( +> filter: { +> inputObject: "0x0000000000000000000000000000000000000000000000000000000000000006" +> } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Input Object Sent Addr Filter +#### multiple filters + +>
{ +> transactionBlockConnection( +> filter: { +> inputObject: "0x0000000000000000000000000000000000000000000000000000000000000006" +> sentAddress: "0x0000000000000000000000000000000000000000000000000000000000000000" +> } +> ) { +> nodes { +> sender { +> location +> } +> effects { +> gasEffects { +> gasObject { +> location +> } +> } +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Package Filter +#### Filtering on package + +>
{ +> transactionBlockConnection( +> filter: { +> package: "0x0000000000000000000000000000000000000000000000000000000000000003" +> } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Package Module Filter +#### Filtering on package and module + +>
{ +> transactionBlockConnection( +> filter: { +> package: "0x0000000000000000000000000000000000000000000000000000000000000003" +> module: "sui_system" +> } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Package Module Func Filter +#### Filtering on package, module and function + +>
{ +> transactionBlockConnection( +> filter: { +> package: "0x0000000000000000000000000000000000000000000000000000000000000003" +> module: "sui_system" +> function: "request_withdraw_stake" +> } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Recv Addr Filter +#### Filter on recvAddress + +>
{ +> transactionBlockConnection( +> filter: { +> recvAddress: "0x0000000000000000000000000000000000000000000000000000000000000000" +> } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Sent Addr Filter +#### Filter on sign or sentAddress + +>
{ +> transactionBlockConnection( +> filter: { +> sentAddress: "0x0000000000000000000000000000000000000000000000000000000000000000" +> } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Tx Ids Filter +#### Filter on transactionIds + +>
{ +> transactionBlockConnection( +> filter: { transactionIds: ["DtQ6v6iJW4wMLgadENPUCEUS5t8AP7qvdG5jX84T1akR"] } +> ) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### Tx Kind Filter +#### Filter on TransactionKind (only SYSTEM_TX or PROGRAMMABLE_TX) + +>
{ +> transactionBlockConnection(filter: { kind: SYSTEM_TX }) { +> nodes { +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> } +>}+ +### +### With Defaults Ascending +#### Fetch some default amount of transactions, ascending + +>
{ +> transactionBlockConnection { +> nodes { +> digest +> effects { +> gasEffects { +> gasObject { +> version +> digest +> } +> gasSummary { +> computationCost +> storageCost +> storageRebate +> nonRefundableStorageFee +> } +> } +> errors +> } +> sender { +> location +> } +> gasInput { +> gasPrice +> gasBudget +> } +> } +> pageInfo { +> endCursor +> } +> } +>}+ +## +## Transaction Block Effects +### +### Transaction Block Effects + +>
{ +> object( +> address: "0x0bba1e7d907dc2832edfc3bf4468b6deacd9a2df435a35b17e640e135d2d5ddc" +> ) { +> version +> kind +> previousTransactionBlock { +> effects { +> status +> checkpoint { +> sequenceNumber +> } +> lamportVersion +> gasEffects { +> gasSummary { +> computationCost +> storageCost +> storageRebate +> nonRefundableStorageFee +> } +> } +> balanceChanges { +> owner { +> location +> balance(type: "0x2::sui::SUI") { +> totalBalance +> } +> } +> amount +> } +> dependencies { +> sender { +> location +> } +> } +> } +> } +> } +>}+ diff --git a/crates/sui-graphql-rpc/src/commands.rs b/crates/sui-graphql-rpc/src/commands.rs index d3d6e83a12bed..9a149ea835aaa 100644 --- a/crates/sui-graphql-rpc/src/commands.rs +++ b/crates/sui-graphql-rpc/src/commands.rs @@ -18,6 +18,11 @@ pub enum Command { #[clap(short, long)] file: Option
{}", query); + for header in headers { + md.write(header.heading(4)) + .map_err(|e| anyhow::anyhow!(e))?; + } + md.write(content.quote()).map_err(|e| anyhow::anyhow!(e))?; + } + } + let bytes = output.into_inner().map_err(|e| anyhow::anyhow!(e))?; + Ok(String::from_utf8(bytes) + .map_err(|e| anyhow::anyhow!(e))? + .replace('\\', "")) +} + +#[test] +fn test_generate_markdown() { + use similar::*; + use std::fs::File; + + let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + buf.push("docs"); + buf.push("examples.md"); + let mut out_file: File = File::open(buf).expect("Could not open examples.md"); + + // Read the current content of `out_file` + let mut current_content = String::new(); + out_file + .read_to_string(&mut current_content) + .expect("Could not read examples.md"); + let new_content: String = generate_markdown().expect("Generating examples markdown failed"); + + if current_content != new_content { + let mut res = vec![]; + let diff = TextDiff::from_lines(¤t_content, &new_content); + for change in diff.iter_all_changes() { + let sign = match change.tag() { + ChangeTag::Delete => "---", + ChangeTag::Insert => "+++", + ChangeTag::Equal => " ", + }; + res.push(format!("{}{}", sign, change)); + } + panic!("Doc examples have changed. Please run `sui-graphql-rpc generate-examples` to update the docs. Diff: {}", res.join("")); + } +} diff --git a/crates/sui-graphql-rpc/src/lib.rs b/crates/sui-graphql-rpc/src/lib.rs index 15439fabff998..a5b09e5f449cf 100644 --- a/crates/sui-graphql-rpc/src/lib.rs +++ b/crates/sui-graphql-rpc/src/lib.rs @@ -11,6 +11,7 @@ pub mod client; pub mod cluster; pub mod context_data; mod error; +pub mod examples; mod extensions; mod metrics; mod types; diff --git a/crates/sui-graphql-rpc/src/main.rs b/crates/sui-graphql-rpc/src/main.rs index 85d89310121de..4d807fb68a016 100644 --- a/crates/sui-graphql-rpc/src/main.rs +++ b/crates/sui-graphql-rpc/src/main.rs @@ -25,6 +25,18 @@ async fn main() { println!("{}", &out); } } + Command::GenerateExamples { file } => { + let new_content: String = sui_graphql_rpc::examples::generate_markdown() + .expect("Generating examples markdown failed"); + + let mut buf: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + buf.push("docs"); + buf.push("examples.md"); + let file = file.unwrap_or(buf); + + std::fs::write(file.clone(), new_content).expect("Writing examples markdown failed"); + println!("Written examples to file: {:?}", file); + } Command::StartServer { db_url, port, diff --git a/crates/sui-graphql-rpc/tests/examples_validation_tests.rs b/crates/sui-graphql-rpc/tests/examples_validation_tests.rs index 3d9d7741d2635..5cc7ea649add1 100644 --- a/crates/sui-graphql-rpc/tests/examples_validation_tests.rs +++ b/crates/sui-graphql-rpc/tests/examples_validation_tests.rs @@ -7,71 +7,11 @@ mod tests { use rand::SeedableRng; use serial_test::serial; use simulacrum::Simulacrum; - use std::io::Read; use std::path::PathBuf; use std::sync::Arc; use sui_graphql_rpc::cluster::SimulatorCluster; use sui_graphql_rpc::config::ConnectionConfig; - - struct ExampleQuery { - pub name: String, - pub contents: String, - pub path: PathBuf, - } - struct ExampleQueryGroup { - pub name: String, - pub queries: Vec