@@ -5,6 +5,9 @@ import SwiftSyntaxMacros
55import Utility
66
77public struct PreparedStatementsPostgresNIOMacro : ExtensionMacro , MemberMacro {
8+ private typealias Column = ( name: String , type: TokenSyntax , alias: String ? )
9+ private typealias Bind = ( name: String , type: TokenSyntax )
10+
811 public static func expansion(
912 of node: AttributeSyntax ,
1013 attachedTo declaration: some DeclGroupSyntax ,
@@ -23,25 +26,26 @@ public struct PreparedStatementsPostgresNIOMacro: ExtensionMacro, MemberMacro {
2326 }
2427
2528 public static func expansion( of node: AttributeSyntax , providingMembersOf declaration: some DeclGroupSyntax , in context: some MacroExpansionContext ) throws -> [ DeclSyntax ] {
26- guard let elements = node. arguments? . as ( LabeledExprListSyntax . self) ?
27- . first? . expression. as ( StringLiteralExprSyntax . self) ? . segments else {
28- // TODO: Be more specific about this error
29- // context.diagnose(Diagnostic(node: Syntax(node), message: PostgresNIODiagnostic.wrongArgument))
30- return [ ]
31- }
29+ // It is fine to force unwrap here, because the compiler ensures we receive this exact syntax tree here.
30+ let elements = node
31+ . arguments!. as ( LabeledExprListSyntax . self) !
32+ . first!. expression. as ( StringLiteralExprSyntax . self) !. segments
3233
3334 var sql = " "
34- var columns : [ ( String , TokenSyntax ) ] = [ ]
35- var binds : [ ( String , TokenSyntax ) ] = [ ]
35+ var columns : [ Column ] = [ ]
36+ var binds : [ Bind ] = [ ]
3637 for element in elements {
3738 if let expression = element. as ( ExpressionSegmentSyntax . self) {
3839 let interpolation = extractInterpolations ( expression)
3940 switch interpolation {
40- case . column( let name, let type) :
41- columns. append ( ( name, type) )
42- sql. append ( name)
43- case . bind( let name, let type) :
44- binds. append ( ( name, type) )
41+ case . column( let column) :
42+ columns. append ( column)
43+ sql. append ( column. name)
44+ if let alias = column. alias {
45+ sql. append ( " AS \( alias) " )
46+ }
47+ case . bind( let bind) :
48+ binds. append ( bind)
4549 sql. append ( " $ \( binds. count) " )
4650 }
4751 } else if let expression = element. as ( StringSegmentSyntax . self) {
@@ -53,14 +57,14 @@ public struct PreparedStatementsPostgresNIOMacro: ExtensionMacro, MemberMacro {
5357 structKeyword: . keyword( . struct, trailingTrivia: . space) ,
5458 name: . identifier( " Row " , trailingTrivia: . space) ,
5559 memberBlockBuilder: {
56- for (name, type) in columns {
60+ for (name, type, alias ) in columns {
5761 MemberBlockItemSyntax (
5862 decl: VariableDeclSyntax (
5963 bindingSpecifier: . keyword( . let, trailingTrivia: . space) ,
6064 bindings: PatternBindingListSyntax (
6165 itemsBuilder: {
6266 PatternBindingSyntax (
63- pattern: IdentifierPatternSyntax ( identifier: . identifier( name) ) ,
67+ pattern: IdentifierPatternSyntax ( identifier: . identifier( alias ?? name) ) ,
6468 typeAnnotation: TypeAnnotationSyntax ( type: IdentifierTypeSyntax ( name: type) )
6569 )
6670 }
@@ -108,42 +112,35 @@ public struct PreparedStatementsPostgresNIOMacro: ExtensionMacro, MemberMacro {
108112 ]
109113 }
110114
111- enum Interpolation {
112- case column( String , TokenSyntax )
113- case bind( String , TokenSyntax )
115+ private enum Interpolation {
116+ case column( Column )
117+ case bind( Bind )
114118 }
115119 private static func extractInterpolations( _ node: ExpressionSegmentSyntax ) -> Interpolation {
116120 let tupleElements = node. expressions
117- guard tupleElements. count == 2 else {
118- fatalError ( " Expected tuple with exactly two elements " )
119- }
121+ precondition ( tupleElements. count >= 2 , " Expected tuple with two or more elements, less are impossible as the compiler already checks for it " )
120122
121123 // First element needs to be the column name
122124 var iterator = tupleElements. makeIterator ( )
123- let identifier = iterator. next ( ) ! as LabeledExprSyntax // works as tuple contains exactly two elements
124- guard let type = iterator. next ( ) !. expression. as ( MemberAccessExprSyntax . self) ? . base? . as ( DeclReferenceExprSyntax . self) else {
125- fatalError ( " expected something " )
126- }
125+ let identifier = iterator. next ( ) ! as LabeledExprSyntax // works as tuple contains at least two elements
126+ // Type can be force-unwrapped as the compiler ensures it is there.
127+ let type = iterator. next ( ) !. expression. as ( MemberAccessExprSyntax . self) !
128+ . base!. as ( DeclReferenceExprSyntax . self) !
129+ // Same thing as with type.
130+ let name = identifier. expression. as ( StringLiteralExprSyntax . self) !
131+ . segments. first!. as ( StringSegmentSyntax . self) !. content. text
127132 switch identifier. label? . identifier? . name {
128133 case " bind " :
129- guard let columnName = identifier. expression. as ( StringLiteralExprSyntax . self) ?
130- . segments. first? . as ( StringSegmentSyntax . self) ? . content
131- . text else {
132- fatalError ( " Expected column name " )
133- }
134- return . bind( columnName, type. baseName)
134+ return . bind( ( name: name, type: type. baseName) )
135135 default :
136- guard let columnName = identifier. expression. as ( StringLiteralExprSyntax . self) ?
137- . segments. first? . as ( StringSegmentSyntax . self) ? . content
138- . text else {
139- fatalError ( " Expected column name " )
140- }
136+ let alias = iterator. next ( ) ? . expression. as ( StringLiteralExprSyntax . self) ?
137+ . segments. first? . as ( StringSegmentSyntax . self) ? . content. text
141138
142- return . column( columnName , type. baseName)
139+ return . column( ( name : name , type: type . baseName, alias : alias ) )
143140 }
144141 }
145142
146- private static func makeBindings( for binds: [ ( String , TokenSyntax ) ] ) -> FunctionDeclSyntax {
143+ private static func makeBindings( for binds: [ Bind ] ) -> FunctionDeclSyntax {
147144 FunctionDeclSyntax (
148145 name: . identifier( " makeBindings " ) ,
149146 signature: FunctionSignatureSyntax (
@@ -218,7 +215,7 @@ public struct PreparedStatementsPostgresNIOMacro: ExtensionMacro, MemberMacro {
218215 )
219216 }
220217
221- private static func decodeRow( from columns: [ ( String , TokenSyntax ) ] ) -> FunctionDeclSyntax {
218+ private static func decodeRow( from columns: [ Column ] ) -> FunctionDeclSyntax {
222219 FunctionDeclSyntax (
223220 name: . identifier( " decodeRow " ) ,
224221 signature: FunctionSignatureSyntax (
@@ -240,8 +237,8 @@ public struct PreparedStatementsPostgresNIOMacro: ExtensionMacro, MemberMacro {
240237 bindings: [
241238 PatternBindingSyntax (
242239 pattern: TuplePatternSyntax ( elementsBuilder: {
243- for (column, _) in columns {
244- TuplePatternElementSyntax ( pattern: IdentifierPatternSyntax ( identifier: . identifier( column) ) )
240+ for (column, _, alias ) in columns {
241+ TuplePatternElementSyntax ( pattern: IdentifierPatternSyntax ( identifier: . identifier( alias ?? column) ) )
245242 }
246243 } ) ,
247244 initializer: InitializerClauseSyntax (
@@ -256,7 +253,7 @@ public struct PreparedStatementsPostgresNIOMacro: ExtensionMacro, MemberMacro {
256253 argumentsBuilder: {
257254 LabeledExprSyntax ( expression: MemberAccessExprSyntax (
258255 base: TupleExprSyntax ( elementsBuilder: {
259- for (_, column) in columns {
256+ for (_, column, _ ) in columns {
260257 LabeledExprSyntax ( expression: DeclReferenceExprSyntax ( baseName: column) )
261258 }
262259 } ) ,
@@ -276,8 +273,11 @@ public struct PreparedStatementsPostgresNIOMacro: ExtensionMacro, MemberMacro {
276273 leftParen: . leftParenToken( ) ,
277274 rightParen: . rightParenToken( ) ,
278275 argumentsBuilder: {
279- for (column, _) in columns {
280- LabeledExprSyntax ( label: column, expression: DeclReferenceExprSyntax ( baseName: . identifier( column) ) )
276+ for (column, _, alias) in columns {
277+ LabeledExprSyntax (
278+ label: alias ?? column,
279+ expression: DeclReferenceExprSyntax ( baseName: . identifier( alias ?? column) )
280+ )
281281 }
282282 }
283283 ) ) ) ) )
0 commit comments