свой снипет.
import Foundation
import PostgresNIO
struct CountryRepository {
let client: PostgresClient
func get(id: UUID) async throws -> Country? {
let rows = try await client.query(Country.generateSelectQuery(id: id))
for try await row in rows {
return try Country(row: row.makeRandomAccess())
}
return nil
}
}
struct Country {
enum Fields {
enum V1 {
static var id = "id"
static var name = "name"
static var nameEs = "name_es"
}
}
let id: UUID
let name: String
var nameEs: String?
init(id: UUID = UUID(), name: String) {
self.id = id
self.name = name
}
init(row: PostgresRandomAccessRow) throws {
self.id = try row[Fields.V1.id].decode(UUID.self)
self.name = try row[Fields.V1.name].decode(String.self)
if row.contains(Fields.V1.nameEs) {
self.nameEs = try row[Fields.V1.nameEs].decode(String.self)
}
}
}
extension Country {
static var schema: String = "countries"
static func generateSelectQuery() -> PostgresQuery {
PostgresQuery(stringLiteral: "SELECT * FROM " + schema)
}
static func generateSelectQuery(id: UUID) -> PostgresQuery {
PostgresQuery(stringLiteral: "SELECT * FROM " + schema + " WHERE id = '\(id)'")
}
}
Безопаснее будет вместо PostgresQuery(stringLiteral:) использовать PostgresQuery(stringInterpolation:)
Я вот думал об этом. В сущности боремся с SQL инъекциями.. Но существует ли такая опасность на сервере, внутри докера, в котором только приложение общается с базой, и никуда никаких портов не прокинуто? Ну кроме 80 к приложению понятно..
Это вопрос из разряда "нужно ли включать поворотник на пустом перекрестке в 4ч утра?" Правильный ответ — не нужно вообще об этом думать, практика поступать так, как следует, должна быть закреплена на уровне рефлексов. :) Ну т.е. просто вообще никогда не нужно применять потенциально небезопасных решений и пытаться в каждом конкретном случае (кроме элементарных) выяснить спектр возможных угро и их вероятность в данном случае. Лишняя работа и ненулевая вероятность ошибочной оценки угроз. К тому же, рано или поздно наступит момент, когда ты просто скопипастишь код, подумав "я это уже делал же, у меня есть готовое решение" и забыв, что этот код писался для другого кейса.
Возвращаясь к вопросу — в коде одной из миграций у меня есть вот такое, это SQLKit: let initialId = String(LoadMigrationSeed_v2_0_0.ininialId) let rawSQL: SQLQueryString = "ALTER SEQUENCE \(raw: LoadAutoID.schema)_id_seq RESTART WITH \(raw: initialId);" return [ db.schema(LoadAutoID.schema) .field("id", .sql(raw: "SERIAL NOT NULL PRIMARY KEY")) .field(LoadAutoID.FieldKeys.updatedAt, .datetime, .required) .create(), (db as! SQLDatabase) .raw(rawSQL) .run() ].sequencedFlatMapEach(on: db.eventLoop) { $0 } (просто для информации)
Не уверен, что здесь точно происходит, но есть функции .all(decoding:) и .first(decoding:)
На картинке работа SQLKit (аналог PostgresKit). Как понимаю, это промежуточный уровень между PostgresNIO и Fluent.
PostgresNIO это сам клиент, а SQLKit универсальная обертка над всеми клиентами
Да, все верно, а Fluent еще более универсальная и более обертка)
А Fluent это уже ORM)
Обсуждают сегодня