325 lines
5.3 KiB
Markdown
325 lines
5.3 KiB
Markdown
# GraphQL Query Patterns for Subgraphs
|
|
|
|
This reference provides common GraphQL query patterns for blockchain subgraph exploration.
|
|
|
|
## Pagination Patterns
|
|
|
|
### Basic Pagination
|
|
```graphql
|
|
query PaginatedQuery($first: Int!, $skip: Int!) {
|
|
entities(first: $first, skip: $skip, orderBy: timestamp, orderDirection: desc) {
|
|
id
|
|
timestamp
|
|
# ... other fields
|
|
}
|
|
}
|
|
```
|
|
|
|
Variables:
|
|
```json
|
|
{
|
|
"first": 100,
|
|
"skip": 0
|
|
}
|
|
```
|
|
|
|
### Cursor-based Pagination
|
|
```graphql
|
|
query CursorPagination($first: Int!, $lastId: String!) {
|
|
entities(first: $first, where: { id_gt: $lastId }, orderBy: id) {
|
|
id
|
|
# ... other fields
|
|
}
|
|
}
|
|
```
|
|
|
|
## Filtering Patterns
|
|
|
|
### Time Range Queries
|
|
```graphql
|
|
query TimeRangeQuery($startTime: Int!, $endTime: Int!) {
|
|
entities(
|
|
where: {
|
|
timestamp_gte: $startTime
|
|
timestamp_lte: $endTime
|
|
}
|
|
orderBy: timestamp
|
|
orderDirection: desc
|
|
) {
|
|
id
|
|
timestamp
|
|
# ... other fields
|
|
}
|
|
}
|
|
```
|
|
|
|
### Address-based Queries
|
|
```graphql
|
|
query UserActivity($userAddress: String!) {
|
|
# Query by exact address
|
|
transactions(where: { from: $userAddress }) {
|
|
id
|
|
to
|
|
value
|
|
timestamp
|
|
}
|
|
|
|
# Query by address (case-insensitive)
|
|
accounts(where: { id: $userAddress }) {
|
|
id
|
|
balance
|
|
# ... other fields
|
|
}
|
|
}
|
|
```
|
|
|
|
### Complex Filters
|
|
```graphql
|
|
query ComplexFilter($minAmount: String!, $tokenAddress: String!) {
|
|
swaps(
|
|
where: {
|
|
amountUSD_gte: $minAmount
|
|
pair_: {
|
|
token0: $tokenAddress
|
|
}
|
|
}
|
|
first: 100
|
|
orderBy: timestamp
|
|
orderDirection: desc
|
|
) {
|
|
id
|
|
amountUSD
|
|
timestamp
|
|
pair {
|
|
token0 { symbol }
|
|
token1 { symbol }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Aggregation Patterns
|
|
|
|
### Daily Aggregates
|
|
```graphql
|
|
query DailyStats($dayId: Int!) {
|
|
dayData(id: $dayId) {
|
|
id
|
|
date
|
|
dailyVolumeUSD
|
|
dailyTxns
|
|
totalLiquidityUSD
|
|
}
|
|
}
|
|
```
|
|
|
|
### Sum and Count
|
|
```graphql
|
|
query Aggregations {
|
|
protocol(id: "1") {
|
|
totalValueLockedUSD
|
|
txCount
|
|
pairCount
|
|
totalVolumeUSD
|
|
}
|
|
}
|
|
```
|
|
|
|
## Relationship Navigation
|
|
|
|
### Nested Queries
|
|
```graphql
|
|
query NestedRelationships($pairId: String!) {
|
|
pair(id: $pairId) {
|
|
id
|
|
token0 {
|
|
id
|
|
symbol
|
|
name
|
|
decimals
|
|
}
|
|
token1 {
|
|
id
|
|
symbol
|
|
name
|
|
decimals
|
|
}
|
|
reserve0
|
|
reserve1
|
|
totalSupply
|
|
|
|
# Related entities
|
|
swaps(first: 10, orderBy: timestamp, orderDirection: desc) {
|
|
id
|
|
timestamp
|
|
amount0In
|
|
amount1In
|
|
amount0Out
|
|
amount1Out
|
|
amountUSD
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Performance Best Practices
|
|
|
|
### Limit Response Size
|
|
- Use `first` parameter to limit results (max typically 1000, recommended 100)
|
|
- Paginate large datasets using `skip` or cursor-based pagination
|
|
- Avoid querying all items in large collections
|
|
|
|
### Use Specific Fields
|
|
```graphql
|
|
# Good - only request needed fields
|
|
query EfficientQuery {
|
|
tokens(first: 10) {
|
|
id
|
|
symbol
|
|
name
|
|
}
|
|
}
|
|
|
|
# Avoid - requesting unnecessary nested data
|
|
query IneffcientQuery {
|
|
tokens(first: 10) {
|
|
id
|
|
symbol
|
|
name
|
|
pairs {
|
|
swaps {
|
|
# This can return massive amounts of data
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Use Aggregated Fields
|
|
```graphql
|
|
# Good - use pre-aggregated data
|
|
query GoodAggregation($contractId: String!) {
|
|
erc721Contract(id: $contractId) {
|
|
holders # Pre-calculated count
|
|
stakedHolders # Pre-calculated count
|
|
totalSupply { value }
|
|
}
|
|
}
|
|
|
|
# Avoid - counting individual records
|
|
query BadAggregation($contractId: String!) {
|
|
erc721Tokens(where: { contract: $contractId }) {
|
|
# Counting these manually is inefficient
|
|
id
|
|
}
|
|
}
|
|
```
|
|
|
|
## Common Query Scenarios
|
|
|
|
### Latest Activity
|
|
```graphql
|
|
query LatestActivity($limit: Int = 20) {
|
|
transactions(
|
|
first: $limit
|
|
orderBy: timestamp
|
|
orderDirection: desc
|
|
) {
|
|
id
|
|
timestamp
|
|
blockNumber
|
|
# ... transaction details
|
|
}
|
|
}
|
|
```
|
|
|
|
### User Portfolio
|
|
```graphql
|
|
query UserPortfolio($userAddress: String!) {
|
|
account(id: $userAddress) {
|
|
id
|
|
|
|
# ERC20 balances
|
|
erc20Balances(where: { value_gt: "0" }) {
|
|
token {
|
|
id
|
|
symbol
|
|
name
|
|
}
|
|
value
|
|
}
|
|
|
|
# ERC721 (NFT) balances
|
|
erc721Balances(where: { value_gt: "0" }) {
|
|
contract {
|
|
id
|
|
name
|
|
symbol
|
|
}
|
|
value
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Price and Volume Analysis
|
|
```graphql
|
|
query PriceVolume($pairAddress: String!, $days: Int = 7) {
|
|
pair(id: $pairAddress) {
|
|
token0 { symbol }
|
|
token1 { symbol }
|
|
token0Price
|
|
token1Price
|
|
volumeUSD
|
|
reserveUSD
|
|
|
|
# Daily historical data
|
|
pairDayData(
|
|
first: $days
|
|
orderBy: date
|
|
orderDirection: desc
|
|
) {
|
|
date
|
|
dailyVolumeUSD
|
|
reserveUSD
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Common GraphQL Errors
|
|
|
|
1. **Field doesn't exist**: Check schema with introspection
|
|
2. **Type mismatch**: Ensure variable types match schema (String vs Int vs BigInt)
|
|
3. **Query too complex**: Simplify nested queries or reduce `first` parameter
|
|
4. **Timeout**: Reduce query complexity or add more specific filters
|
|
|
|
### Debugging Queries
|
|
|
|
Use introspection to explore the schema:
|
|
```graphql
|
|
query IntrospectTypes {
|
|
__schema {
|
|
types {
|
|
name
|
|
kind
|
|
}
|
|
}
|
|
}
|
|
|
|
query IntrospectType($typeName: String!) {
|
|
__type(name: $typeName) {
|
|
name
|
|
fields {
|
|
name
|
|
type {
|
|
name
|
|
kind
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|