Skip to content

Commit 37cc23d

Browse files
committed
back to variables
1 parent cae697b commit 37cc23d

7 files changed

Lines changed: 152 additions & 197 deletions

File tree

Sources/Compiler/Gen/Generator.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ extension Language2 {
8888
}.joined()
8989

9090
return GeneratedQuery(
91-
name: "\(name.capitalizedFirst)Query",
91+
name: "\(name)Query",
9292
type: type,
9393
input: input,
9494
output: output,
@@ -127,7 +127,7 @@ extension Language2 {
127127
)
128128
}
129129

130-
let inputTypeName = "Input"
130+
let inputTypeName = "\(name.capitalizedFirst)Input"
131131

132132
let model = GeneratedModel(
133133
name: inputTypeName,
@@ -164,7 +164,7 @@ extension Language2 {
164164
return .builtin(builtinType(for: firstColumn), isArray: firstColumn.isRow)
165165
}
166166

167-
let outputTypeName = "Row"
167+
let outputTypeName = "\(name.capitalizedFirst)Output"
168168

169169
let model = GeneratedModel(
170170
name: outputTypeName,

Sources/Compiler/Gen/SwiftLanguage.swift

Lines changed: 79 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ public struct SwiftLanguage: Language2 {
4848
try declaration(for: migrations, options: options)
4949

5050
for query in queries {
51+
if case let .model(model) = query.input, !model.isTable {
52+
try declaration(for: model, isOutput: false, options: options)
53+
}
54+
55+
if case let .model(model) = query.output, !model.isTable {
56+
try declaration(for: model, isOutput: true, options: options)
57+
}
58+
5159
try declaration(for: query, options: options)
5260
}
5361
}
@@ -91,88 +99,68 @@ public struct SwiftLanguage: Language2 {
9199
for query: GeneratedQuery,
92100
options: GenerationOptions
93101
) throws -> DeclSyntax {
94-
let query = try StructDeclSyntax(
95-
name: TokenSyntax.identifier(query.name),
96-
inheritanceClause: InheritanceClauseSyntax {
97-
InheritedTypeSyntax(type: TypeSyntax("DatabaseQuery"))
98-
}
99-
) {
100-
switch query.input {
101-
case .model(let model) where !model.isTable:
102-
try declaration(for: model, isOutput: false, options: options)
103-
case .some(let type):
104-
try typealiasDecl(named: "Input", for: type)
105-
case nil:
106-
try TypeAliasDeclSyntax("typealias Input = ()")
107-
}
108-
109-
switch query.output {
110-
case .model(let model) where !model.isTable:
111-
try declaration(for: model, isOutput: true, options: options)
112-
try outputTypeAlias(cardinality: query.outputCardinality)
113-
case .some(let type):
114-
try typealiasDecl(named: "Row", for: type)
115-
try outputTypeAlias(cardinality: query.outputCardinality)
116-
case nil:
117-
try TypeAliasDeclSyntax("typealias Row = ()")
118-
try TypeAliasDeclSyntax("typealias Output = ()")
119-
}
120-
121-
try VariableDeclSyntax("var transactionKind: Feather.TransactionKind") {
122-
query.isReadOnly ? ".read" : ".write"
123-
}
124-
125-
FunctionDeclSyntax(
126-
name: "execute",
127-
signature: FunctionSignatureSyntax(
128-
parameterClause: FunctionParameterClauseSyntax(
129-
parameters: [
130-
FunctionParameterSyntax(
131-
firstName: "with",
132-
secondName: "input",
133-
type: IdentifierTypeSyntax(name: "Input"),
134-
trailingComma: TokenSyntax.commaToken()
135-
),
136-
FunctionParameterSyntax(
137-
firstName: "tx",
138-
type: IdentifierTypeSyntax(name: "borrowing Feather.Transaction")
139-
)
140-
]
141-
),
142-
effectSpecifiers: FunctionEffectSpecifiersSyntax(
143-
throwsClause: ThrowsClauseSyntax(
144-
throwsSpecifier: TokenSyntax.keyword(.throws)
145-
)
146-
),
147-
returnClause: ReturnClauseSyntax(type: IdentifierTypeSyntax(name: "Output"))
148-
)
149-
) {
150-
let sql = stringLiteral(of: query.sourceSql, multiline: true)
151-
let statementBinding: TokenSyntax = .keyword(query.input == nil ? .let : .var)
152-
"\(statementBinding) statement = try Feather.Statement(\(sql), \ntransaction: tx\n)"
102+
let inputTypeName = inputTypeName(for: query)
103+
let outputTypeName = outputTypeName(for: query)
104+
let queryTypeName = "DatabaseQuery<\(inputTypeName), \(outputTypeName)>"
105+
106+
let query = try VariableDeclSyntax("var \(raw: query.name): \(raw: queryTypeName)") {
107+
FunctionCallExprSyntax(
108+
calledExpression: DeclReferenceExprSyntax(
109+
baseName: .identifier("DatabaseQueryImpl<\(inputTypeName), \(outputTypeName)>")
110+
),
111+
leftParen: .leftParenToken(),
112+
arguments: LabeledExprListSyntax {
113+
LabeledExprSyntax(
114+
label: nil,
115+
colon: nil,
116+
expression: DeclReferenceExprSyntax(
117+
baseName: query.isReadOnly ? ".read" : ".write"
118+
),
119+
trailingComma: TokenSyntax.commaToken()
120+
)
121+
LabeledExprSyntax(
122+
label: TokenSyntax.identifier("database"),
123+
colon: TokenSyntax.colonToken(),
124+
expression: DeclReferenceExprSyntax(baseName: .identifier("database")),
125+
trailingComma: nil
126+
)
127+
},
128+
rightParen: .rightParenToken(),
129+
trailingClosure: ClosureExprSyntax(
130+
signature: ClosureSignatureSyntax(
131+
parameterClause: .simpleInput(.init {
132+
ClosureShorthandParameterSyntax(name: "input")
133+
ClosureShorthandParameterSyntax(name: "transaction")
134+
})
135+
)
136+
) {
137+
let sql = stringLiteral(of: query.sourceSql, multiline: true)
138+
let statementBinding: TokenSyntax = .keyword(query.input == nil ? .let : .var)
139+
"\(statementBinding) statement = try Feather.Statement(\(sql), \ntransaction: tx\n)"
153140

154-
if let input = query.input {
155-
switch input {
156-
case let .builtin(_, isArray):
157-
bind(field: nil, isArray: isArray)
158-
case .model(let model):
159-
for field in model.fields.values {
160-
bind(field: field.name, isArray: field.isArray)
141+
if let input = query.input {
142+
switch input {
143+
case let .builtin(_, isArray):
144+
bind(field: nil, isArray: isArray)
145+
case .model(let model):
146+
for field in model.fields.values {
147+
bind(field: field.name, isArray: field.isArray)
148+
}
161149
}
162150
}
163-
}
164151

165-
if query.output == nil {
166-
"_ = try statement.step()"
167-
} else {
168-
switch query.outputCardinality {
169-
case .single:
170-
"return try statement.fetchOne(of: Row.self)"
171-
case .many:
172-
"return try statement.fetchMany(of: Row.self)"
152+
if query.output == nil {
153+
"_ = try statement.step()"
154+
} else {
155+
switch query.outputCardinality {
156+
case .single:
157+
"return try statement.fetchOne(of: Row.self)"
158+
case .many:
159+
"return try statement.fetchMany(of: Row.self)"
160+
}
173161
}
174162
}
175-
}
163+
)
176164
}
177165

178166
return DeclSyntax(query)
@@ -187,6 +175,21 @@ public struct SwiftLanguage: Language2 {
187175
}
188176
}
189177

178+
private static func inputTypeName(for query: GeneratedQuery) -> String {
179+
return query.input?.description ?? "()"
180+
}
181+
182+
private static func outputTypeName(for query: GeneratedQuery) -> String {
183+
if let output = query.output {
184+
switch query.outputCardinality {
185+
case .single: "\(output)?"
186+
case .many: "[\(output)]"
187+
}
188+
} else {
189+
"()"
190+
}
191+
}
192+
190193
private static func declaration(
191194
for model: GeneratedModel,
192195
isOutput: Bool,

Sources/Feather/Migration.swift

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ public struct MigrationRunner {
1717
public static func execute(migrations: [String], tx: borrowing Transaction) throws {
1818
try createTableIfNeeded(tx: tx)
1919

20-
let lastMigration = try LastMigrationQuery()
21-
.replaceNil(with: 0)
22-
.execute(with: (), tx: tx)
20+
let lastMigration = try lastMigration(tx: tx)
2321

2422
let pendingMigrations = migrations.enumerated()
2523
.map { (number: $0.offset + 1, migration: $0.element) }
@@ -41,36 +39,24 @@ public struct MigrationRunner {
4139

4240
static func execute(migration: String, number: Int, tx: borrowing Transaction) throws {
4341
try tx.execute(sql: migration)
44-
try InsertMigrationQuery().execute(with: number, tx: tx)
42+
try insertMigration(version: number, tx: tx)
4543
}
46-
47-
struct LastMigrationQuery: DatabaseQuery {
48-
var transactionKind: TransactionKind { .read }
49-
func execute(
50-
with _: (),
51-
tx: borrowing Transaction
52-
) throws -> Int? {
53-
let statement = try Statement(in: tx) {
54-
"SELECT MAX(number) FROM \(MigrationRunner.migrationTableName)"
55-
}
56-
57-
return try statement.fetchOne(of: Int.self)
44+
45+
private static func lastMigration(tx: borrowing Transaction) throws -> Int {
46+
let statement = try Statement(in: tx) {
47+
"SELECT MAX(number) FROM \(MigrationRunner.migrationTableName)"
5848
}
49+
50+
return try statement.fetchOne(of: Int.self) ?? 0
5951
}
6052

61-
struct InsertMigrationQuery: DatabaseQuery {
62-
var transactionKind: TransactionKind { .write }
63-
func execute(
64-
with input: Int,
65-
tx: borrowing Transaction
66-
) throws {
67-
let statement = try Statement(in: tx) {
68-
"INSERT INTO \(MigrationRunner.migrationTableName) (number) VALUES (?)"
69-
} bind: { statement in
70-
try statement.bind(value: input, to: 1)
71-
}
72-
73-
_ = try statement.step()
53+
private static func insertMigration(version: Int, tx: borrowing Transaction) throws {
54+
let statement = try Statement(in: tx) {
55+
"INSERT INTO \(MigrationRunner.migrationTableName) (number) VALUES (?)"
56+
} bind: { statement in
57+
try statement.bind(value: version, to: 1)
7458
}
59+
60+
_ = try statement.step()
7561
}
7662
}

Sources/Feather/Queries.swift

Lines changed: 10 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,23 @@
66
//
77

88
public enum Queries {
9-
/// Replaces the `Database` associated type with the input
10-
/// resulting in a query with a `Void` database.
11-
/// Allows for the erasing of the database so a query can be
12-
/// passed around and be able to be executed without
13-
/// having the caller worry about by what.
14-
public struct WithDatabase<Base: DatabaseQuery>: Query {
15-
/// The original query that requires a database
16-
let base: Base
17-
/// The database to execute the query in
18-
let database: any Database
19-
20-
public func execute(
21-
with input: Base.Input
22-
) async throws -> Base.Output {
23-
return try await base.execute(with: input, in: database)
24-
}
25-
26-
public func observe(with input: Input) -> any QueryObservation<Output> {
27-
return base.observe(with: input, in: database)
28-
}
29-
}
30-
319
/// Applies a transform to the queries result
3210
public struct Map<Base: DatabaseQuery, Output: Sendable>: DatabaseQuery {
11+
public typealias Input = Base.Input
12+
public typealias Output = Output
3313
/// The upstream query to transform
3414
let base: Base
3515
/// The transform to apply to the output
3616
let transform: @Sendable (Base.Output) throws -> Output
17+
/// The database to execute the query on
18+
public var database: any Database {
19+
return base.database
20+
}
3721

3822
public var transactionKind: TransactionKind {
3923
return base.transactionKind
4024
}
4125

42-
public func execute(
43-
with input: Base.Input,
44-
in database: any Database
45-
) async throws -> Output {
46-
return try await transform(base.execute(with: input, in: database))
47-
}
48-
4926
public func execute(
5027
with input: Base.Input,
5128
tx: borrowing Transaction
@@ -94,12 +71,15 @@ public enum Queries {
9471
where First: DatabaseQuery, Second: DatabaseQuery
9572
{
9673
public typealias Input = First.Input
74+
public typealias Output = (First.Output, Second.Output)
9775

9876
let first: First
9977
let second: Second
10078
let secondInput: @Sendable (First.Input, First.Output) -> Second.Input
10179

102-
public typealias DB = any Database
80+
public var database: any Database {
81+
return first.database
82+
}
10383

10484
public var transactionKind: TransactionKind {
10585
return max(first.transactionKind, second.transactionKind)
@@ -115,26 +95,9 @@ public enum Queries {
11595
return (firstOutput, secondOutput)
11696
}
11797
}
118-
119-
public struct None<Input: Sendable>: DatabaseQuery {
120-
public init() {}
121-
122-
public var transactionKind: TransactionKind {
123-
return .read
124-
}
125-
126-
public func execute(
127-
with input: Input,
128-
tx: borrowing Transaction
129-
) throws {}
130-
}
13198
}
13299

133100
public extension DatabaseQuery {
134-
func with(database: any Database) -> Queries.WithDatabase<Self> {
135-
return Queries.WithDatabase(base: self, database: database)
136-
}
137-
138101
func map<NewOutput>(
139102
_ transform: @Sendable @escaping (Output) throws -> NewOutput
140103
) -> Queries.Map<Self, NewOutput> {

Sources/Feather/Query.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
// Created by Wes Wickwire on 3/29/25.
66
//
77

8-
public protocol Query<Input, Output> {
9-
associatedtype Input
10-
associatedtype Output
8+
public protocol Query<Input, Output>: Sendable {
9+
associatedtype Input: Sendable
10+
associatedtype Output: Sendable
1111

1212
func execute(with input: Input) async throws -> Output
1313

0 commit comments

Comments
 (0)