Skip to content

Commit db9bf8e

Browse files
authored
Add @Table diagnostic for empty structs (pointfreeco#14)
1 parent 054c3c4 commit db9bf8e

File tree

3 files changed

+99
-68
lines changed

3 files changed

+99
-68
lines changed

Sources/StructuredQueriesMacros/TableMacro.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,19 @@ extension TableMacro: ExtensionMacro {
526526
conformances = protocolNames.map { "\(moduleName).\($0)" }
527527
}
528528

529+
if columnsProperties.isEmpty {
530+
diagnostics.append(
531+
Diagnostic(
532+
node: node,
533+
message: MacroExpansionErrorMessage(
534+
"""
535+
'@Table' requires at least one stored column property to be defined on '\(type)'
536+
"""
537+
)
538+
)
539+
)
540+
}
541+
529542
guard diagnostics.isEmpty else {
530543
diagnostics.forEach(context.diagnose)
531544
return []

Tests/StructuredQueriesMacrosTests/TableMacroTests.swift

Lines changed: 84 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -957,90 +957,108 @@ extension SnapshotTests {
957957
"""#
958958
}
959959
}
960-
}
961-
962-
@Test func noTypeWithAs() {
963-
assertMacro {
964-
"""
965-
@Table
966-
struct RemindersList: Hashable, Identifiable {
967-
var id: Int
968-
@Column(as: Color.HexRepresentation.self)
969-
var color = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
970-
var name = ""
971-
}
972-
"""
973-
} expansion: {
974-
#"""
975-
struct RemindersList: Hashable, Identifiable {
976-
var id: Int
977-
var color = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
978-
var name = ""
979-
}
980960

981-
extension RemindersList: StructuredQueries.Table, StructuredQueries.PrimaryKeyedTable {
982-
public struct TableColumns: StructuredQueries.TableDefinition, StructuredQueries.PrimaryKeyedTableDefinition {
983-
public typealias QueryValue = RemindersList
984-
public let id = StructuredQueries.TableColumn<QueryValue, Int>("id", keyPath: \QueryValue.id)
985-
public let color = StructuredQueries.TableColumn<QueryValue, Color.HexRepresentation>("color", keyPath: \QueryValue.color, default: Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255))
986-
public let name = StructuredQueries.TableColumn<QueryValue, Swift.String>("name", keyPath: \QueryValue.name, default: "")
987-
public var primaryKey: StructuredQueries.TableColumn<QueryValue, Int> {
988-
self.id
989-
}
990-
public static var allColumns: [any StructuredQueries.TableColumnExpression] {
991-
[QueryValue.columns.id, QueryValue.columns.color, QueryValue.columns.name]
992-
}
961+
@Test func noTypeWithAs() {
962+
assertMacro {
963+
"""
964+
@Table
965+
struct RemindersList: Hashable, Identifiable {
966+
var id: Int
967+
@Column(as: Color.HexRepresentation.self)
968+
var color = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
969+
var name = ""
993970
}
994-
public struct Draft: StructuredQueries.TableDraft {
995-
public typealias PrimaryTable = RemindersList
996-
@Column(primaryKey: false)
997-
var id: Int?
998-
@Column(as: Color.HexRepresentation.self) var color = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
971+
"""
972+
} expansion: {
973+
#"""
974+
struct RemindersList: Hashable, Identifiable {
975+
var id: Int
976+
var color = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
999977
var name = ""
1000-
public struct TableColumns: StructuredQueries.TableDefinition {
1001-
public typealias QueryValue = RemindersList.Draft
1002-
public let id = StructuredQueries.TableColumn<QueryValue, Int?>("id", keyPath: \QueryValue.id)
978+
}
979+
980+
extension RemindersList: StructuredQueries.Table, StructuredQueries.PrimaryKeyedTable {
981+
public struct TableColumns: StructuredQueries.TableDefinition, StructuredQueries.PrimaryKeyedTableDefinition {
982+
public typealias QueryValue = RemindersList
983+
public let id = StructuredQueries.TableColumn<QueryValue, Int>("id", keyPath: \QueryValue.id)
1003984
public let color = StructuredQueries.TableColumn<QueryValue, Color.HexRepresentation>("color", keyPath: \QueryValue.color, default: Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255))
1004985
public let name = StructuredQueries.TableColumn<QueryValue, Swift.String>("name", keyPath: \QueryValue.name, default: "")
986+
public var primaryKey: StructuredQueries.TableColumn<QueryValue, Int> {
987+
self.id
988+
}
1005989
public static var allColumns: [any StructuredQueries.TableColumnExpression] {
1006990
[QueryValue.columns.id, QueryValue.columns.color, QueryValue.columns.name]
1007991
}
1008992
}
993+
public struct Draft: StructuredQueries.TableDraft {
994+
public typealias PrimaryTable = RemindersList
995+
@Column(primaryKey: false)
996+
var id: Int?
997+
@Column(as: Color.HexRepresentation.self) var color = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
998+
var name = ""
999+
public struct TableColumns: StructuredQueries.TableDefinition {
1000+
public typealias QueryValue = RemindersList.Draft
1001+
public let id = StructuredQueries.TableColumn<QueryValue, Int?>("id", keyPath: \QueryValue.id)
1002+
public let color = StructuredQueries.TableColumn<QueryValue, Color.HexRepresentation>("color", keyPath: \QueryValue.color, default: Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255))
1003+
public let name = StructuredQueries.TableColumn<QueryValue, Swift.String>("name", keyPath: \QueryValue.name, default: "")
1004+
public static var allColumns: [any StructuredQueries.TableColumnExpression] {
1005+
[QueryValue.columns.id, QueryValue.columns.color, QueryValue.columns.name]
1006+
}
1007+
}
1008+
public static let columns = TableColumns()
1009+
public static let tableName = RemindersList.tableName
1010+
public init(decoder: inout some StructuredQueries.QueryDecoder) throws {
1011+
self.id = try decoder.decode(Int.self)
1012+
self.color = try decoder.decode(Color.HexRepresentation.self) ?? Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
1013+
self.name = try decoder.decode(Swift.String.self) ?? ""
1014+
}
1015+
public init(_ other: RemindersList) {
1016+
self.id = other.id
1017+
self.color = other.color
1018+
self.name = other.name
1019+
}
1020+
public init(
1021+
id: Int? = nil,
1022+
color: Color.HexRepresentation.QueryOutput = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255),
1023+
name: Swift.String = ""
1024+
) {
1025+
self.id = id
1026+
self.color = color
1027+
self.name = name
1028+
}
1029+
}
10091030
public static let columns = TableColumns()
1010-
public static let tableName = RemindersList.tableName
1031+
public static let tableName = "remindersLists"
10111032
public init(decoder: inout some StructuredQueries.QueryDecoder) throws {
1012-
self.id = try decoder.decode(Int.self)
1033+
let id = try decoder.decode(Int.self)
10131034
self.color = try decoder.decode(Color.HexRepresentation.self) ?? Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
10141035
self.name = try decoder.decode(Swift.String.self) ?? ""
1015-
}
1016-
public init(_ other: RemindersList) {
1017-
self.id = other.id
1018-
self.color = other.color
1019-
self.name = other.name
1020-
}
1021-
public init(
1022-
id: Int? = nil,
1023-
color: Color.HexRepresentation.QueryOutput = Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255),
1024-
name: Swift.String = ""
1025-
) {
1036+
guard let id else {
1037+
throw QueryDecodingError.missingRequiredColumn
1038+
}
10261039
self.id = id
1027-
self.color = color
1028-
self.name = name
10291040
}
10301041
}
1031-
public static let columns = TableColumns()
1032-
public static let tableName = "remindersLists"
1033-
public init(decoder: inout some StructuredQueries.QueryDecoder) throws {
1034-
let id = try decoder.decode(Int.self)
1035-
self.color = try decoder.decode(Color.HexRepresentation.self) ?? Color(red: 0x4a / 255, green: 0x99 / 255, blue: 0xef / 255)
1036-
self.name = try decoder.decode(Swift.String.self) ?? ""
1037-
guard let id else {
1038-
throw QueryDecodingError.missingRequiredColumn
1039-
}
1040-
self.id = id
1042+
"""#
1043+
}
1044+
}
1045+
1046+
@Test func emptyStruct() {
1047+
assertMacro {
1048+
"""
1049+
@Table
1050+
struct Foo {
10411051
}
1052+
"""
1053+
} diagnostics: {
1054+
"""
1055+
@Table
1056+
┬─────
1057+
╰─ 🛑 '@Table' requires at least one stored column property to be defined on 'Foo'
1058+
struct Foo {
1059+
}
1060+
"""
10421061
}
1043-
"""#
10441062
}
10451063
}
10461064

Tests/StructuredQueriesTests/UpdateTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ extension SnapshotTests {
365365
WHERE ("reminders"."id" = 1)
366366
RETURNING "dueDate"
367367
"""
368-
}results: {
368+
} results: {
369369
"""
370370
┌─────┐
371371
│ nil │
@@ -383,7 +383,7 @@ extension SnapshotTests {
383383
WHERE ("reminders"."id" = 1)
384384
RETURNING "dueDate"
385385
"""
386-
}results: {
386+
} results: {
387387
"""
388388
┌────────────────────────────────┐
389389
│ Date(2018-01-29T00:08:00.000Z) │

0 commit comments

Comments
 (0)