Repository navigation
Expand file tree
/
Copy pathcode_instead.jl
More file actions
263 lines (193 loc) · 6.6 KB
/
Copy pathcode_instead.jl
File metadata and controls
263 lines (193 loc) · 6.6 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# All code is attached to its underlying database source
struct SourceCode{Source}
source::Source
code::Expr
end
"""
struct BySQL{Source}
If you would like a statement to be evaluated by SQL, not Julia, and
none of the arguments are SQL code, you can use BySQL to hack dispatch.
```jldoctest
julia> using QuerySQLite
julia> using Query: @map
julia> using DataValues: DataValue
julia> database = Database(joinpath(pathof(QuerySQLite) |> dirname |> dirname, "test", "Chinook_Sqlite.sqlite"));
julia> result = database.Track |> @map({a = rand(BySQL(_), Int)});
julia> collect(result)[1].a isa DataValue{Int}
true
```
"""
struct BySQL{Source}
source::Source
end
export BySQL
# Every time `SourceCode` objects are combined, check to see whether they all come from the same source
function pop_source!(sources, something)
something
end
function pop_source!(sources, source_code::SourceCode)
push!(sources, source_code.source)
source_code.code
end
function pop_source!(sources, by_sql::BySQL)
push!(sources, by_sql.source)
by_sql
end
function key_pop_source!(sources, (key, source_code))
code = pop_source!(sources, source_code)
Expr(:kw, key, code)
end
function combine_sources(a_function, source_codes...; key_source_codes...)
sources = Set(Any[])
codes = [
pop_source!(sources, source_code)
for source_code in source_codes
]
filter!(codes) do code
!(code isa BySQL)
end
key_codes = [
key_pop_source!(sources, key_source_code)
for key_source_code in key_source_codes
]
if length(sources) != 1
error("Expected exactly one source; got ($(sources...))")
else
SourceCode(
first(sources),
Expr(:call, a_function, Expr(:parameters, key_codes...), codes...)
)
end
end
function numbered_argument(number)
Symbol(string("argument", number))
end
function assert_type(argument, type)
Expr(:(::), argument, type)
end
# Splat Varargs
function maybe_splat(argument, a_type)
if @capture a_type Vararg{AType_}
Expr(:(...), argument)
else
argument
end
end
# `@code_instead` hijacks call to create Julia expressions instead of evaluating functions
function code_instead(location, a_function, types...)
arguments = ntuple(numbered_argument, length(types))
keywords = Expr(:parameters, Expr(:..., :keywords))
Expr(:function,
Expr(:call, a_function, keywords, map(assert_type, arguments, types)...),
Expr(:block, location, Expr(:call,
combine_sources,
keywords,
a_function,
map(maybe_splat, arguments, types)...
))
)
end
macro code_instead(a_function, types...)
code_instead(__source__, a_function, types...) |> esc
end
# Currently, query doesn't do anything
function QueryOperators.query(source_code::SourceCode)
source_code
end
@code_instead (==) SourceCode Any
@code_instead (==) Any SourceCode
@code_instead (==) SourceCode SourceCode
@code_instead (!=) SourceCode Any
@code_instead (!=) Any SourceCode
@code_instead (!=) SourceCode SourceCode
@code_instead (!) SourceCode
@code_instead (&) SourceCode Any
@code_instead (&) Any SourceCode
@code_instead (&) SourceCode SourceCode
@code_instead (|) SourceCode Any
@code_instead (|) Any SourceCode
@code_instead (|) SourceCode SourceCode
@code_instead (*) SourceCode Any
@code_instead (*) Any SourceCode
@code_instead (*) SourceCode SourceCode
@code_instead (-) SourceCode Any
@code_instead (-) Any SourceCode
@code_instead (-) SourceCode SourceCode
@code_instead (+) SourceCode Any
@code_instead (+) Any SourceCode
@code_instead (+) SourceCode SourceCode
@code_instead (/) SourceCode Any
@code_instead (/) Any SourceCode
@code_instead (/) SourceCode SourceCode
@code_instead (%) SourceCode Any
@code_instead (%) Any SourceCode
@code_instead (%) SourceCode SourceCode
@code_instead abs SourceCode
# TODO: add more methods
@code_instead char SourceCode Vararg{Any}
@code_instead coalesce SourceCode Vararg{Any}
@code_instead convert Type{Int} SourceCode
@code_instead QueryOperators.drop SourceCode Integer
@code_instead QueryOperators.filter SourceCode Any Expr
@code_instead format SourceCode AbstractString
@code_instead format AbstractString SourceCode
@code_instead format SourceCode SourceCode
@code_instead QueryOperators.groupby SourceCode Any Expr Any Expr
@code_instead hex SourceCode
@code_instead if_else SourceCode Any Any
@code_instead if_else Any SourceCode Any
@code_instead if_else Any Any SourceCode
@code_instead if_else Any SourceCode SourceCode
@code_instead if_else SourceCode Any SourceCode
@code_instead if_else SourceCode SourceCode Any
@code_instead if_else SourceCode SourceCode SourceCode
# TODO: add more methods
@code_instead in SourceCode Any
@code_instead instr SourceCode Any
@code_instead instr Any SourceCode
@code_instead instr SourceCode SourceCode
@code_instead isequal SourceCode Any
@code_instead isequal Any SourceCode
@code_instead isequal SourceCode SourceCode
@code_instead isless SourceCode Any
@code_instead isless Any SourceCode
@code_instead isless SourceCode SourceCode
@code_instead ismissing SourceCode
@code_instead join SourceCode
@code_instead QueryOperators.join SourceCode SourceCode Any Expr Any Expr Any Expr
@code_instead max SourceCode Vararg{Any}
@code_instead maximum SourceCode
@code_instead mean SourceCode
@code_instead min SourceCode Vararg{Any}
@code_instead minimum SourceCode
@code_instead length SourceCode
@code_instead lowercase SourceCode
@code_instead QueryOperators.map SourceCode Any Expr
@code_instead occursin AbstractString SourceCode
@code_instead occursin SourceCode AbstractString
@code_instead occursin SourceCode SourceCode
@code_instead QueryOperators.orderby SourceCode Any Expr
@code_instead QueryOperators.orderby_descending SourceCode Any Expr
@code_instead rand BySQL Type{Int}
@code_instead randstring BySQL Integer
@code_instead randstring SourceCode
@code_instead replace SourceCode Pair
@code_instead repr SourceCode
@code_instead round SourceCode
@code_instead secondary SourceCode
# TODO: add more methods
@code_instead string SourceCode Vararg{Any}
@code_instead strip SourceCode
@code_instead strip SourceCode Char
@code_instead SubString SourceCode Number Number
@code_instead SubString SourceCode Number
@code_instead sum SourceCode
@code_instead QueryOperators.take SourceCode Any
@code_instead QueryOperators.thenby SourceCode Any Expr
@code_instead QueryOperators.thenby_descending SourceCode Any Expr
@code_instead type_of SourceCode
@code_instead QueryOperators.unique SourceCode Any Expr
@code_instead uppercase SourceCode
# TODO: add
# printf
# zeroblob