Хитрость здесь в том, что, как разработчик сервера, курсор может быть буквально любым значением, которое вы хотите закодировать как строку.Большинство примеров, которые я видел, были закодированы в base64 для немного непрозрачности, но это не обязательно.(Попробуйте, например, base64-декодирование курсоров из примеров Star Wars в вашей ссылке.)
Допустим, ваша схема GraphQL выглядит как
enum ThingColumn { FOO BAR }
input ThingFilter {
foo: Int
bar: Int
}
type Query {
things(
filter: ThingFilter,
sort: ThingColumn,
first: Int,
after: String
): ThingConnection
}
Ваш первый запрос может быть
query {
things(filter: { foo: 1 }, sort: BAR, first: 2) {
edges {
node { bar }
}
pageInfo {
endCursor
hasNextPage
}
}
}
Само по себе это может довольно прямо переводиться в SQL-запрос, например
SELECT bar FROM things WHERE foo=1 ORDER BY bar ASC LIMIT 2;
Теперь, когда вы перебираете каждый элемент, вы можете просто использовать строковую версию его смещения в качестве курсора;это полностью разрешено спецификацией.
{
"data": {
"things": {
"edges": [
{ "node": { "bar": 17 } },
{ "node": { "bar": 42 } }
],
"pageInfo": {
"endCursor": "2",
"hasNextPage": true
}
}
}
}
Затем, когда следующий запрос скажет after: "2"
, вы можете превратить его обратно в SQL OFFSET
и повторить запрос.
Если выПытаясь создать общий интерфейс GraphQL, который переводится на достаточно общие запросы SQL, невозможно создать индексы, которые бы выполняли каждый запрос «быстро».Как и в других случаях, вам нужно выяснить, каковы ваши общие и / или медленные запросы и CREATE INDEX
при необходимости.Возможно, вы сможете ограничить параметры в своей схеме теми вещами, которые, как вы знаете, можете индексировать:
type Other {
things(first: Int, after: String): ThingConnection
}
query OtherThings($id: ID!, $cursor: String) {
node(id: $id) {
... on Other {
things(first: 100, after: $cursor) { ... FromAbove }
}
}
}
SELECT * FROM things WHERE other_id=? ORDER BY id LIMIT ?;
CREATE INDEX things_other ON things(other_id);