在使用筛选器参数和order by时,如何在GraphQL/Relay中使用(不透明)游标

在使用筛选器参数和order by时,如何在GraphQL/Relay中使用(不透明)游标,graphql,relayjs,relay,Graphql,Relayjs,Relay,设想以下GraphQL请求: { books( first:10, filter: [{field: TITLE, contains: "Potter"}], orderBy: [{sort: PRICE, direction: DESC}, {sort: TITLE}] ) } 结果将返回与中继光标信息的连接 光标是否应包含过滤器和orderBy详细信息 这意味着查询下一组数据只意味着: { books(first:10, after:"opaque-cu

设想以下GraphQL请求:

{
  books(
    first:10,
    filter: [{field: TITLE, contains: "Potter"}],
    orderBy: [{sort: PRICE, direction: DESC}, {sort: TITLE}]
  )
}
结果将返回与中继光标信息的连接

光标是否应包含
过滤器
orderBy
详细信息

这意味着查询下一组数据只意味着:

{
  books(first:10, after:"opaque-cursor")
}
或者应该重复
过滤器
排序依据

在后一种情况下,用户可以指定不同的
过滤器
和/或
orderBy
详细信息,这将使不透明光标无效


我在中继规范中找不到与此相关的任何内容。

我看到了多种方法,但我发现,使用基于光标的分页,光标只存在于数据集中,更改过滤器会更改数据集,使其无效

如果您使用的是SQL(或者没有基于游标的分页的东西),那么您需要在游标中包含足够的信息,以便能够恢复它。您的光标需要包含所有过滤器/订单信息,并且您需要禁止任何其他过滤


如果他们发送“after”和“filter/orderBy”,则必须抛出一个错误。如果出现用户错误,您可以选择检查参数是否与光标中的参数相同,但根本没有获取不同数据集的“第2页”的用例。

我遇到了相同的问题,得出了与@Dan Crews相同的结论。光标必须包含执行数据库查询所需的所有内容,但
LIMIT
除外

当您的初始查询类似于

SELECT *
FROM DataTable
WHERE filterField = 42
ORDER BY sortingField,ASC
LIMIT 10
-- with implicit OFFSET 0
然后你基本上可以(不要在真正的应用程序中这样做,因为SQL注入!)使用这个查询作为你的光标。您只需为每个节点删除
限制x
并附加
偏移量y

答复:

{
  edges: [
    {
      cursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 0",
      node: { ... }
    },
    {
      cursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 1",
      node: { ... }
    },
    ...,
    {
      cursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 9",
      node: { ... }
    }
  ]
  pageInfo: {
    startCursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 0"
    endCursor: "SELECT ... WHERE ... ORDER BY ... OFFSET 9"
  }
}
然后,下一个请求将使用
after:CURSOR,first:10
。然后,您将使用
after
参数并设置
限制
偏移

  • LIMIT=first
  • OFFSET=OFFSET+1
使用
after=endCursor
时,生成的数据库查询如下:

SELECT *
FROM DataTable
WHERE filterField = 42
ORDER BY sortingField,ASC
LIMIT 10
OFFSET 10

如上所述:这只是一个示例,它非常容易受到SQL注入的攻击


在现实世界的应用程序中,您只需在光标内对提供的
过滤器
orderBy
参数进行编码,并添加
偏移量

函数handleGraphQLRequest(第一个、第二个、过滤器、orderBy){
let offset=0;//如果未提供after,则为初始偏移量
如果(在!=null之后){
//不允许after+筛选器/orderBy的组合!
if(filter!=null | | orderBy!=null){
抛出新错误(“您不能将after与筛选器和/或orderBy组合”);
}
//解析筛选器、orderBy、从光标后的偏移量
cursorData=fromBase64字符串(之后);
filter=cursorData.filter;
orderBy=cursorData.orderBy;
偏移量=游标数据。偏移量;
}
const databaseResult=已执行的DatabaseQuery(
过滤器,//=其中。。。
订购人,//=订购人。。。
首先,//=LIMIT。。。
偏移量//=偏移量。。。
);
const edges=[];//这是结果边数组
让currentOffset=offset;//用于计算每个节点的偏移量
for(让databaseResult.nodes的节点){//遍历数据库结果
currentOffset++;
const currentCursor=createCursorForNode(筛选器、orderBy、currentOffset);
推({
游标=当前游标,
节点=节点
});
}
返回{
边缘:边缘,
pageInfo:buildPageInfo(边、总数、偏移量)//而不是
//为了提供totalCount,您还可以从
//数据库,以检查是否有下一页可用
}
}
//此函数返回光标字符串
函数createCursorForNode(筛选器、orderBy、偏移量){
返回toBase64String({
过滤器:过滤器,
orderBy:orderBy,
偏移量:偏移量
});
}
//用于生成pageInfo对象的函数
函数buildPageInfo(边、总计数、偏移){
返回{
startCursor:edges.length?边[0]。光标:null,
endCursor:edges.length?边[edges.length-1]。光标:null,
hasPreviousPage:偏移量>0&&totalCount>0,
hasNextPage:偏移+边。长度<总计数
}
}
游标的内容主要取决于您的数据库和数据库布局


上面的代码模拟了带有限制和偏移量的简单分页。但是你当然可以(如果你的数据库支持的话)使用其他东西。

与此同时,我得出了另一个结论:我认为你是否使用一个多功能游标,或者你是否对每个请求重复
筛选
orderBy
,其实并不重要

基本上有两种类型的游标:

(1.)可以将光标视为“指向特定项的指针”。这样,过滤器和排序可以更改,但光标可以保持不变。有点像quicksort中的pivot元素,其中pivot元素保持不变,并且周围的所有东西都可以移动

像这样工作。这里的
光标
只是指向数据集中特定项的指针。但是,
filter
orderBy
可以独立更改

这种风格的游标的实现非常简单:只需concat每个可排序字段。完成。示例:如果您的实体可以按
price
title
排序(当然还有
id
,因为您需要一些唯一的字段作为平分符),则光标始终由
{id,price,title}
组成

(2.)另一方面,“一体式光标”的作用类似于“指向过滤和排序结果集中的项目的指针”。它的好处是,你可以编码你想要的任何东西。Th