-
-
Notifications
You must be signed in to change notification settings - Fork 71
crasher in postgres-kit/Sources/PostgresKit/PostgresDataDecoder.swift, line 143 #175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Thanks for reporting @lsh-silpion. That should throw a value not found error instead of crashing. |
This seems to have something to do with me using a I refactored my code so it now looks like this (no more joins, everything in a single table): GeoJSONController: import Fluent
import Vapor
struct GeoJSONController {
func index(req: Request) throws -> EventLoopFuture<[GeoJSONDTO]> {
return GeoJSON.query(on: req.db).all()
.flatMapThrowing { geoJSONArray in
try geoJSONArray.map { geoJSON in try GeoJSONDTO(model: geoJSON) }
}.flatMapErrorThrowing { error in
throw Abort(.internalServerError)
}
}
func create(req: Request) throws -> EventLoopFuture<GeoJSON> {
let geoJSON = try req.content.decode(GeoJSON.self)
return geoJSON.save(on: req.db).map { geoJSON }
}
func get(req: Request) throws -> EventLoopFuture<String> {
return GeoJSON.find(req.parameters.get("GeoJSONID"), on: req.db)
.unwrap(or: Abort(.notFound))
.flatMapThrowing { found in
try JSONEncoder().encode(found.json)
}.map { data in
String(decoding: data, as: UTF8.self)
}.flatMapErrorThrowing { error in
throw Abort(.internalServerError)
}
}
func put(req: Request) throws -> EventLoopFuture<HTTPStatus> {
guard let payload = try? req.content.decode(AnyCodable.self) else {
throw Abort(.badRequest, reason: "Not a valid payload")
}
return GeoJSON.find(req.parameters.get("GeoJSONID"), on: req.db)
.unwrap(or: Abort(.notFound))
.map { found in
found.json = payload
found.save(on: req.db)
return .noContent
}
}
func delete(req: Request) throws -> EventLoopFuture<HTTPStatus> {
return GeoJSON.find(req.parameters.get("GeoJSONID"), on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { found in found.delete(on: req.db) }
.transform(to: .noContent)
}
} GeoJSON: import Fluent
import Vapor
final class GeoJSON: Model, Content {
static let schema = "geo_jsons"
@ID(key: .id)
var id: UUID?
@Field(key: "description")
var description: String
@Field(key: "json")
var json: AnyCodable?
init() { }
init(id: UUID? = nil, description: String) {
self.id = id
self.description = description
}
} GeoJSONDTO: import Foundation
import Vapor
struct GeoJSONDTO: Content {
var id: GeoJSON.IDValue
var description: String?
init(model: GeoJSON) throws {
self.id = try model.requireID()
self.description = model.description
}
} CreateGeoJSON: import Fluent
struct CreateGeoJSON: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
return database.schema("geo_jsons")
.id()
.field("description", .string, .required)
.field("json", .json)
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
return database.schema("geo_jsons").delete()
}
} configure: import Fluent
import FluentPostgresDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
print(app.directory.workingDirectory)
app.databases.use(.postgres(
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
username: Environment.get("DATABASE_USERNAME") ?? "MapEditor",
password: Environment.get("DATABASE_PASSWORD") ?? "mapeditor",
database: Environment.get("DATABASE_NAME") ?? "MapEditor"
), as: .psql)
app.migrations.add(CreateGeoJSON())
// register routes
try routes(app)
} routes: import Fluent
import Vapor
func routes(_ app: Application) throws {
app.get { req in
return "It works!"
}
app.group("MapEditorBackend") { mapEditorBackend in
let geoJSONController = GeoJSONController()
mapEditorBackend.get(use: geoJSONController.index)
mapEditorBackend.post(use: geoJSONController.create)
mapEditorBackend.group(":GeoJSONID") { geoJSON in
geoJSON.get(use: geoJSONController.get)
geoJSON.put(use: geoJSONController.put)
geoJSON.delete(use: geoJSONController.delete)
}
}
} and Steps to reproduce:
|
It looks that as soon as a value is in the |
Potential fix in #176 |
I created a somewhat reduced test case: Package.swift: // swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "postgres-kit_issues_175_test",
platforms: [
.macOS(.v10_15)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0-rc"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.0.0-rc"),
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0-rc"),
.package(url: "https://github.com/Flight-School/AnyCodable.git", from: "0.2.3")
],
targets: [
.target(name: "App", dependencies: [
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "Vapor", package: "vapor"),
.product(name: "AnyCodable", package: "AnyCodable")
]),
.target(name: "Run", dependencies: ["App"]),
.testTarget(name: "AppTests", dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
])
]
) Sources/App/Controllers/Issue175Controller.swift: import Fluent
import Vapor
struct Issue175Controller {
func index(req: Request) throws -> EventLoopFuture<[Issue175]> {
return Issue175.query(on: req.db).all()
}
func create(req: Request) throws -> EventLoopFuture<Issue175> {
let issue175 = try req.content.decode(Issue175.self)
return issue175.save(on: req.db).map { issue175 }
}
func delete(req: Request) throws -> EventLoopFuture<HTTPStatus> {
return Issue175.find(req.parameters.get("issue175ID"), on: req.db)
.unwrap(or: Abort(.notFound))
.flatMap { $0.delete(on: req.db) }
.transform(to: .ok)
}
} Sources/App/Migrations/CreateIssue175.swift: import Fluent
struct CreateIssue175: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
return database.schema("issue_175")
.id()
.field("json", .json)
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
return database.schema("issue_175").delete()
}
} Sources/App/Models/Issue175.swift: import Fluent
import Vapor
import AnyCodable
final class Issue175: Model, Content {
static let schema = "issue_175"
@ID(key: .id)
var id: UUID?
@Field(key: "json")
var json: AnyCodable?
init() { }
init(id: UUID? = nil, json: AnyCodable? = nil) {
self.id = id
self.json = json
}
} Sources/App/configure.swift: import Fluent
import FluentPostgresDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
app.databases.use(.postgres(
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
username: Environment.get("DATABASE_USERNAME") ?? "issue_175",
password: Environment.get("DATABASE_PASSWORD") ?? "issue_175",
database: Environment.get("DATABASE_NAME") ?? "issue_175"
), as: .psql)
app.migrations.add(CreateIssue175())
// register routes
try routes(app)
} Sources/App/routes.swift: import Fluent
import Vapor
func routes(_ app: Application) throws {
app.get { req in
return "It works!"
}
let issue175Controller = Issue175Controller()
app.get("postgres-kit_issues_175_test", use: issue175Controller.index)
app.post("postgres-kit_issues_175_test", use: issue175Controller.create)
app.delete("postgres-kit_issues_175_test", ":issue175ID", use: issue175Controller.delete)
} Sources/Run/main.swift is unchanged from the template Steps to reproduce the issue:
|
Fixed in #182 |
* 2.0.0 gm * file updates * update guide docs * fix img * fix img * fixes * fixes * fixes * fixes * fixes * fixes * fixes * fixes * code cleanup * add search path * add searchPath fixes #9 * optional password * fix decoder force unwrap #175 * pass server hostname, fixes #178 * array type test * test fluent gm branch * master + import fix
Hi,
I've got a crash in postgres-kit/Sources/PostgresKit/PostgresDataDecoder.swift, line 143:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
looking at the code there:
it says in line 143:
return convertible.init(postgresData: self.data)! as! T
looking at
convertible.init(postgresData: self.data)
I see inPostgresNIO/Data/PostgresData+Bool.swift
lines 57-62:that a call to
convertible.init(postgresData: self.data)
can indeed returnnil
, so I guess the forced unwrapping in line 143 ofPostgresDataDecoder.swift
is wrong.See also on this: https://forums.swift.org/t/vapor-4-and-fluent-bug-in-postgres-kit-sources-postgreskit-postgresdatadecoder-swift-or-my-sources/34585
If you need more information please let me know!
The text was updated successfully, but these errors were encountered: