1
# All code is attached to its underlying database source
2
struct SourceCode{Source}
3 1
    source::Source
4
    code::Expr
5
end
6

7
"""
8
    struct BySQL{Source}
9

10
If you would like a statement to be evaluated by SQL, not Julia, and
11
none of the arguments are SQL code, you can use BySQL to hack dispatch.
12

13
```jldoctest
14
julia> using QuerySQLite
15

16
julia> using Query: @map
17

18
julia> using DataValues: DataValue
19

20
julia> database = Database(joinpath(pathof(QuerySQLite) |> dirname |> dirname, "test", "Chinook_Sqlite.sqlite"));
21

22
julia> result = database.Track |> @map({a = rand(BySQL(_), Int)});
23

24
julia> collect(result)[1].a isa DataValue{Int}
25
true
26
```
27
"""
28
struct BySQL{Source}
29 1
    source::Source
30
end
31

32
export BySQL
33

34
# Every time `SourceCode` objects are combined, check to see whether they all come from the same source
35
function pop_source!(sources, something)
36 0
    something
37
end
38
function pop_source!(sources, source_code::SourceCode)
39 1
    push!(sources, source_code.source)
40 1
    source_code.code
41
end
42
function pop_source!(sources, by_sql::BySQL)
43 0
    push!(sources, by_sql.source)
44 0
    by_sql
45
end
46
function key_pop_source!(sources, (key, source_code))
47 0
    code = pop_source!(sources, source_code)
48 0
    Expr(:kw, key, code)
49
end
50

51
function combine_sources(a_function, source_codes...; key_source_codes...)
52 1
    sources = Set(Any[])
53 1
    codes = [
54
        pop_source!(sources, source_code)
55
        for source_code in source_codes
56
    ]
57 1
    filter!(codes) do code
58
        !(code isa BySQL)
59
    end
60 1
    key_codes = [
61
        key_pop_source!(sources, key_source_code)
62
        for key_source_code in key_source_codes
63
    ]
64 1
    if length(sources) != 1
65 0
        error("Expected exactly one source; got ($(sources...))")
66
    else
67 1
        SourceCode(
68
            first(sources),
69
            Expr(:call, a_function, Expr(:parameters, key_codes...), codes...)
70
        )
71
    end
72
end
73

74
function numbered_argument(number)
75 0
    Symbol(string("argument", number))
76
end
77

78
function assert_type(argument, type)
79 1
    Expr(:(::), argument, type)
80
end
81

82
# Splat Varargs
83
function maybe_splat(argument, a_type)
84 1
    if @capture a_type Vararg{AType_}
85 1
        Expr(:(...), argument)
86
    else
87 1
        argument
88
    end
89
end
90

91
# `@code_instead` hijacks call to create Julia expressions instead of evaluating functions
92
function code_instead(location, a_function, types...)
93 1
    arguments = ntuple(numbered_argument, length(types))
94 1
    keywords = Expr(:parameters, Expr(:..., :keywords))
95 1
    Expr(:function,
96
        Expr(:call, a_function, keywords, map(assert_type, arguments, types)...),
97
        Expr(:block, location, Expr(:call,
98
            combine_sources,
99
            keywords,
100
            a_function,
101
            map(maybe_splat, arguments, types)...
102
        ))
103
    )
104
end
105

106
macro code_instead(a_function, types...)
107 1
    code_instead(__source__, a_function, types...) |> esc
108
end
109

110
# Currently, query doesn't do anything
111
function QueryOperators.query(source_code::SourceCode)
112 1
    source_code
113
end
114

115 1
@code_instead (==) SourceCode Any
116
@code_instead (==) Any SourceCode
117 1
@code_instead (==) SourceCode SourceCode
118

119
@code_instead (!=) SourceCode Any
120
@code_instead (!=) Any SourceCode
121 1
@code_instead (!=) SourceCode SourceCode
122

123 1
@code_instead (!) SourceCode
124

125
@code_instead (&) SourceCode Any
126
@code_instead (&) Any SourceCode
127 1
@code_instead (&) SourceCode SourceCode
128

129
@code_instead (|) SourceCode Any
130
@code_instead (|) Any SourceCode
131 1
@code_instead (|) SourceCode SourceCode
132

133 1
@code_instead (*) SourceCode Any
134
@code_instead (*) Any SourceCode
135 1
@code_instead (*) SourceCode SourceCode
136

137
@code_instead (-) SourceCode Any
138
@code_instead (-) Any SourceCode
139 1
@code_instead (-) SourceCode SourceCode
140

141
@code_instead (+) SourceCode Any
142
@code_instead (+) Any SourceCode
143 1
@code_instead (+) SourceCode SourceCode
144

145
@code_instead (/) SourceCode Any
146
@code_instead (/) Any SourceCode
147 1
@code_instead (/) SourceCode SourceCode
148

149
@code_instead (%) SourceCode Any
150
@code_instead (%) Any SourceCode
151 1
@code_instead (%) SourceCode SourceCode
152

153 1
@code_instead abs SourceCode
154

155
# TODO: add more methods
156 1
@code_instead char SourceCode Vararg{Any}
157

158 1
@code_instead coalesce SourceCode Vararg{Any}
159

160 1
@code_instead convert Type{Int} SourceCode
161

162
@code_instead QueryOperators.drop SourceCode Integer
163

164 1
@code_instead QueryOperators.filter SourceCode Any Expr
165

166 1
@code_instead format SourceCode AbstractString
167 1
@code_instead format AbstractString SourceCode
168 1
@code_instead format SourceCode SourceCode
169

170 1
@code_instead QueryOperators.groupby SourceCode Any Expr Any Expr
171

172 1
@code_instead hex SourceCode
173

174 1
@code_instead if_else SourceCode Any Any
175 1
@code_instead if_else Any SourceCode Any
176 1
@code_instead if_else Any Any SourceCode
177 1
@code_instead if_else Any SourceCode SourceCode
178 1
@code_instead if_else SourceCode Any SourceCode
179 1
@code_instead if_else SourceCode SourceCode Any
180 1
@code_instead if_else SourceCode SourceCode SourceCode
181

182
# TODO: add more methods
183 1
@code_instead in SourceCode Any
184

185 1
@code_instead instr SourceCode Any
186 1
@code_instead instr Any SourceCode
187 1
@code_instead instr SourceCode SourceCode
188

189
@code_instead isequal SourceCode Any
190
@code_instead isequal Any SourceCode
191
@code_instead isequal SourceCode SourceCode
192

193
@code_instead isless SourceCode Any
194
@code_instead isless Any SourceCode
195
@code_instead isless SourceCode SourceCode
196

197 1
@code_instead ismissing SourceCode
198

199 1
@code_instead join SourceCode
200

201 1
@code_instead QueryOperators.join SourceCode SourceCode Any Expr Any Expr Any Expr
202

203 1
@code_instead max SourceCode Vararg{Any}
204 1
@code_instead maximum SourceCode
205

206 1
@code_instead mean SourceCode
207

208 1
@code_instead min SourceCode Vararg{Any}
209 1
@code_instead minimum SourceCode
210

211 1
@code_instead length SourceCode
212

213 1
@code_instead lowercase SourceCode
214

215 1
@code_instead QueryOperators.map SourceCode Any Expr
216

217 1
@code_instead occursin AbstractString SourceCode
218 1
@code_instead occursin SourceCode AbstractString
219 1
@code_instead occursin SourceCode SourceCode
220

221 1
@code_instead QueryOperators.orderby SourceCode Any Expr
222

223 1
@code_instead QueryOperators.orderby_descending SourceCode Any Expr
224

225 1
@code_instead rand BySQL Type{Int}
226

227
@code_instead randstring BySQL Integer
228
@code_instead randstring SourceCode
229

230 1
@code_instead replace SourceCode Pair
231

232 1
@code_instead repr SourceCode
233

234 1
@code_instead round SourceCode
235

236
@code_instead secondary SourceCode
237

238
# TODO: add more methods
239 1
@code_instead string SourceCode Vararg{Any}
240

241 1
@code_instead strip SourceCode
242 1
@code_instead strip SourceCode Char
243

244 1
@code_instead SubString SourceCode Number Number
245 1
@code_instead SubString SourceCode Number
246

247 1
@code_instead sum SourceCode
248

249
@code_instead QueryOperators.take SourceCode Any
250

251 1
@code_instead QueryOperators.thenby SourceCode Any Expr
252

253 1
@code_instead QueryOperators.thenby_descending SourceCode Any Expr
254

255 1
@code_instead type_of SourceCode
256

257 1
@code_instead QueryOperators.unique SourceCode Any Expr
258

259 1
@code_instead uppercase SourceCode
260

261
# TODO: add
262
# printf
263
# zeroblob

Read our documentation on viewing source code .

Loading