Initial commit
This commit is contained in:
324
skills/subgraph-explorer/references/graphql_patterns.md
Normal file
324
skills/subgraph-explorer/references/graphql_patterns.md
Normal file
@@ -0,0 +1,324 @@
|
||||
# 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user