Skip to content

Commit 5de1b89

Browse files
committed
wip
1 parent 42392bd commit 5de1b89

2 files changed

Lines changed: 649 additions & 184 deletions

File tree

Sources/StructuredQueriesMacros/TableMacro.swift

Lines changed: 128 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ extension TableMacro: ExtensionMacro {
408408
}
409409
initDecoder = """
410410
411-
\(raw: initAccess)\(nonisolated)init(decoder: inout some \(moduleName).QueryDecoder) throws {
411+
\(raw: initAccess)\(nonisolated)\
412+
init(decoder: inout some \(moduleName).QueryDecoder) throws {
412413
\(raw: (decodings + decodingUnwrappings + decodingAssignments).joined(separator: "\n"))
413414
}
414415
"""
@@ -1229,7 +1230,8 @@ extension TableMacro: MemberMacro {
12291230
draft = """
12301231
12311232
@_Draft(\(type).self)
1232-
\(raw: draftAccess)struct Draft: \(moduleName).TableDraft, \(moduleName).PartialSelectStatement {
1233+
\(raw: draftAccess)struct Draft: \
1234+
\(moduleName).TableDraft, \(moduleName).PartialSelectStatement {
12331235
public typealias SourceTable = \(type)
12341236
\(draftProperties, separator: "\n")
12351237
}
@@ -1319,84 +1321,135 @@ extension TableMacro: MemberMacro {
13191321
} ?? []
13201322
)
13211323
if !codableConformances.isEmpty,
1322-
declaration.is(StructDeclSyntax.self)
1323-
? codingKeys.contains(where: { $0.rawValue != nil })
1324-
: declaration.is(EnumDeclSyntax.self),
1325-
!declaration.memberBlock.members.contains(where: {
1324+
declaration.is(StructDeclSyntax.self) || declaration.is(EnumDeclSyntax.self)
1325+
{
1326+
let attributeName = node.attributeName.identifier ?? "Table"
1327+
let customCodingKeys = declaration.memberBlock.members.first {
13261328
$0.decl.as(EnumDeclSyntax.self)?.name.text == "CodingKeys"
13271329
|| $0.decl.as(StructDeclSyntax.self)?.name.text == "CodingKeys"
13281330
|| $0.decl.as(TypeAliasDeclSyntax.self)?.name.text == "CodingKeys"
1329-
})
1330-
{
1331-
let codingKeysCases: [DeclSyntax] = codingKeys.map { identifier, rawValue in
1332-
rawValue.map { "case \(identifier) = \($0)" } ?? "case \(identifier)"
13331331
}
1334-
codingKeysDecl = """
1335-
1336-
private enum CodingKeys: Swift.String, Swift.CodingKey {
1337-
\(codingKeysCases, separator: "\n")
1338-
}
1339-
"""
1340-
if declaration.is(EnumDeclSyntax.self) {
1341-
let hasManualDecode = declaration.memberBlock.members.contains {
1342-
$0.decl.as(InitializerDeclSyntax.self)?
1343-
.signature.parameterClause.parameters.first?.firstName.text == "from"
1344-
}
1345-
let hasManualEncode = declaration.memberBlock.members.contains {
1346-
guard let function = $0.decl.as(FunctionDeclSyntax.self) else { return false }
1347-
return function.name.text == "encode"
1348-
&& function.signature.parameterClause.parameters.first?.firstName.text == "to"
1349-
}
1350-
if !hasManualDecode,
1351-
codableConformances.contains("Codable") || codableConformances.contains("Decodable")
1352-
{
1353-
let decodeCases: [DeclSyntax] = codableEnumCases.map { identifier, label, payloadType in
1354-
"""
1355-
case .\(identifier):
1356-
self = .\(identifier)(\
1357-
\(raw: label.map { "\($0.text): " } ?? "")\
1358-
try container.decode(\(payloadType).self, forKey: .\(identifier)))
1359-
"""
1360-
}
1361-
codableDecls.append(
1362-
"""
1363-
public \(nonisolated)init(from decoder: any Swift.Decoder) throws {
1364-
let container = try decoder.container(keyedBy: CodingKeys.self)
1365-
guard container.allKeys.count == 1, let key = container.allKeys.first
1366-
else {
1367-
throw Swift.DecodingError.dataCorrupted(
1368-
Swift.DecodingError.Context(
1369-
codingPath: container.codingPath,
1370-
debugDescription: "Invalid number of keys found."
1371-
)
1332+
if let customCodingKeys {
1333+
context.diagnose(
1334+
Diagnostic(
1335+
node: customCodingKeys.decl,
1336+
message: MacroExpansionErrorMessage(
1337+
"""
1338+
'@\(attributeName)' derives 'CodingKeys' from its columns and cannot define custom \
1339+
'CodingKeys'
1340+
"""
1341+
),
1342+
fixIt: .replace(
1343+
message: MacroExpansionFixItMessage("Remove 'CodingKeys'"),
1344+
oldNode: customCodingKeys,
1345+
newNode: TokenSyntax("")
13721346
)
1373-
}
1374-
switch key {
1375-
\(decodeCases, separator: "\n")
1376-
}
1377-
}
1378-
"""
13791347
)
1348+
)
1349+
} else {
1350+
let codingKeysCases: [DeclSyntax] = codingKeys.map { identifier, rawValue in
1351+
rawValue.map { "case \(identifier) = \($0)" } ?? "case \(identifier)"
13801352
}
1381-
if !hasManualEncode,
1382-
codableConformances.contains("Codable") || codableConformances.contains("Encodable")
1383-
{
1384-
let encodeCases: [DeclSyntax] = codableEnumCases.map { identifier, _, _ in
1385-
"""
1386-
case .\(identifier)(let value):
1387-
try container.encode(value, forKey: .\(identifier))
1388-
"""
1353+
codingKeysDecl = """
1354+
1355+
private enum CodingKeys: Swift.String, Swift.CodingKey {
1356+
\(codingKeysCases, separator: "\n")
13891357
}
1390-
codableDecls.append(
1391-
"""
1392-
public \(nonisolated)func encode(to encoder: any Swift.Encoder) throws {
1393-
var container = encoder.container(keyedBy: CodingKeys.self)
1394-
switch self {
1395-
\(encodeCases, separator: "\n")
1358+
"""
1359+
}
1360+
if declaration.is(EnumDeclSyntax.self) {
1361+
if codableConformances.contains("Codable") || codableConformances.contains("Decodable") {
1362+
if let customDecode = declaration.memberBlock.members.first(where: {
1363+
$0.decl.as(InitializerDeclSyntax.self)?
1364+
.signature.parameterClause.parameters.first?.firstName.text == "from"
1365+
}) {
1366+
context.diagnose(
1367+
Diagnostic(
1368+
node: customDecode.decl,
1369+
message: MacroExpansionErrorMessage(
1370+
"""
1371+
'@\(attributeName)' derives its 'Decodable' conformance from its columns and \
1372+
cannot define a custom 'init(from:)'
1373+
"""
1374+
),
1375+
fixIt: .replace(
1376+
message: MacroExpansionFixItMessage("Remove 'init(from:)'"),
1377+
oldNode: customDecode,
1378+
newNode: TokenSyntax("")
1379+
)
1380+
)
1381+
)
1382+
} else if customCodingKeys == nil {
1383+
let decodeCases: [DeclSyntax] = codableEnumCases.map {
1384+
identifier, label, payloadType in
1385+
"""
1386+
case .\(identifier):
1387+
self = .\(identifier)(\
1388+
\(raw: label.map { "\($0.text): " } ?? "")\
1389+
try container.decode(\(payloadType).self, forKey: .\(identifier)))
1390+
"""
13961391
}
1392+
codableDecls.append(
1393+
"""
1394+
public \(nonisolated)init(from decoder: any Swift.Decoder) throws {
1395+
let container = try decoder.container(keyedBy: CodingKeys.self)
1396+
guard container.allKeys.count == 1, let key = container.allKeys.first
1397+
else {
1398+
throw Swift.DecodingError.dataCorrupted(
1399+
Swift.DecodingError.Context(
1400+
codingPath: container.codingPath,
1401+
debugDescription: "Invalid number of keys found."
1402+
)
1403+
)
1404+
}
1405+
switch key {
1406+
\(decodeCases, separator: "\n")
1407+
}
1408+
}
1409+
"""
1410+
)
1411+
}
1412+
}
1413+
if codableConformances.contains("Codable") || codableConformances.contains("Encodable") {
1414+
if let customEncode = declaration.memberBlock.members.first(where: {
1415+
guard let function = $0.decl.as(FunctionDeclSyntax.self) else { return false }
1416+
return function.name.text == "encode"
1417+
&& function.signature.parameterClause.parameters.first?.firstName.text == "to"
1418+
}) {
1419+
context.diagnose(
1420+
Diagnostic(
1421+
node: customEncode.decl,
1422+
message: MacroExpansionErrorMessage(
1423+
"""
1424+
'@\(attributeName)' derives its 'Encodable' conformance from its columns and \
1425+
cannot define a custom 'encode(to:)'
1426+
"""
1427+
),
1428+
fixIt: .replace(
1429+
message: MacroExpansionFixItMessage("Remove 'encode(to:)'"),
1430+
oldNode: customEncode,
1431+
newNode: TokenSyntax("")
1432+
)
1433+
)
1434+
)
1435+
} else if customCodingKeys == nil {
1436+
let encodeCases: [DeclSyntax] = codableEnumCases.map { identifier, _, _ in
1437+
"""
1438+
case .\(identifier)(let value):
1439+
try container.encode(value, forKey: .\(identifier))
1440+
"""
13971441
}
1398-
"""
1399-
)
1442+
codableDecls.append(
1443+
"""
1444+
public \(nonisolated)func encode(to encoder: any Swift.Encoder) throws {
1445+
var container = encoder.container(keyedBy: CodingKeys.self)
1446+
switch self {
1447+
\(encodeCases, separator: "\n")
1448+
}
1449+
}
1450+
"""
1451+
)
1452+
}
14001453
}
14011454
}
14021455
}
@@ -1420,7 +1473,8 @@ extension TableMacro: MemberMacro {
14201473
public \(nonisolated)struct TableColumns: \(schemaConformances, separator: ", ") {
14211474
public typealias QueryValue = \(type.trimmed)\(primaryKeyTypealias)
14221475
\(columnsProperties, separator: "\n")
1423-
\(raw: optimizeNoneWorkaround)public static var allColumns: [any \(moduleName).TableColumnExpression] {
1476+
\(raw: optimizeNoneWorkaround)public static var allColumns: \
1477+
[any \(moduleName).TableColumnExpression] {
14241478
var allColumns: [any \(moduleName).TableColumnExpression] = []
14251479
\(raw: allColumnsAssignment)return allColumns
14261480
}
@@ -1563,7 +1617,9 @@ extension TableMacro: MemberAttributeMacro {
15631617
}
15641618
return [
15651619
"""
1566-
@Column("\(raw: identifier)"\(raw: identifier == "id" ? ", primaryKey: true" : lazyInitializableHint))
1620+
@Column(\
1621+
"\(raw: identifier)"\(raw: identifier == "id" ? ", primaryKey: true" : lazyInitializableHint)\
1622+
)
15671623
"""
15681624
] + checkAttribute
15691625
}

0 commit comments

Comments
 (0)