CursorPagination 是一个用于 Vapor 的 Fluent 库,它允许你使用不透明的光标来分页查询。如果你正在寻找基于偏移量的 Fluent 分页,请查看 Pagination。如果你不确定什么是光标分页,或者你需要光标分页还是偏移量分页,我推荐这篇来自 Slack 团队的精彩 文章,它解释了两者之间的区别以及各自的优缺点。
CursorPagination 可以通过 Swift Package Manager 获得。要安装,请将以下内容添加到你的 Package.swift 文件中。
let package = Package(
name: "YourProject",
dependencies: [
...
.package(url: "https://github.com/Appsaurus/CursorPagination", from: "0.1.0"),
],
targets: [
.target(name: "YourApp", dependencies: ["CursorPagination", ... ])
]
)
查看此项目中包含的 app 以获取完整的示例。以下是一些基本用法:
1. 导入库
import CusorPagination
2. 扩展你的模型类以采用 CusorPaginatable 协议
你可以简单地声明协议采用并继承默认实现。
extension KitchenSink: CursorPaginatable{}
或者你可以通过实现以下任何静态类变量来设置一些默认配置。
extension KitchenSink: CursorPaginatable{
public static var defaultPageSorts: [CursorSort<KitchenSink>] {
return [idKey.descendingSort]
}
public static var defaultPageSize: Int {
return 20
}
public static var maxPageSize: Int? {
return 50
}
}
3. 设置你的路由
设置路由以返回一个 Future<CursorPage<YourModel>>
。当你运行查询时,只需在你的类或 QueryBuilder 上调用 paginate(request: sorts: )
。
router.get("modelsByDate") { request -> Future<CursorPage<KitchenSink>> in
return try KitchenSink.paginate(database: Database,
sorts: .descending(\.dateField))
}
在你的第一个请求中,省略光标告诉方法你正在从第一页开始。
curl "https://:8080/modelsByDate?limit=5"
结果:
{
"remaining":45,
"data":[
{
"booleanField":false,
"id":10,
"stringField":"Hammes Glen",
"doubleField":718.52944714909995,
"dateField":"2102-06-07T12:58:40Z",
"intField":82
},
{
"booleanField":false,
"id":11,
"stringField":"Stracke Green",
"doubleField":808.52215080719998,
"dateField":"2094-08-08T15:32:25Z",
"intField":714
},
{
"intField":789,
"id":30,
"dateField":"2093-01-24T07:06:53Z",
"doubleField":992.49123409219999,
"booleanField":true,
"stringField":"Schowalter Branch",
"optionalStringField":"15"
},
{
"intField":282,
"id":38,
"dateField":"2092-03-01T03:59:20Z",
"doubleField":194.4565969041,
"booleanField":true,
"stringField":"Ignacio Springs",
"optionalStringField":"20"
},
{
"booleanField":true,
"id":32,
"stringField":"Braun Rapid",
"doubleField":445.48755242620001,
"dateField":"2078-05-13T15:50:20Z",
"intField":583
}
],
"nextPageCursor":"W3sia2V5IjoiZGF0ZUZpZWxkIiwidmFsdWUiOjMzODQ2Nzc4NjgsImRpcmVjdGlvbiI6ImRlc2NlbmRpbmcifSx7ImtleSI6ImlkIiwidmFsdWUiOjQ2LCJkaXJlY3Rpb24iOiJhc2NlbmRpbmcifV0="
}
然后在你的下一个请求中使用 nextPageCursor
curl "https://:8080/modelsByDate?limit=5&cursor=W3sia2V5IjoiZGF0ZUZpZWxkIiwidmFsdWUiOjMzODQ2Nzc4NjgsImRpcmVjdGlvbiI6ImRlc2NlbmRpbmcifSx7ImtleSI6ImlkIiwidmFsdWUiOjQ2LCJkaXJlY3Rpb24iOiJhc2NlbmRpbmcifV0="
{
"remaining":40,
"data":[
{
"booleanField":false,
"id":46,
"stringField":"Aditya Crossroad",
"doubleField":226.63376066519999,
"dateField":"2077-04-03T12:17:48Z",
"intField":149
},
{
"booleanField":true,
"id":18,
"stringField":"Emmitt Ridges",
"doubleField":90.362315319999993,
"dateField":"2074-09-14T07:46:27Z",
"intField":990
},
{
"booleanField":true,
"id":27,
"stringField":"Evelyn Rest",
"doubleField":371.72649320490001,
"dateField":"2072-11-21T19:26:05Z",
"intField":77
},
{
"intField":351,
"id":45,
"dateField":"2071-04-18T00:59:09Z",
"doubleField":45.889304030200002,
"booleanField":true,
"stringField":"Fisher Trail",
"optionalStringField":"24"
},
{
"intField":476,
"id":25,
"dateField":"2070-04-10T15:16:10Z",
"doubleField":810.14490844919999,
"booleanField":false,
"stringField":"Paucek Plains",
"optionalStringField":"12"
}
],
"nextPageCursor":"W3sia2V5IjoiZGF0ZUZpZWxkIiwidmFsdWUiOjMwOTM3NTk5MzcsImRpcmVjdGlvbiI6ImRlc2NlbmRpbmcifSx7ImtleSI6ImlkIiwidmFsdWUiOjYsImRpcmVjdGlvbiI6ImFzY2VuZGluZyJ9XQ=="
}
当没有更多结果时,将不会返回光标。
对多个属性进行排序也可以。
注意
为了打破平局,最后一个排序必须是对唯一属性的排序,否则将应用对默认唯一属性(Fluent id)的排序。
router.get("modelsByBooleanAndString") { request -> Future<CursorPage<KitchenSink>> in
return try KitchenSink.paginate(database: Database,
sorts: .descending(\.booleanField), .ascending(\.stringField))
}
你可以允许客户端通过查询参数动态地指定结果的排序方式。
由于动态排序 API 无法从基于字符串的参数解析 KeyPaths,它使用运行时反射来构建光标。在 Swift ABI 稳定之前,你可能不想在生产环境中使用此 API。
像这样设置一个动态可排序的请求处理程序
router.get("dynamicModels") { request -> Future<CursorPage<KitchenSink>> in
return try KitchenSink.paginate(dynamicdatabase: Database)
}
然后在你的请求中,分别通过 sort[]
和 order[]
参数对每个内容进行排序和排序(顺序很重要):curl "https://:8080/dynamicModels?limit=5&sort[]=booleanField&order[]=descending&sort[]=stringField&order[]=ascending"
我们欢迎你为 CursorPagination 做出贡献,请查看 CONTRIBUTING 文件以获取更多信息。
CursorPagination 在 MIT 许可下可用。请查看 LICENSE 文件以获取更多信息。