/
strings.jl
148 lines (112 loc) · 3.6 KB
/
strings.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Serialized SQL query with parameter mapping.
"""
SQLString(raw, vars = Symbol[])
Serialized SQL query.
Parameter `vars` is a vector of query parameters (created with [`Var`](@ref))
in the order they are expected by the `DBInterface.execute()` function.
# Examples
```jldoctest
julia> person = SQLTable(:person, columns = [:person_id, :year_of_birth]);
julia> q = From(person);
julia> render(q)
SQLString(\"""
SELECT
"person_1"."person_id",
"person_1"."year_of_birth"
FROM "person" AS "person_1\\"\""")
julia> q = From(person) |> Where(Fun.and(Get.year_of_birth .>= Var.YEAR,
Get.year_of_birth .< Var.YEAR .+ 10));
julia> render(q, dialect = :mysql)
SQLString(\"""
SELECT
`person_1`.`person_id`,
`person_1`.`year_of_birth`
FROM `person` AS `person_1`
WHERE
(`person_1`.`year_of_birth` >= ?) AND
(`person_1`.`year_of_birth` < (? + 10))\""",
vars = [:YEAR, :YEAR])
julia> render(q, dialect = :postgresql)
SQLString(\"""
SELECT
"person_1"."person_id",
"person_1"."year_of_birth"
FROM "person" AS "person_1"
WHERE
("person_1"."year_of_birth" >= \$1) AND
("person_1"."year_of_birth" < (\$1 + 10))\""",
vars = [:YEAR])
```
"""
struct SQLString <: AbstractString
raw::String
vars::Vector{Symbol}
SQLString(raw; vars = Symbol[]) =
new(raw, vars)
end
Base.ncodeunits(sql::SQLString) =
ncodeunits(sql.raw)
Base.codeunit(sql::SQLString) =
codeunit(sql.raw)
@Base.propagate_inbounds Base.codeunit(sql::SQLString, i::Integer) =
codeunit(sql.raw, i)
@Base.propagate_inbounds Base.isvalid(sql::SQLString, i::Integer) =
isvalid(sql.raw, i)
@Base.propagate_inbounds Base.iterate(sql::SQLString, i::Integer = 1) =
iterate(sql.raw, i)
Base.String(sql::SQLString) =
sql.raw
Base.print(io::IO, sql::SQLString) =
print(io, sql.raw)
Base.write(io::IO, sql::SQLString) =
write(io, sql.raw)
function PrettyPrinting.quoteof(sql::SQLString)
ex = Expr(:call, nameof(SQLString), sql.raw)
if !isempty(sql.vars)
push!(ex.args, Expr(:kw, :vars, quoteof(sql.vars)))
end
ex
end
function Base.show(io::IO, sql::SQLString)
print(io, "SQLString(")
show(io, sql.raw)
if !isempty(sql.vars)
print(io, ", vars = ")
show(io, sql.vars)
end
print(io, ')')
nothing
end
Base.show(io::IO, ::MIME"text/plain", sql::SQLString) =
pprint(io, sql)
"""
pack(sql::SQLString, vars::Union{Dict, NamedTuple})::Vector{Any}
Convert a dictionary or a named tuple of query parameters to the positional
form expected by `DBInterface.execute()`.
```jldoctest
julia> person = SQLTable(:person, columns = [:person_id, :year_of_birth]);
julia> q = From(person) |> Where(Fun.and(Get.year_of_birth .>= Var.YEAR,
Get.year_of_birth .< Var.YEAR .+ 10));
julia> sql = render(q, dialect = :mysql);
julia> pack(sql, (; YEAR = 1950))
2-element Vector{Any}:
1950
1950
julia> sql = render(q, dialect = :postgresql);
julia> pack(sql, (; YEAR = 1950))
1-element Vector{Any}:
1950
```
"""
function pack
end
pack(sql::SQLString, params) =
pack(sql.vars, params)
pack(sql::AbstractString, params) =
params
pack(vars::Vector{Symbol}, d::AbstractDict{Symbol}) =
Any[d[var] for var in vars]
pack(vars::Vector{Symbol}, d::AbstractDict{<:AbstractString}) =
Any[d[String(var)] for var in vars]
pack(vars::Vector{Symbol}, nt::NamedTuple) =
Any[getproperty(nt, var) for var in vars]