swift - Vapor:日期对象以字符串格式解码,但解码器需要双精度
问题描述
我有一个看起来像这样的数据模型:
struct Post: Content, MySQLModel, Migration, Equatable {
var id: Int?
var userId: Int
var title: String
var body: String
var creationDate: Date?
var lastEditDate: Date?
static func prepare(on connection: MySQLConnection) -> Future<Void> {
return MySQLDatabase.create(self, on: connection) { builder in
builder.field(for: \.id, isIdentifier: true)
builder.field(for: \.userId)
builder.field(for: \.title)
builder.field(for: \.body, type: .text())
builder.field(for: \.creationDate)
builder.field(for: \.lastEditDate)
}
}
}
如果我在数据库中有一些实例,我可以安全地在路径中传递帖子的 id 进行查询,我会得到一个对象,其创建/上次编辑日期以字符串格式格式化:
func retrievePost(on req: Request) throws -> Future<Post> {
let id = try req.parameters.next(Int.self)
return Post.find(id, on: req).map(to: Post.self) { post in
guard let post = post else {
throw Abort(.notFound)
}
return post
}
}
如果我进行 GET 查询,这就是我在响应正文中返回的内容:
{
"body": "value",
"id": 8723,
"title": "value",
"creationDate": "2020-05-27T15:24:41Z",
"userId": 0
}
这是我的 PUT 方法实现:
func updatePost(on req: Request) throws -> Future<Post> {
var updatedPost = try req.content.syncDecode(Post.self)
guard let id = updatedPost.id else {
throw Abort(.badRequest)
}
return Post.find(id, on: req).flatMap { post in
guard let _ = post else {
throw Abort(.notFound)
}
return updatedPost.save(on: req)
}
}
但是,如果我发送一个 PUT 请求,传递与我在 GET 响应正文中得到的完全相同的字段,并且创建日期格式为字符串,我会收到以下错误:
{
"error": true,
"reason": "Could not convert to `Double`: str(\"2020-05-27T15:24:41Z\")"
}
它期待双倍。如果我尝试发送 1970 年之后的秒数,它可以工作,但我不明白为什么相同的日期对象使用字符串日期进行编码并使用双精度进行解码。如何解决这个问题?
解决方案
和你一样,我使用:
struct MyForm {
let myDate:Date
}
在.leaf
表单中,我使用不同的字段名称来允许用户修改日期:
<input type="date" name="userDate" value="#date(myDate, "yyyy-MM-dd")">
然后,在提交按钮的onclick
事件中,我使用 javascript 计算日期的时间戳值,并在“原始”字段中返回:
var d = new Date(f["userDate"].value);
f['myDate'].value = d.getTime()/1000;
return true;
给你带来麻烦的decode
那个现在应该可以正常工作了。
我还使用 customTag 以较短的格式表示日期:
struct DateTag:LeafTag
{
public func render(_ context:LeafContext) throws -> LeafData
{
try context.requireParameterCount(2)
guard let timestamp = context.parameters.first?.double else { return .string("") }
guard let format = context.parameters[1].string else { throw "DateTag needs a format to work on" }
let df = DateFormatter()
df.dateFormat = format
return .string(df.string(from:Date(timeIntervalSince1970:timestamp)))
}
}
嵌套的双引号是可以的,因为 Leaf 仅适用于内部集,而将外部集留给浏览器。
推荐阅读
- vb.net - 如何使用小键盘输入来导航菜单中的按钮?
- c# - Roslyn 中的调用方法
- tensorflow - 在模型训练期间定义输入,TensorFlow 中的功能 API
- python-3.x - Selenium+Python3 - 无法找到这些打印和下载图标的 ID
- ruby - 使用复选框在使用 ruby 迁移时将多个字符串传递给数组
- oracle - 如何在 Windows 10 上安装 Oracle 18c 客户端
- javascript - 为什么我的函数传递给孩子时出现无法读取属性道具错误?
- java - 用文本文件中的一行(字符串)填充数组的每个槽
- javascript - 如何使用查找表来反映某些输出?
- objective-c - XCode:文件“[APP NAME].app”无法打开,因为没有这样的文件