Skip to content

Commit 84c120a

Browse files
committed
Allow for custom input and output names
1 parent 026c094 commit 84c120a

6 files changed

Lines changed: 86 additions & 14 deletions

File tree

Sources/Compiler/Compiler.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ fileprivate struct CompilerWithSource {
113113
self.schema = typeChecker.schema
114114

115115
let statement = Statement(
116-
name: nil,
116+
definition: nil,
117117
parameters: uniqueParameters,
118118
resultColumns: type,
119119
outputCardinality: cardinality,
@@ -190,7 +190,14 @@ extension CompilerWithSource: StmtSyntaxVisitor {
190190

191191
mutating func visit(_ stmt: QueryDefinitionStmtSyntax) -> (Statement, Diagnostics)? {
192192
guard let (innerStmt, diagnostics) = stmt.statement.accept(visitor: &self) else { return nil }
193-
return (innerStmt.with(name: stmt.name.value), diagnostics)
193+
194+
let definition = Definition(
195+
name: stmt.name.value,
196+
input: stmt.input?.value,
197+
output: stmt.output?.value
198+
)
199+
200+
return (innerStmt.with(definition: definition), diagnostics)
194201
}
195202

196203
mutating func visit(_ stmt: PragmaStmt) -> (Statement, Diagnostics)? {

Sources/Compiler/Gen/Language.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ extension Language {
6464
for statement: Statement,
6565
tables: OrderedDictionary<Substring, GeneratedModel>
6666
) -> GeneratedQuery {
67-
guard let name = statement.name else {
67+
guard let definition = statement.definition else {
6868
fatalError("Upstream error should have caught this")
6969
}
7070

71-
let input = inputTypeIfNeeded(statement: statement, name: name)
72-
let output = outputTypeIfNeeded(statement: statement, name: name, tables: tables)
71+
let input = inputTypeIfNeeded(statement: statement, definition: definition)
72+
let output = outputTypeIfNeeded(statement: statement, definition: definition, tables: tables)
7373

7474
let type = queryType(
7575
for: statement.noOutput ? nil : statement.outputCardinality,
@@ -91,7 +91,7 @@ extension Language {
9191
}.joined()
9292

9393
return GeneratedQuery(
94-
name: "\(name)Query",
94+
name: "\(definition.name)Query",
9595
type: type,
9696
input: input,
9797
output: output,
@@ -119,7 +119,7 @@ extension Language {
119119

120120
private static func inputTypeIfNeeded(
121121
statement: Statement,
122-
name: Substring
122+
definition: Definition
123123
) -> BuiltinOrGenerated? {
124124
guard let firstParameter = statement.parameters.first else { return nil }
125125

@@ -130,7 +130,7 @@ extension Language {
130130
)
131131
}
132132

133-
let inputTypeName = "\(name.capitalizedFirst)Input"
133+
let inputTypeName = definition.input?.description ?? "\(definition.name.capitalizedFirst)Input"
134134

135135
let model = GeneratedModel(
136136
name: inputTypeName,
@@ -149,7 +149,7 @@ extension Language {
149149

150150
private static func outputTypeIfNeeded(
151151
statement: Statement,
152-
name: Substring,
152+
definition: Definition,
153153
tables: OrderedDictionary<Substring, GeneratedModel>
154154
) -> BuiltinOrGenerated? {
155155
guard let firstResultColumns = statement.resultColumns.chunks.first else { return nil }
@@ -171,7 +171,7 @@ extension Language {
171171
return .builtin(builtinType(for: firstColumn), isArray: firstColumn.isRow)
172172
}
173173

174-
let outputTypeName = "\(name.capitalizedFirst)Output"
174+
let outputTypeName = definition.output?.description ?? "\(definition.name.capitalizedFirst)Output"
175175

176176
let model = GeneratedModel(
177177
name: outputTypeName,

Sources/Compiler/Parse/Parsers.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,11 +2070,28 @@ enum Parsers {
20702070
let define = state.take(.define)
20712071
state.skip(.query)
20722072
let name = identifier(state: &state)
2073+
2074+
let params: [Substring: IdentifierSyntax]? = take(if: .openParen, state: &state) { state in
2075+
parens(state: &state) { state in
2076+
delimited(by: .comma, state: &state, reduceInto: [:]) { params, param in
2077+
params[param.name.value] = param.value
2078+
} element: { state in
2079+
let name = identifier(state: &state)
2080+
state.skip(.colon)
2081+
let value = identifier(state: &state)
2082+
return (name: name, value: value)
2083+
}
2084+
}
2085+
}
2086+
20732087
state.skip(.as)
20742088
let stmt = try stmt(state: &state)
2089+
20752090
return QueryDefinitionStmtSyntax(
20762091
id: state.nextId(),
20772092
name: name,
2093+
input: params?["input"],
2094+
output: params?["output"],
20782095
statement: stmt,
20792096
location: define.location.spanning(state.current.location)
20802097
)
@@ -2143,6 +2160,22 @@ enum Parsers {
21432160
return elements
21442161
}
21452162

2163+
static func delimited<Element, Output>(
2164+
by kind: Token.Kind,
2165+
state: inout ParserState,
2166+
reduceInto elements: Output,
2167+
reduce: (inout Output, Element) -> Void,
2168+
element: (inout ParserState) throws -> Element
2169+
) rethrows -> Output {
2170+
var elements = elements
2171+
2172+
repeat {
2173+
try reduce(&elements, element(&state))
2174+
} while state.take(if: kind)
2175+
2176+
return elements
2177+
}
2178+
21462179
static func parens<Value>(
21472180
state: inout ParserState,
21482181
value: (inout ParserState) throws -> Value

Sources/Compiler/Sema/Statement.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
//
77

88
public struct Statement {
9-
public let name: Substring?
9+
/// The information in the `DEFINE` statement if it exists
10+
public let definition: Definition?
1011
/// Any bind parameters for the statement
1112
public let parameters: [Parameter<String>]
1213
/// The return type if any.
@@ -29,10 +30,15 @@ public struct Statement {
2930
return resultColumns.isEmpty
3031
}
3132

32-
/// Replaces the name with the given input
33-
public func with(name: Substring?) -> Statement {
33+
/// The name if one was defined
34+
public var name: Substring? {
35+
return definition?.name
36+
}
37+
38+
/// Replaces the definition with the given input
39+
public func with(definition: Definition?) -> Statement {
3440
return Statement(
35-
name: name,
41+
definition: definition,
3642
parameters: parameters,
3743
resultColumns: resultColumns,
3844
outputCardinality: outputCardinality,
@@ -65,6 +71,13 @@ public struct Parameter<Name> {
6571
}
6672
}
6773

74+
/// The values from a `DEFINE QUERY` statement
75+
public struct Definition {
76+
public let name: Substring
77+
public let input: Substring?
78+
public let output: Substring?
79+
}
80+
6881
/// The output of a statement
6982
public struct ResultColumns: Sendable {
7083
public let chunks: [Chunk]

Sources/Compiler/Syntax/StmtSyntax.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ struct InsertStmtSyntax: StmtSyntax, Syntax {
115115
struct QueryDefinitionStmtSyntax: StmtSyntax {
116116
let id: SyntaxId
117117
let name: IdentifierSyntax
118+
let input: IdentifierSyntax?
119+
let output: IdentifierSyntax?
118120
let statement: any StmtSyntax
119121
let location: SourceLocation
120122

Tests/CompilerTests/Parser/ParseDefinition.sql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,20 @@ SELECT * FROM user WHERE id = ?;
1212
-- CHECK: ...
1313
DEFINE QUERY insertUser AS
1414
INSERT INTO user (id, name) VALUES (1, 'Joe');
15+
16+
-- CHECK: QUERY_DEFINITION_STMT_SYNTAX
17+
-- CHECK: NAME fetchUser
18+
-- CHECK: OUTPUT FetchedUser
19+
-- CHECK: STATEMENT
20+
-- CHECK: ...
21+
DEFINE QUERY fetchUser(output: FetchedUser) AS
22+
SELECT * FROM user WHERE id = ?;
23+
24+
-- CHECK: QUERY_DEFINITION_STMT_SYNTAX
25+
-- CHECK: NAME fetchUser
26+
-- CHECK: INPUT TheBestInput
27+
-- CHECK: OUTPUT FetchedUser
28+
-- CHECK: STATEMENT
29+
-- CHECK: ...
30+
DEFINE QUERY fetchUser(input: TheBestInput, output: FetchedUser) AS
31+
SELECT * FROM user WHERE id = ?;

0 commit comments

Comments
 (0)