@@ -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