From 5c76cc2096ebce8230edd38f5658d37fadd6c1f3 Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Tue, 29 Apr 2025 17:04:05 -0700 Subject: [PATCH] Synthesize `LosslessStringConvertible` `QueryBindable` conformances This commit makes it trivial to conform `LosslessStringConvertible` types to `QueryBindable`. --- .../StructuredQueriesCore/QueryBindable.swift | 4 ++++ .../StructuredQueriesCore/QueryDecodable.swift | 11 +++++++++++ Tests/StructuredQueriesTests/DecodingTests.swift | 16 ++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/Sources/StructuredQueriesCore/QueryBindable.swift b/Sources/StructuredQueriesCore/QueryBindable.swift index f73d2156..fcb76c11 100644 --- a/Sources/StructuredQueriesCore/QueryBindable.swift +++ b/Sources/StructuredQueriesCore/QueryBindable.swift @@ -102,6 +102,10 @@ extension DefaultStringInterpolation { } } +extension QueryBindable where Self: LosslessStringConvertible { + public var queryBinding: QueryBinding { description.queryBinding } +} + extension QueryBindable where Self: RawRepresentable, RawValue: QueryBindable { public var queryBinding: QueryBinding { rawValue.queryBinding } } diff --git a/Sources/StructuredQueriesCore/QueryDecodable.swift b/Sources/StructuredQueriesCore/QueryDecodable.swift index b5448f96..f93528ff 100644 --- a/Sources/StructuredQueriesCore/QueryDecodable.swift +++ b/Sources/StructuredQueriesCore/QueryDecodable.swift @@ -138,6 +138,17 @@ extension UInt64: QueryDecodable { } } +extension QueryDecodable where Self: LosslessStringConvertible { + @inlinable + public init(decoder: inout some QueryDecoder) throws { + guard let losslessStringConvertible = try Self(String(decoder: &decoder)) + else { + throw DataCorruptedError() + } + self = losslessStringConvertible + } +} + extension QueryDecodable where Self: RawRepresentable, RawValue: QueryDecodable { @inlinable public init(decoder: inout some QueryDecoder) throws { diff --git a/Tests/StructuredQueriesTests/DecodingTests.swift b/Tests/StructuredQueriesTests/DecodingTests.swift index 2d9caf21..ff0da712 100644 --- a/Tests/StructuredQueriesTests/DecodingTests.swift +++ b/Tests/StructuredQueriesTests/DecodingTests.swift @@ -39,6 +39,22 @@ extension SnapshotTests { #expect(bytes == [0xDE, 0xAD, 0xBE, 0xEF]) } + @Test func losslessStringConvertible() throws { + struct Email: Equatable, LosslessStringConvertible, QueryBindable { + var description: String + + init?(_ description: String) { + self.description = description + } + } + #expect( + try db.execute( + SimpleSelect { #sql("'support@pointfree.co'", as: Email.self) } + ) + .first == Email("support@pointfree.co") + ) + } + @Test func rawRepresentable() throws { enum Priority: Int, QueryBindable { case low = 1