feat: Implements common database interactions as dependencies.

This commit is contained in:
2025-01-10 22:37:59 -05:00
parent 6f206bbd82
commit 69351d0a0b
11 changed files with 325 additions and 207 deletions

View File

@@ -1,36 +1,56 @@
import Dependencies
import DependenciesMacros
import Fluent
import Vapor
struct UserDB {
func create(_ model: User.Create, on db: any Database) async throws -> User.DTO {
guard model.password == model.confirmPassword else {
throw Abort(.badRequest, reason: "Passwords did not match.")
}
let user = try User(
username: model.username,
email: model.email,
passwordHash: Bcrypt.hash(model.password)
)
try await user.save(on: db)
return user.toDTO()
extension DependencyValues {
var users: UserDB {
get { self[UserDB.self] }
set { self[UserDB.self] = newValue }
}
}
@DependencyClient
struct UserDB: Sendable {
var create: @Sendable (User.Create) async throws -> User.DTO
var delete: @Sendable (User.IDValue) async throws -> Void
var fetchAll: @Sendable () async throws -> [User.DTO]
var login: @Sendable (User) async throws -> UserToken
}
extension UserDB: TestDependencyKey {
static let testValue: UserDB = Self()
static func live(database db: any Database) -> Self {
self.init(
create: { model in
guard model.password == model.confirmPassword else {
throw Abort(.badRequest, reason: "Passwords did not match.")
}
let user = try User(
username: model.username,
email: model.email,
passwordHash: Bcrypt.hash(model.password)
)
try await user.save(on: db)
return user.toDTO()
},
delete: { id in
guard let user = try await User.find(id, on: db) else {
throw Abort(.notFound)
}
try await user.delete(on: db)
},
fetchAll: {
try await User.query(on: db).all().map { $0.toDTO() }
},
login: { user in
let token = try user.generateToken()
try await token.save(on: db)
return token
}
)
}
func login(user: User, on db: any Database) async throws -> UserToken {
let token = try user.generateToken()
try await token.save(on: db)
return token
}
func fetchAll(on db: any Database) async throws -> [User.DTO] {
try await User.query(on: db).all().map { $0.toDTO() }
}
func delete(id: User.IDValue, on db: any Database) async throws {
guard let user = try await User.find(id, on: db) else {
throw Abort(.notFound)
}
try await user.delete(on: db)
}
}