Skip to content

Commit 05d68b7

Browse files
committed
getting close
1 parent fec7be4 commit 05d68b7

9 files changed

Lines changed: 146 additions & 79 deletions

File tree

Project.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ uuid = "57f923c0-76be-11e9-095d-c942eaffc94b"
33
version = "0.2.1-DEV"
44

55
[deps]
6+
DataValues = "e7dc6d0d-1eca-5fa6-8ad6-5aecde8b7ea5"
7+
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
68
IteratorInterfaceExtensions = "82899510-4779-5014-852e-03e436cf321d"
79
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
810
QueryOperators = "2aef5ad7-51ca-5a8f-8e88-e75cf067b44b"
911
SQLite = "0aa819cd-b072-5ff4-a722-6bc24af294d9"
10-
TableTraits = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
11-
DataValues = "e7dc6d0d-1eca-5fa6-8ad6-5aecde8b7ea5"
12-
TableShowUtils = "5e66a065-1f0a-5976-b372-e0b8c017ca10"
1312
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
13+
TableShowUtils = "5e66a065-1f0a-5976-b372-e0b8c017ca10"
14+
TableTraits = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
1415

1516
[extras]
1617
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"

src/QuerySQLite.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
module QuerySQLite
22

3-
import Base: !, &, |, ==, !=, *, +, %, abs, Char, coalesce, collect, eltype, getproperty, length,
3+
import Base: !, &, |, ==, !=, *, +, %, abs, Char, coalesce, collect, convert, eltype, getproperty, length,
44
lowercase, in, isdone, isequal, isless, ismissing, iterate, IteratorSize, max, min,
5-
occursin, rand, show, showerror, startswith, string, strip, uppercase
5+
occursin, rand, replace, repr, round, show, showerror, startswith, string, strip, SubString, uppercase
66
using Base: Generator, NamedTuple, RefValue, SizeUnknown, tail
77
using Base.Meta: quot
88
import Base.Multimedia: showable
99
using DataValues: DataValue
10+
import Dates: Date, DateTime, Time
1011
import IteratorInterfaceExtensions: getiterator, isiterable
1112
import MacroTools
1213
using MacroTools: @capture

src/code_instead.jl

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
# All code is attached to its underlying database source
22
struct SourceCode{Source}
33
source::Source
4-
code::Expr
4+
code::Union{Expr, Nothing}
55
end
66

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+
struct BySQL{Source}
14+
source::Source
15+
end
16+
17+
export BySQL
18+
719
# Every time `SourceCode` objects are combined, check to see whether they all come from the same source
820
function pop_source!(sources, something)
921
something
@@ -12,18 +24,28 @@ function pop_source!(sources, source_code::SourceCode)
1224
push!(sources, source_code.source)
1325
source_code.code
1426
end
27+
function pop_source!(sources, by_sql::BySQL)
28+
push!(sources, by_sql.source)
29+
by_sql
30+
end
1531
function key_pop_source!(sources, (key, source_code))
16-
code = pop_source!(souces, source_code)
32+
code = pop_source!(sources, source_code)
1733
Expr(:kw, key, code)
1834
end
1935

2036
function combine_sources(a_function, source_codes...; key_source_codes...)
2137
sources = Set(Any[])
22-
codes = partial_map(pop_source!, sources, source_codes)
23-
key_codes = (
38+
codes = [
39+
pop_source!(sources, source_code)
40+
for source_code in source_codes
41+
]
42+
filter!(codes) do code
43+
!(code isa BySQL)
44+
end
45+
key_codes = [
2446
key_pop_source!(sources, key_source_code)
2547
for key_source_code in key_source_codes
26-
)
48+
]
2749
if length(sources) != 1
2850
error("Expected exactly one source; got ($(sources...))")
2951
else
@@ -56,12 +78,12 @@ function code_instead(location, a_function, types...)
5678
arguments = ntuple(numbered_argument, length(types))
5779
keywords = Expr(:parameters, Expr(:..., :keywords))
5880
Expr(:function,
59-
Expr(:call, a_function, keywords, map_unrolled(assert_type, arguments, types)...),
81+
Expr(:call, a_function, keywords, map(assert_type, arguments, types)...),
6082
Expr(:block, location, Expr(:call,
6183
combine_sources,
6284
keywords,
6385
a_function,
64-
map_unrolled(maybe_splat, arguments, types)...
86+
map(maybe_splat, arguments, types)...
6587
))
6688
)
6789
end
@@ -111,6 +133,14 @@ end
111133

112134
@code_instead coalesce SourceCode Vararg{Any}
113135

136+
@code_instead convert Type{Int} SourceCode
137+
138+
# TODO: support dateformat
139+
@code_instead Date SourceCode
140+
141+
# TODO: support dateformat
142+
@code_instead DateTime SourceCode
143+
114144
@code_instead QueryOperators.drop SourceCode Integer
115145

116146
@code_instead QueryOperators.filter SourceCode Any Expr
@@ -164,18 +194,35 @@ end
164194

165195
@code_instead QueryOperators.orderby_descending SourceCode Any Expr
166196

197+
@code_instead rand BySQL Type{Int}
198+
199+
# TODO: add more methods
200+
@code_instead replace SourceCode Pair
201+
202+
@code_instead repr SourceCode
203+
204+
@code_instead round SourceCode
205+
167206
@code_instead secondary SourceCode
168207

208+
@code_instead strip SourceCode
209+
@code_instead strip SourceCode Char
210+
211+
@code_instead SubString SourceCode Number Number
212+
@code_instead SubString SourceCode Number
213+
214+
@code_instead sum SourceCode
215+
169216
@code_instead QueryOperators.take SourceCode Any
170217

171218
@code_instead QueryOperators.thenby SourceCode Any Expr
172219

173220
@code_instead QueryOperators.thenby_descending SourceCode Any Expr
174221

175-
@code_instead sum SourceCode
222+
# TODO: support dateformat
223+
@code_instead Time SourceCode
176224

177-
@code_instead strip SourceCode
178-
@code_instead strip SourceCode Char
225+
@code_instead type_of SourceCode
179226

180227
# TODO: add more methods
181228
@code_instead QueryOperators.unique SourceCode Any Expr
@@ -184,20 +231,10 @@ end
184231

185232
# TODO: add
186233
# printf
187-
# quote
188-
# random
189234
# randomblob
190-
# replace
191-
# round
192-
# substr
193-
# typeof
194-
# unicode
195235
# zeroblob
196236
# group_concat
197237
# total
198-
# date
199-
# time
200-
# datetime
201238
# julianday
202239
# strftime
203240

src/iterate.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ function getiterator(source_code::SourceCode)
115115
sqlite3_column_count(handle)
116116
)
117117
SQLiteCursor{NamedTuple{
118-
Tuple(map_unrolled(first, schema)),
119-
Tuple{map_unrolled(second, schema)...}
118+
Tuple(map(first, schema)),
119+
Tuple{map(second, schema)...}
120120
}}(statement, Ref(status), Ref(0))
121121
end
122122

src/model_row.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ end
2525
function model_row_call(::typeof(getproperty), source_tables::Database, table_name)
2626
source = get_source(source_tables)
2727
column_names = get_column_names(source, table_name)
28-
NamedTuple{column_names}(partial_map(
29-
get_column,
30-
SourceRow(source, table_name),
31-
column_names
32-
))
28+
source_row = SourceRow(source, table_name)
29+
NamedTuple{column_names}(
30+
map(column_names) do column_name
31+
get_column(source_row, column_name)
32+
end
33+
)
3334
end
3435

3536
# Map is the only function which directly modifies the model row

src/translate.jl

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
# Frustratingly, primary tables are translated differently from secondary tables, so translate must propagate the `primary` keyword
33
struct SQLExpression
44
call::Symbol
5-
arguments::Tuple
6-
SQLExpression(call, arguments...) = new(call, arguments)
5+
arguments::Vector{Any}
6+
SQLExpression(call, arguments...) = new(call, Any[arguments...])
77
end
88

99
function translate(something::Union{Char, AbstractString}; primary = true)
@@ -26,7 +26,7 @@ end
2626
function translate_default(location, function_type, SQL_call)
2727
result = :(
2828
function translate_call($function_type, arguments...; primary = true)
29-
$SQLExpression($SQL_call, $map_unrolled(
29+
$SQLExpression($SQL_call, $map(
3030
argument -> $translate(argument; primary = primary),
3131
arguments
3232
)...)
@@ -65,9 +65,17 @@ function as(pair; primary = true)
6565
)
6666
end
6767

68+
@translate_default ::typeof(coalesce) :COALESCE
69+
6870
@translate_default ::typeof(char) :CHAR
6971

70-
@translate_default ::typeof(coalesce) :COALESCE
72+
function translate_call(::typeof(convert), ::Type{Int}, it; primary = true)
73+
SQLExpression(:UNICODE, translate(it))
74+
end
75+
76+
@translate_default ::Type{Date} :DATE
77+
78+
@translate_default ::Type{DateTime} :DATETIME
7179

7280
@translate_default ::typeof(hex) :HEX
7381

@@ -191,10 +199,33 @@ function translate_call(::typeof(QueryOperators.orderby_descending), unordered,
191199
)
192200
end
193201

202+
@translate_default ::typeof(repr) :QUOTE
203+
204+
function translate_call(::typeof(rand), ::Type{Int}; primary = true, digits = 0)
205+
SQLExpression(:RANDOM)
206+
end
207+
208+
function translate_call(::typeof(replace), it, pair; primary = true)
209+
SQLExpression(:REPLACE,
210+
translate(it; primary = primary),
211+
translate(pair.first; primary = primary),
212+
translate(pair.second; primary = primary)
213+
)
214+
end
215+
216+
function translate_call(::typeof(round), it; primary = true, digits = 0)
217+
SQLExpression(:ROUND,
218+
translate(it; primary = primary),
219+
translate(digits; primary = primary)
220+
)
221+
end
222+
194223
@translate_default ::typeof(string) :||
195224

196225
@translate_default ::typeof(strip) :TRIM
197226

227+
@translate_default ::Type{SubString} :SUBSTR
228+
198229
@translate_default ::typeof(sum) :SUM
199230

200231
@translate_default ::typeof(QueryOperators.take) :LIMIT
@@ -215,6 +246,10 @@ function translate_call(::typeof(QueryOperators.thenby_descending), unordered, k
215246
)
216247
end
217248

249+
@translate_default ::Type{Time} :Time
250+
251+
@translate_default ::typeof(type_of) :TYPEOF
252+
218253
function translate_call(::typeof(QueryOperators.unique), repeated, key_function, key_function_expression; primary = true)
219254
result = translate(repeated; primary = primary)
220255
SQLExpression(Symbol(string(result.call, " DISTINCT")), result.arguments...)

src/utilities.jl

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,5 @@
1-
# Recursion will be more performant than iteration for small tuples. My own recursive map makes sure that there is no iteration for performance
2-
function map_unrolled(call, variables::Tuple{})
3-
()
4-
end
5-
function map_unrolled(call, variables)
6-
(call(first(variables)), map_unrolled(call, tail(variables))...)
7-
end
8-
9-
function map_unrolled(call, variables1::Tuple{}, variables2::Tuple{})
10-
()
11-
end
12-
function map_unrolled(call, variables1, variables2)
13-
(
14-
call(first(variables1), first(variables2)),
15-
map_unrolled(call, tail(variables1), tail(variables2))...
16-
)
17-
end
18-
19-
# In partial map, fixed is passed each time. This avoids captures, which have performace issues
20-
function partial_map(call, fixed, variables::Tuple{})
21-
()
22-
end
23-
function partial_map(call, fixed, variables)
24-
(
25-
call(fixed, first(variables)),
26-
partial_map(call, fixed, tail(variables))...
27-
)
28-
end
29-
function partial_map(call, fixed, variables1::Tuple{}, variables2::Tuple{})
30-
()
31-
end
32-
function partial_map(call, fixed, variables1, variables2)
33-
(
34-
call(fixed, first(variables1), first(variables2)),
35-
partial_map(call, fixed, tail(variables1), tail(variables2))...
36-
)
37-
end
38-
391
function as_symbols(them)
40-
map_unrolled(Symbol, (them...,))
2+
map(Symbol, (them...,))
413
end
424

435
split_keyword(keyword::Expr) =

0 commit comments

Comments
 (0)