Skip to content

Commit ea2a49a

Browse files
committed
Add a vector of output columns to the generated SQLString
1 parent caa923a commit ea2a49a

File tree

7 files changed

+48
-14
lines changed

7 files changed

+48
-14
lines changed

docs/src/test/nodes.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3945,7 +3945,8 @@ On the next stage, the query object is converted to a SQL syntax tree.
39453945
│ ID(:visit_group_1) |> ID(:person_id)),
39463946
│ left = true) |>
39473947
│ SELECT(ID(:person_2) |> ID(:person_id),
3948-
│ ID(:visit_group_1) |> ID(:max) |> AS(:max_visit_start_date)))
3948+
│ ID(:visit_group_1) |> ID(:max) |> AS(:max_visit_start_date)),
3949+
│ columns = [SQLColumn(:person_id), SQLColumn(:max_visit_start_date)])
39493950
└ @ FunSQL …
39503951
=#
39513952

@@ -3980,6 +3981,7 @@ Finally, the SQL tree is serialized into SQL.
39803981
│ "visit_occurrence_1"."person_id"
39813982
│ FROM "visit_occurrence" AS "visit_occurrence_1"
39823983
│ GROUP BY "visit_occurrence_1"."person_id"
3983-
│ ) AS "visit_group_1" ON ("person_2"."person_id" = "visit_group_1"."person_id")""")
3984+
│ ) AS "visit_group_1" ON ("person_2"."person_id" = "visit_group_1"."person_id")""",
3985+
│ columns = [SQLColumn(:person_id), SQLColumn(:max_visit_start_date)])
39843986
└ @ FunSQL …
39853987
=#

docs/src/test/other.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,15 @@ A completely custom dialect can be specified.
343343
String(sql)
344344
#-> "SELECT * FROM person"
345345

346+
`SQLString` may carry a vector `columns` describing the output columns of
347+
the query.
348+
349+
sql = SQLString("SELECT person_id FROM person", columns = [SQLColumn(:person_id)])
350+
#-> SQLString("SELECT person_id FROM person", columns = […1 column…])
351+
352+
display(sql)
353+
#-> SQLString("SELECT person_id FROM person", columns = [SQLColumn(:person_id)])
354+
346355
When the query has parameters, `SQLString` should include a vector of
347356
parameter names in the order they should appear in `DBInterface.execute` call.
348357

src/FunSQL.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ end
9696

9797
include("dissect.jl")
9898
include("quote.jl")
99-
include("strings.jl")
10099
include("dialects.jl")
101100
include("types.jl")
102101
include("catalogs.jl")
102+
include("strings.jl")
103103
include("clauses.jl")
104104
include("nodes.jl")
105105
include("connections.jl")

src/clauses/internal.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
mutable struct WithContextClause <: AbstractSQLClause
66
over::SQLClause
77
dialect::SQLDialect
8+
columns::Union{Vector{SQLColumn}, Nothing}
89

9-
WithContextClause(; over, dialect) =
10-
new(over, dialect)
10+
WithContextClause(; over, dialect, columns = nothing) =
11+
new(over, dialect, columns)
1112
end
1213

1314
WITH_CONTEXT(args...; kws...) =
@@ -21,5 +22,8 @@ function PrettyPrinting.quoteof(c::WithContextClause, ctx::QuoteContext)
2122
if c.dialect !== default_dialect
2223
push!(ex.args, Expr(:kw, :dialect, quoteof(c.dialect)))
2324
end
25+
if c.columns !== nothing
26+
push!(ex.args, Expr(:kw, :columns, Expr(:vect, Any[quoteof(col) for col in c.columns]...)))
27+
end
2428
ex
2529
end

src/serialize.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ mutable struct SerializeContext <: IO
1212
end
1313

1414
function serialize(c::SQLClause)
15-
@dissect(c, WITH_CONTEXT(over = c′, dialect = dialect)) || throw(IllFormedError())
15+
@dissect(c, WITH_CONTEXT(over = c′, dialect = dialect, columns = columns)) || throw(IllFormedError())
1616
ctx = SerializeContext(dialect)
1717
serialize!(c′, ctx)
1818
raw = String(take!(ctx.io))
19-
SQLString(raw, vars = ctx.vars)
19+
SQLString(raw, columns = columns, vars = ctx.vars)
2020
end
2121

2222
Base.write(ctx::SerializeContext, octet::UInt8) =

src/strings.jl

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# Serialized SQL query with parameter mapping.
22

33
"""
4-
SQLString(raw, vars = Symbol[])
4+
SQLString(raw; columns = nothing, vars = Symbol[])
55
66
Serialized SQL query.
77
8+
Parameter `columns` is a vector describing the output columns.
9+
810
Parameter `vars` is a vector of query parameters (created with [`Var`](@ref))
911
in the order they are expected by the `DBInterface.execute()` function.
1012
@@ -20,7 +22,8 @@ SQLString(\"""
2022
SELECT
2123
"person_1"."person_id",
2224
"person_1"."year_of_birth"
23-
FROM "person" AS "person_1\\"\""")
25+
FROM "person" AS "person_1\\"\""",
26+
columns = [SQLColumn(:person_id), SQLColumn(:year_of_birth)])
2427
2528
julia> q = From(person) |> Where(Fun.and(Get.year_of_birth .>= Var.YEAR,
2629
Get.year_of_birth .< Var.YEAR .+ 10));
@@ -34,6 +37,7 @@ SQLString(\"""
3437
WHERE
3538
(`person_1`.`year_of_birth` >= ?) AND
3639
(`person_1`.`year_of_birth` < (? + 10))\""",
40+
columns = [SQLColumn(:person_id), SQLColumn(:year_of_birth)],
3741
vars = [:YEAR, :YEAR])
3842
3943
julia> render(q, dialect = :postgresql)
@@ -45,15 +49,17 @@ SQLString(\"""
4549
WHERE
4650
("person_1"."year_of_birth" >= \$1) AND
4751
("person_1"."year_of_birth" < (\$1 + 10))\""",
52+
columns = [SQLColumn(:person_id), SQLColumn(:year_of_birth)],
4853
vars = [:YEAR])
4954
```
5055
"""
5156
struct SQLString <: AbstractString
5257
raw::String
58+
columns::Union{Vector{SQLColumn}, Nothing}
5359
vars::Vector{Symbol}
5460

55-
SQLString(raw; vars = Symbol[]) =
56-
new(raw, vars)
61+
SQLString(raw; columns = nothing, vars = Symbol[]) =
62+
new(raw, columns, vars)
5763
end
5864

5965
Base.ncodeunits(sql::SQLString) =
@@ -82,6 +88,9 @@ Base.write(io::IO, sql::SQLString) =
8288

8389
function PrettyPrinting.quoteof(sql::SQLString)
8490
ex = Expr(:call, nameof(SQLString), sql.raw)
91+
if sql.columns !== nothing
92+
push!(ex.args, Expr(:kw, :columns, Expr(:vect, Any[quoteof(col) for col in sql.columns]...)))
93+
end
8594
if !isempty(sql.vars)
8695
push!(ex.args, Expr(:kw, :vars, quoteof(sql.vars)))
8796
end
@@ -91,6 +100,11 @@ end
91100
function Base.show(io::IO, sql::SQLString)
92101
print(io, "SQLString(")
93102
show(io, sql.raw)
103+
if sql.columns !== nothing
104+
print(io, ", columns = ")
105+
l = length(sql.columns)
106+
print(io, l == 0 ? "[]" : l == 1 ? "[…1 column…]" : "[…$l columns…]")
107+
end
94108
if !isempty(sql.vars)
95109
print(io, ", vars = ")
96110
show(io, sql.vars)

src/translate.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,14 @@ function allocate_alias(ctx::TranslateContext, alias::Symbol)
184184
end
185185

186186
function translate(n::SQLNode)
187-
@dissect(n, WithContext(over = n′, catalog = catalog, defs = defs)) || throw(IllFormedError())
187+
@dissect(n, WithContext(over = Linked(over = n′, refs = refs), catalog = catalog, defs = defs)) || throw(IllFormedError())
188188
ctx = TranslateContext(catalog = catalog, defs = defs)
189-
c = translate(n′, ctx)
189+
base = assemble(n′, TranslateContext(ctx, refs = refs))
190+
columns = nothing
191+
if !isempty(base.cols)
192+
columns = [SQLColumn(col) for col in keys(base.cols)]
193+
end
194+
c = complete(base)
190195
with_args = SQLClause[]
191196
for cte_a in ctx.ctes
192197
!cte_a.external || continue
@@ -205,7 +210,7 @@ function translate(n::SQLNode)
205210
if !isempty(with_args)
206211
c = WITH(over = c, args = with_args, recursive = ctx.recursive[])
207212
end
208-
WITH_CONTEXT(over = c, dialect = ctx.catalog.dialect)
213+
WITH_CONTEXT(over = c, dialect = ctx.catalog.dialect, columns = columns)
209214
end
210215

211216
function translate(n::SQLNode, ctx)

0 commit comments

Comments
 (0)