Skip to content

Commit 5309599

Browse files
committed
refactor: organize CASE expressions under Conditional namespace
Resolves namespace collision by separating domain (Conditional) from constructor (Case). Structure: - Conditional.swift: namespace enum + global Case() constructors - Conditional.Case.swift: main CASE expression builder - Conditional.Builder.swift: intermediate builder with accumulated WHEN clauses - Conditional.When.swift: WHEN...THEN clause helper Key insight: Namespaces should describe domains (Conditional), not constructors (Case). This allows Case() to function as an ergonomic global constructor without conflicts. API: - Case() - beautiful ergonomic syntax (no conflicts!) - Conditional.Case<Base, QueryValue> - properly namespaced type - Conditional.Builder, Conditional.When - semantic organization Follows Point-Free principle: namespace the domain, expose ergonomic constructors.
1 parent 671d825 commit 5309599

File tree

5 files changed

+168
-264
lines changed

5 files changed

+168
-264
lines changed

Sources/StructuredQueriesPostgres/Functions/Conditional/CaseExpression.swift

Lines changed: 0 additions & 154 deletions
This file was deleted.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import StructuredQueriesCore
2+
3+
extension Conditional {
4+
/// A `CASE` expression builder with accumulated WHEN clauses.
5+
public struct Builder<Base, QueryValue: _OptionalProtocol>: QueryExpression {
6+
var base: QueryFragment?
7+
var cases: [QueryFragment]
8+
9+
/// Adds a `WHEN` clause to a `CASE` expression.
10+
///
11+
/// - Parameters:
12+
/// - condition: A condition to test.
13+
/// - expression: A return value should the condition pass.
14+
/// - Returns: A `CASE` expression builder.
15+
public func when(
16+
_ condition: some QueryExpression<Base>,
17+
then expression: some QueryExpression<QueryValue>
18+
) -> Conditional.Builder<Base, QueryValue> {
19+
var cases = self
20+
cases.cases.append(
21+
Conditional.When(predicate: condition.queryFragment, expression: expression.queryFragment)
22+
.queryFragment
23+
)
24+
return cases
25+
}
26+
27+
/// Adds a `WHEN` clause to a `CASE` expression.
28+
///
29+
/// - Parameters:
30+
/// - condition: A condition to test.
31+
/// - expression: A return value should the condition pass.
32+
/// - Returns: A `CASE` expression builder.
33+
public func when(
34+
_ condition: some QueryExpression<Base>,
35+
then expression: some QueryExpression<QueryValue.Wrapped>
36+
) -> Conditional.Builder<Base, QueryValue> {
37+
var cases = self
38+
cases.cases.append(
39+
Conditional.When(predicate: condition.queryFragment, expression: expression.queryFragment)
40+
.queryFragment
41+
)
42+
return cases
43+
}
44+
45+
/// Terminates a `CASE` expression with an `ELSE` clause.
46+
///
47+
/// - Parameter expression: A return value should every `WHEN` condition fail.
48+
/// - Returns: A `CASE` expression.
49+
public func `else`(
50+
_ expression: some QueryExpression<QueryValue.Wrapped>
51+
) -> some QueryExpression<QueryValue.Wrapped> {
52+
var cases = self
53+
cases.cases.append("ELSE \(expression)")
54+
return SQLQueryExpression(cases.queryFragment)
55+
}
56+
57+
public var queryFragment: QueryFragment {
58+
var query: QueryFragment = "CASE"
59+
if let base {
60+
query.append(" \(base)")
61+
}
62+
query.append(" \(cases.joined(separator: " ")) END")
63+
return query
64+
}
65+
}
66+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import StructuredQueriesCore
2+
3+
extension Conditional {
4+
/// A type that builds SQL `CASE` expressions.
5+
///
6+
/// ```swift
7+
/// Case(5).when(condition1, then: result1)
8+
/// // Generates: CASE 5 WHEN condition1 THEN result1 END
9+
/// ```
10+
public struct Case<Base, QueryValue: _OptionalPromotable> {
11+
var base: QueryFragment?
12+
13+
/// Creates a SQL `CASE` expression builder.
14+
///
15+
/// - Parameter base: A "base" expression to test against for each `WHEN`.
16+
public init(
17+
_ base: some QueryExpression<Base>
18+
) {
19+
self.base = base.queryFragment
20+
}
21+
22+
/// Creates a SQL `CASE` expression builder.
23+
public init() where Base == Bool {}
24+
25+
/// Adds a `WHEN` clause to a `CASE` expression.
26+
///
27+
/// - Parameters:
28+
/// - condition: A condition to test.
29+
/// - expression: A return value should the condition pass.
30+
/// - Returns: A `CASE` expression builder.
31+
public func when(
32+
_ condition: some QueryExpression<Base>,
33+
then expression: some QueryExpression<QueryValue>
34+
) -> Conditional.Builder<Base, QueryValue?> {
35+
Conditional.Builder(
36+
base: base,
37+
cases: [
38+
Conditional.When(predicate: condition.queryFragment, expression: expression.queryFragment)
39+
.queryFragment
40+
]
41+
)
42+
}
43+
44+
/// Adds a `WHEN` clause to a `CASE` expression.
45+
///
46+
/// - Parameters:
47+
/// - condition: A condition to test.
48+
/// - expression: A return value should the condition pass.
49+
/// - Returns: A `CASE` expression builder.
50+
public func when(
51+
_ condition: some QueryExpression<Base>,
52+
then expression: some QueryExpression<QueryValue._Optionalized>
53+
) -> Conditional.Builder<Base, QueryValue._Optionalized> {
54+
Conditional.Builder(
55+
base: base,
56+
cases: [
57+
Conditional.When(predicate: condition.queryFragment, expression: expression.queryFragment)
58+
.queryFragment
59+
]
60+
)
61+
}
62+
}
63+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import StructuredQueriesCore
2+
3+
extension Conditional {
4+
/// A WHEN...THEN clause for CASE expressions.
5+
struct When: QueryExpression {
6+
typealias QueryValue = Never
7+
8+
let predicate: QueryFragment
9+
let expression: QueryFragment
10+
11+
public var queryFragment: QueryFragment {
12+
"WHEN \(predicate) THEN \(expression)"
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)