不支持 GraphQL 范围查询(但……它们即将推出!)
FaunaDB 不为其GraphQL提供开箱即用的范围查询,我们正在开发这些功能。
..但有一个解决方法。
这并不意味着它不能进行范围查询,因为FQL支持范围查询,并且您始终可以通过编写用户定义函数 (UDF) 从 GraphQL“逃逸”到 FQL 以实现更高级的查询。
.. 使用解析器
通过在架构中使用@resolver关键字,您可以通过在 FQL 中的 FaunaDB 中编写用户定义函数来自己实现 GraphQL 查询。文档中有一些基本示例,我想您可能需要一些帮助,所以我会给您写一个简单的示例。
我添加了您的架构并添加了两个文档:

首先,我们的模式将使用解析器进行扩展:
type Todo {
name: String!
created_at: Time
}
type Query {
allTodos: [Todo!]!
todosByCreatedAtFlag(created_at: Time!): [Todo!]!
todosByCreatedRange(before: Time, after:Time): [Todo!]! @resolver
}
所有这一切都是为我们添加一个函数来实现:

如果我们通过 GraphQL 调用,它会为我们提供我们之前在屏幕截图中看到的 Abort 消息,因为它尚未实现。但我们可以看到,GraphQL 语句实际上调用了函数。

.. UDF 实施
我们要做的第一件事是添加一个参数,它只是写一个名字作为 lambda 的第一个参数:

如果您需要传递多个参数,它还需要一个数组(我在架构中定义的解析器中执行此操作):

我们将添加一个索引来支持我们的查询。值用于范围(以及返回值和排序)。我们将添加 created_at 以覆盖它并添加ref,因为我们需要返回值来获取索引后面的实际文档。

然后我们可以从编写一个简单的函数开始(这还行不通)
Query(
Lambda(
["before", "after"],
Paginate(
Range(Match(Index("todosByCreatedAtRange")), Var("before"), Var("after"))
)
)
)
并且可以通过shell手动调用函数来测试它。

这确实返回了两个对象(范围包括在内)。当然,这样做有一个问题,它不会以GraphQL 期望的结构返回数据,所以我们会得到这些奇怪的错误:

我们现在可以做两件事,或者在我们的模式中定义一个适合这些的类型和/或者我们可以调整返回的数据。我们将做后者并将我们的结果调整为预期的 [Todo!]!结果给你看。
第一步,映射结果。我们在这里唯一介绍的是 Map 和 Lambda。我们还没有做任何特别的事情,我们只是返回引用而不是 ts 和引用作为示例。
Query(
Lambda(
["before", "after"],
Map(
Paginate(
Range(
Match(Index("todosByCreatedAtRange")),
Var("before"),
Var("after")
)
),
Lambda(["created_at", "ref"], Var("ref"))
)
)
)
调用它确实表明该函数现在只返回引用。

让我们获取实际文件。我知道 FQL 很冗长(并且有充分的理由,尽管将来应该变得不那么冗长)所以我开始添加评论以澄清事情
Query(
Lambda(
["before", "after"],
Map(
// This is just the query to get your range
Paginate(
Range(
Match(Index("todosByCreatedAtRange")),
Var("before"),
Var("after")
)
),
// This is a function that will be executed on each result (with the help of Map)
Lambda(["created_at", "ref"],
// We'll use Let to structure our queries ( allowing us to use varaibles )
Let({
todo: Get(Var("ref"))
},
// And then we return something
Var("todo")))
)
)
)
我们的函数现在返回数据.. woohoo!

我们仍然需要确保这些数据符合 GraphQL 的预期,并且从模式中我们可以看到它需要一个 [Todo!]!(参见 docs 选项卡)和 Todo 看起来像(参见 schema 选项卡):
type Todo {
_id: ID!
_ts: Long!
name: String!
created_at: Time
}
您还可以从该文档选项卡中看到,“非解析器”查询会自动更改为返回 TodoPages。到目前为止,我们编写的函数实际上是返回页面。
选项 1,更改架构并将其转换为分页解析器。
我们可以通过向解析器添加 paginated: true 选项来解决这个问题。您将不得不考虑将添加到解析器的额外参数,如此处所述。我自己没有尝试过,所以我不能 100% 确定它会如何工作。分页解析的优点是您可以立即利用 GraphQL 端点中的合理分页。
选项2,将其转换为非分页结果。
分页结果如下所示: { data: [ document1, document2, .. ], before: ... after: .. }
结果不接受页面,而是一个数组,因此我将对其进行更改并检索数据字段:

我们有我们的结果。

完整的查询如下所示:
Query(
Lambda(
["before", "after"],
Select(
["data"],
Map(
Paginate(
Range(
Match(Index("todosByCreatedAtRange")),
Var("before"),
Var("after")
)
),
Lambda(
["created_at", "ref"],
Let({ todo: Get(Var("ref")) }, Var("todo"))
)
)
)
)
)
免责声明
一旦你去自定义,分页也成为你的责任(例如传递一个额外的参数)。您不能再像通常通过请求 GraphQL 正文中的关系来获取开箱即用的关系了。
关于 UDF 和 GraphQL/FQL 混合的好处的一些话
在您回避 FQL 之前(是的,我们确实必须添加范围查询并且正在努力),这里有一些关于 UDF 方法的一般解释,以及为什么无论如何考虑它是有意义的。
在某个时刻,您会在 GraphQL 中遇到一些不可能的事情(复杂的条件事务,例如更新文档并仅在导致先前更新的某些条件为真时才更新此其他文档)。使用其他 GraphQL 实现的用户通常通过编写无服务器函数来解决这个问题,以防您必须实现高级逻辑或事务。
FaunaDB 对此的回答是使用他们的用户定义函数 (UDF)。这不是无服务器功能,它是在 FQL 中实现的 FaunaDB 功能,起初可能看起来很麻烦,但重要的是要意识到它为您提供了相同的好处(多区域/强一致性/可扩展性/免费层/按时付费)你去)FaunaDB 提供。