Query Conversion
Envio uses standard GraphQL query language, while TheGraph uses a custom GraphQL syntax. While the queries are very similar, there are some important differences to be aware of when migrating.
This guide covers all the differences between TheGraph's query syntax and Envio's query syntax, with examples for each conversion rule.
Converter Tool
We've built a query converter tool that automatically converts TheGraph queries to Envio's GraphQL syntax. You can:
- Convert and execute: Provide your Envio GraphQL endpoint and a query written in TheGraph syntax. The tool will convert it, execute it against your endpoint, and return the results
- Convert only: Use the tool to convert queries and view the converted output without executing them
Repository: subgraph-to-hyperindex-query-converter
Dedicated Tier: Hosted Converter Endpoint
For users on our dedicated tier, we can host the query converter as a proxy endpoint for your hosted indexer. This allows you to continue using TheGraph query syntax without making any changes to your existing queries or client code. Simply point your applications to the converter endpoint, which will automatically translate TheGraph queries to Envio's syntax and forward them to your indexer.
This converter tool is still very much in beta. We're actively working on it and discovering new query conversions that need to be handled.
If you encounter any conversion failures or incorrect conversions, please file a GitHub issue in the repository so we can address it.
1. Entity Name Conversion
Rule: TheGraph uses pluralized entity names (e.g., pools, factories, tokens), while Envio uses the entity name exactly as defined in your schema (singular, PascalCase).
Example:
# TheGraph
query {
pools { id }
factories { id }
tokens { id }
}
# Envio
query {
Pool { id }
Factory { id }
Token { id }
}
Single entity queries use EntityName_by_pk (by primary key) in Envio. Alternatively, you could use a where clause with the primary key field:
# TheGraph
query {
pool(id: "0x123") { value }
}
# Envio
query {
Pool_by_pk(id: "0x123") { value }
}
Or using a where clause:
# Envio
query {
Pool(where: {id: {_eq: "0x123"}}) { value }
}
2. Pagination Parameters
First → Limit
Rule: Use limit instead of first.
Example:
# TheGraph
query {
pools(first: 10) { id }
}
# Envio
query {
Pool(limit: 10) { id }
}
Skip → Offset
Rule: Use offset instead of skip.
Example:
# TheGraph
query {
pools(skip: 20) { id }
}
# Envio
query {
Pool(offset: 20) { id }
}
3. Ordering Parameters
OrderBy and OrderDirection → Order_by
Rule: Combine orderBy and orderDirection into a single order_by: {field: direction} clause.
Example:
# TheGraph
query {
pools(orderBy: name, orderDirection: desc) { id name }
# Use orderDirection: asc for ascending order
}
# Envio
query {
Pool(order_by: {name: desc}) { id name }
# Use asc for ascending order, e.g., order_by: {name: asc}
}
4. Filter Operators
Equality Filter
Rule: Use where: {field: {_eq: value}} format for simple equality filters.
Example:
# TheGraph
query {
pools(name: "test") { id name }
}
# Envio
query {
Pool(where: {name: {_eq: "test"}}) { id name }
}
Comparison Filters
Rule: Use Hasura filter operators for comparison filters. Replace _not with _neq, _not_in with _nin, and keep _gt, _gte, _lt, _lte, _in as-is, wrapping them in where: {field: {_operator: value}}.
Examples:
# TheGraph
query {
pools(id_not: "0x123") { id }
pools(amount_gt: 100) { id amount }
pools(amount_gte: 100) { id amount }
pools(timestamp_lt: 1650000000) { id timestamp }
pools(timestamp_lte: 1650000000) { id timestamp }
pools(id_in: ["1", "2", "3"]) { id name }
pools(id_not_in: ["1", "2", "3"]) { id name }
}
# Envio
query {
Pool(where: {id: {_neq: "0x123"}}) { id }
Pool(where: {amount: {_gt: 100}}) { id amount }
Pool(where: {amount: {_gte: 100}}) { id amount }
Pool(where: {timestamp: {_lt: 1650000000}}) { id timestamp }
Pool(where: {timestamp: {_lte: 1650000000}}) { id timestamp }
Pool(where: {id: {_in: ["1", "2", "3"]}}) { id name }
Pool(where: {id: {_nin: ["1", "2", "3"]}}) { id name }
}
String Filters
Rule: Use _ilike with % wildcards for string filters. Replace _contains with _ilike: "%text%", _starts_with with _ilike: "text%", and _ends_with with _ilike: "%text". The % symbol represents any text at that position in the pattern.
Examples:
# TheGraph
query {
pools(name_contains: "test") { id name }
pools(name_not_contains: "test") { id name }
pools(symbol_starts_with: "ABC") { id symbol }
pools(symbol_ends_with: "XYZ") { id symbol }
pools(name_not_starts_with: "A") { id name }
pools(name_not_ends_with: "x") { id name }
pools(name_contains_nocase: "test") { id name }
pools(name_starts_with_nocase: "test") { id name }
pools(name_ends_with_nocase: "test") { id name }
}
# Envio
query {
Pool(where: {name: {_ilike: "%test%"}}) { id name }
Pool(where: {_not: {name: {_ilike: "%test%"}}}) { id name }
Pool(where: {symbol: {_ilike: "ABC%"}}) { id symbol }
Pool(where: {symbol: {_ilike: "%XYZ"}}) { id symbol }
Pool(where: {_not: {name: {_ilike: "A%"}}}) { id name }
Pool(where: {_not: {name: {_ilike: "%x"}}}) { id name }
Pool(where: {name: {_ilike: "%test%"}}) { id name }
Pool(where: {name: {_ilike: "test%"}}) { id name }
Pool(where: {name: {_ilike: "%test"}}) { id name }
}
5. Variable Type Conversions
ID → String
Rule: Use String and String! instead of ID and ID! for variable types.
Example:
# TheGraph
query getPoolValue($id: ID!) {
pool(id: $id) { value }
}
# Envio
query getPoolValue($id: String!) {
Pool_by_pk(id: $id) { value }
}
Bytes → String
Rule: Use String and String! instead of Bytes and Bytes! for variable types.
Example:
# TheGraph
query getTokens($id: Bytes) {
tokens(where: { id: $id }) { id timestamp }
}
# Envio
query getTokens($id: String) {
Token(where: {id: {_eq: $id}}) { id timestamp }
}
BigInt → numeric
Rule: Use numeric and numeric! instead of BigInt and BigInt! for variable types.
Example:
# TheGraph
query GetTokens($amount: BigInt) {
tokens(where: { amount: $amount }) { id amount }
}
# Envio
query GetTokens($amount: numeric) {
Token(where: {amount: {_eq: $amount}}) { id amount }
}
BigDecimal → numeric
Rule: Use numeric and numeric! instead of BigDecimal and BigDecimal! for variable types.
Example:
# TheGraph
query GetValue($value: BigDecimal!) {
pools(where: { value: $value }) { id }
}
# Envio
query GetValue($value: numeric!) {
Pool(where: {value: {_eq: $value}}) { id }
}
Summary Table
| Category | TheGraph | Envio | Example |
|---|---|---|---|
| Entity Names | Plural camelCase | Singular PascalCase (as-is from schema) | pools → Pool |
| Pagination | first, skip | limit, offset | first: 10, skip: 20 → limit: 10, offset: 20 |
| Ordering | orderBy, orderDirection | order_by: {field: direction} | orderBy: name, orderDirection: desc → order_by: {name: desc} |
| Equality Filter | field: value | field: {_eq: value} | name: "test" → name: {_eq: "test"} |
| Comparison Filters | field_gt, field_gte, etc. | field: {_gt: value}, etc. | amount_gt: 100 → amount: {_gt: 100} |
| String Filters | _contains, _starts_with, etc. | _ilike with % wildcards | name_contains: "test" → name: {_ilike: "%test%"} |
| Variable Types | ID, Bytes, BigInt, BigDecimal | String, numeric | $id: ID! → $id: String! |
Getting Help
If you encounter any issues with query conversion or have questions:
- Converter Issues: File a GitHub issue for the converter tool
- General Questions: Join our Discord community for support