mirror of
https://github.com/luxfi/graph.git
synced 2026-09-24 00:26:07 +00:00
parseTopFields split top-level fields on NEWLINES, so a one-line document parsed as a single field — name taken up to the first paren — and every field after it was dropped with no error. The explore page asks for its bundle, factory, tokens, pools and day series in one document; minified, it would have been answered with the bundle alone. A field now ends where its own arguments and selection set end, which is the same place whether the client pretty-prints or not. Also from reading the live wire: a day's token-denominated value locked was rendered as currency (two decimals reads a small holding as none), and the token a row points at was a stub — a client selecting through it saw a token that had never traded. Co-authored-by: Hanzo Dev <[email protected]>
90 lines
3.0 KiB
Go
90 lines
3.0 KiB
Go
package engine
|
|
|
|
import "testing"
|
|
|
|
// A document is the same document minified. Splitting top-level fields on
|
|
// newlines answered a one-line query with its FIRST field and dropped the rest
|
|
// without an error — the shape every client library produces when it strips
|
|
// whitespace, and the shape of the explore page's whole document.
|
|
|
|
func names(t *testing.T, query string) []string {
|
|
t.Helper()
|
|
fs, err := parseTopFields(query)
|
|
if err != nil {
|
|
t.Fatalf("parse %q: %v", query, err)
|
|
}
|
|
out := make([]string, 0, len(fs))
|
|
for _, f := range fs {
|
|
n := f.name
|
|
if f.alias != "" {
|
|
n = f.alias + ":" + f.name
|
|
}
|
|
out = append(out, n)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestTopFieldsSurviveMinification(t *testing.T) {
|
|
const pretty = `{
|
|
bundle(id: "1") { ethPriceUSD }
|
|
factories(first: 1) { id poolCount }
|
|
tokenDayDatas(where: { date_gte: 1767225600 }, orderBy: date, orderDirection: desc, first: 100) {
|
|
token { id }
|
|
date
|
|
volumeUSD
|
|
}
|
|
poolDayDatas(first: 90, orderBy: date, orderDirection: desc, where: { pool: "0xabc" }) { date open high low close }
|
|
}`
|
|
minified := `{bundle(id:"1"){ethPriceUSD} factories(first:1){id poolCount} tokenDayDatas(where:{date_gte:1767225600},orderBy:date,orderDirection:desc,first:100){token{id} date volumeUSD} poolDayDatas(first:90,orderBy:date,orderDirection:desc,where:{pool:"0xabc"}){date open high low close}}`
|
|
|
|
want := []string{"bundle", "factories", "tokenDayDatas", "poolDayDatas"}
|
|
for label, q := range map[string]string{"pretty": pretty, "minified": minified} {
|
|
got := names(t, q)
|
|
if len(got) != len(want) {
|
|
t.Fatalf("%s: parsed %v, want %v", label, got, want)
|
|
}
|
|
for i := range want {
|
|
if got[i] != want[i] {
|
|
t.Errorf("%s: field %d = %q, want %q", label, i, got[i], want[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// The arguments have to survive the split too, or a chart asks for 90 days
|
|
// of one pool and is answered with a default page of everything.
|
|
fs, err := parseTopFields(minified)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
limit, orderBy, dir, where := parseListArgs(fs[3].args, 30)
|
|
if limit != 90 || orderBy != "date" || dir != "desc" {
|
|
t.Errorf("poolDayDatas args = first %d, orderBy %q, %q; want 90, date, desc", limit, orderBy, dir)
|
|
}
|
|
if where == nil || where["pool"] != "0xabc" {
|
|
t.Errorf("poolDayDatas where = %v, want pool 0xabc", where)
|
|
}
|
|
}
|
|
|
|
func TestTopFieldsParseAliasesAndBareFields(t *testing.T) {
|
|
for _, c := range []struct {
|
|
query string
|
|
want []string
|
|
}{
|
|
{`{a:pools(first:1){id} b:pools(first:2){id}}`, []string{"a:pools", "b:pools"}},
|
|
{`{bundle{ethPriceUSD} factory{id}}`, []string{"bundle", "factory"}},
|
|
{"{ bundles\n factories }", []string{"bundles", "factories"}},
|
|
{`{pools(where:{token0:"0x1"}){id token0{id}} swaps(first:1){id}}`, []string{"pools", "swaps"}},
|
|
} {
|
|
got := names(t, c.query)
|
|
if len(got) != len(c.want) {
|
|
t.Errorf("%s parsed %v, want %v", c.query, got, c.want)
|
|
continue
|
|
}
|
|
for i := range c.want {
|
|
if got[i] != c.want[i] {
|
|
t.Errorf("%s: field %d = %q, want %q", c.query, i, got[i], c.want[i])
|
|
}
|
|
}
|
|
}
|
|
}
|