import SQLKit import Vapor struct UserToken: Decodable { let token: String static func create (connection: any SQLDatabase) async throws -> UserToken { return try await connection.raw (""" SELECT string_agg (substr (c, (random() * length (c) + 1)::integer, 1), '') AS "token" FROM (VALUES ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')) AS x(c), generate_series (1, 32) """) .first (decoding: UserToken.self)! } struct Token: Content { let userId: UUID let email: String enum CodingKeys: String, CodingKey { case userId = "user_id" case email } } static func fetch (token: String, connection: any SQLDatabase) async throws -> Token? { return try await connection.raw (""" SELECT "user_id", "email" FROM "user_tokens" JOIN "users" ON "users"."id" = "user_tokens"."user_id" WHERE "token" = \(bind: token) AND "insert_time" >= CURRENT_TIMESTAMP - INTERVAL '1 HOUR' """) .first (decoding: Token.self) } static func delete (token: String, connection: any SQLDatabase) async throws { return try await connection.raw (""" DELETE FROM "user_tokens" WHERE "token" = \(bind: token) """) .run() } }