Skip to content

Commit 560af9e

Browse files
committed
documentation
1 parent 659e0bb commit 560af9e

8 files changed

Lines changed: 142 additions & 4 deletions

File tree

docs/src/index.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,42 @@
22
Modules = [QuerySQLite]
33
```
44

5+
QuerySQLite is an experimental package sponsored by Google Summer of Code. It's
6+
finally ready for public use. Although QuerySQLite is only tested on SQLite,
7+
it's been purposefully designed to easily incorporate other database software.
8+
9+
Use [`Database`](@ref) to wrap an external database. Then, you can access its
10+
tables using `.`, and conduct most `Query` operations on them. In theory, most
11+
operations should "just work". There are a couple of exceptions.
12+
13+
### Non-overloadable methods
14+
15+
Functions like `ifelse` and `typeof` can't be overloaded. Instead, QuerySQLite
16+
exports the [`if_else`](@ref) and [`type_of`](@ref) functions and overloads them
17+
instead.
18+
19+
### No SQL arguments
20+
21+
If you would like to translate code to SQL, but you do not pass any SQL
22+
arguments, you will need use [`BySQL`](@ref) to pass a dummy SQL object instead.
23+
See the `BySQL` docstring for more information.
24+
25+
## Developer notes
26+
27+
QuerySQLite hijacks Julia's multiple dispatch to translate external database
28+
commands to SQL instead of evaluating them. To do this, it construct a
29+
"model_row" that represents the structure of a row of data. If you would like to
30+
support for a new function, there are only a few steps:
31+
32+
- Use the `@code_instead` macro to specify the argument types for diversion
33+
into SQL translation.
34+
- If your function will modify the row structure of the
35+
table, define a `model_row_call` method.
36+
- Use the `@translate_default` macro to name the matching SQL function. If more
37+
involved processing is required, define a `translate_call` method instead.
38+
- If you would like to show your SQL expression in a non-standard way, edit the
39+
`show` method for `SQLExpression`s.
40+
541
```@autodocs
642
Modules = [QuerySQLite]
743
```

src/QuerySQLite.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module QuerySQLite
22

3-
import Base: !, &, |, ==, !=, *, +, %, abs, Char, coalesce, collect, convert, 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,
55
occursin, rand, replace, repr, round, show, showerror, startswith, string, strip, SubString, uppercase
66
using Base: Generator, NamedTuple, RefValue, SizeUnknown, tail

src/code_instead.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@ end
99
1010
If you would like a statement to be evaluated by SQL, not Julia, and
1111
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+
```
1227
"""
1328
struct BySQL{Source}
1429
source::Source
@@ -119,10 +134,18 @@ end
119134
@code_instead (*) Any SourceCode
120135
@code_instead (*) SourceCode SourceCode
121136

137+
@code_instead (-) SourceCode Any
138+
@code_instead (-) Any SourceCode
139+
@code_instead (-) SourceCode SourceCode
140+
122141
@code_instead (+) SourceCode Any
123142
@code_instead (+) Any SourceCode
124143
@code_instead (+) SourceCode SourceCode
125144

145+
@code_instead (/) SourceCode Any
146+
@code_instead (/) Any SourceCode
147+
@code_instead (/) SourceCode SourceCode
148+
126149
@code_instead (%) SourceCode Any
127150
@code_instead (%) Any SourceCode
128151
@code_instead (%) SourceCode SourceCode

src/database.jl

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
"""
22
get_table_names(source)::Tuple{Symbol}
33
4-
Get the names of the tables in `source`
4+
Get the names of the tables in `source`.
5+
6+
```jldoctest
7+
julia> using QuerySQLite
8+
9+
julia> database = Database(joinpath(pathof(QuerySQLite) |> dirname |> dirname, "test", "Chinook_Sqlite.sqlite"));
10+
11+
julia> get_table_names(getfield(database, :source))
12+
(:Album, :Artist, :Customer, :Employee, :Genre, :Invoice, :InvoiceLine, :MediaType, :Playlist, :PlaylistTrack, :Track)
13+
```
514
"""
615
function get_table_names(source::DB)
716
as_symbols(tables(source).name)
@@ -11,7 +20,16 @@ export get_table_names
1120
"""
1221
get_column_names(source, table_name)::Tuple{Symbol}
1322
14-
Get the names of the columns in `table_name` in `source`
23+
Get the names of the columns in `table_name` in `source`.
24+
25+
```jldoctest example
26+
julia> using QuerySQLite
27+
28+
julia> database = Database(joinpath(pathof(QuerySQLite) |> dirname |> dirname, "test", "Chinook_Sqlite.sqlite"));
29+
30+
julia> get_column_names(getfield(database, :source), :Album)
31+
(:AlbumId, :Title, :ArtistId)
32+
```
1533
"""
1634
function get_column_names(source::DB, table_name)
1735
as_symbols(columns(source, String(table_name)).name)
@@ -21,19 +39,48 @@ export get_column_names
2139
"""
2240
struct Database{Source}
2341
24-
`source` need only support [`get_table_names`](@ref) and [`get_column_names`](@ref).
42+
A wrapper for an external database. `source` need only support
43+
[`get_table_names`](@ref) and [`get_column_names`](@ref).
44+
45+
```jldoctest
46+
julia> using QuerySQLite
47+
48+
julia> database = Database(joinpath(pathof(QuerySQLite) |> dirname |> dirname, "test", "Chinook_Sqlite.sqlite"));
49+
50+
julia> database.Track
51+
?x9 SQLite query result
52+
TrackId │ Name │ AlbumId │ MediaTypeId
53+
────────┼───────────────────────────────────────────┼─────────┼────────────
54+
1 │ "For Those About To Rock (We Salute You)" │ 1 │ 1
55+
2 │ "Balls to the Wall" │ 2 │ 2
56+
3 │ "Fast As a Shark" │ 3 │ 2
57+
4 │ "Restless and Wild" │ 3 │ 2
58+
5 │ "Princess of the Dawn" │ 3 │ 2
59+
6 │ "Put The Finger On You" │ 1 │ 1
60+
7 │ "Let's Get It Up" │ 1 │ 1
61+
8 │ "Inject The Venom" │ 1 │ 1
62+
9 │ "Snowballed" │ 1 │ 1
63+
10 │ "Evil Walks" │ 1 │ 1
64+
... with more rows, and 5 more columns: GenreId, Composer, Milliseconds, Bytes, UnitPrice
65+
```
2566
"""
2667
struct Database{Source}
2768
source::Source
2869
end
2970

71+
"""
72+
Database(filename::AbstractString)
73+
74+
Guess the database software from the filename.
75+
"""
3076
function Database(filename::AbstractString)
3177
if endswith(filename, ".sqlite")
3278
Database(SQLite.DB(filename))
3379
else
3480
throw(ArgumentError("Unsupported database type for $filename"))
3581
end
3682
end
83+
export Database
3784

3885
get_source(source_tables::Database) = getfield(source_tables, :source)
3986

src/show.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,12 @@ function show(io::IO, sql_expression::SQLExpression)
100100
infix(io, call, arguments...)
101101
elseif call === :*
102102
infix(io, call, arguments...)
103+
elseif call === :/
104+
infix(io, call, arguments...)
103105
elseif call === :+
104106
infix(io, call, arguments...)
107+
elseif call === :-
108+
infix(io, call, arguments...)
105109
elseif call === :%
106110
infix(io, call, arguments...)
107111
elseif call === :AND
@@ -164,3 +168,23 @@ end
164168
function finalize(something)
165169
something
166170
end
171+
172+
"""
173+
get_sql(it)
174+
175+
Use `get_sql` if you would like to see the SQL code generated by an SQLite
176+
query.
177+
178+
```jldoctest example
179+
julia> using QuerySQLite
180+
181+
julia> database = Database(joinpath(pathof(QuerySQLite) |> dirname |> dirname, "test", "Chinook_Sqlite.sqlite"));
182+
183+
julia> get_sql(database.Track)
184+
FROM (Track)
185+
```
186+
"""
187+
function get_sql(it)
188+
translate(it.code)
189+
end
190+
export get_sql

src/translate.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@ end
5555

5656
@translate_default ::typeof(*) :*
5757

58+
@translate_default ::typeof(/) :/
59+
5860
@translate_default ::typeof(+) :+
5961

62+
@translate_default ::typeof(-) :-
63+
6064
@translate_default ::typeof(%) :%
6165

6266
@translate_default ::typeof(abs) :ABS

test/runtests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ result =
136136
and_test = _.zero & _.one,
137137
or_test = _.zero | _.one,
138138
times_test = _.zero * _.one,
139+
divide_test = _.zero / _.one,
139140
plus_test = _.zero + _.one,
141+
minus_test = _.one - _.zero,
140142
mod_test = _.zero % _.one,
141143
abs_test = abs(_.negative_one),
142144
in_test = _.zero in (0, 1),
@@ -183,7 +185,9 @@ result =
183185
@test result.and_test == 0
184186
@test result.or_test == 1
185187
@test result.times_test == 0
188+
@test result.divide_test == 0
186189
@test result.plus_test == 1
190+
@test result.minus_test == 1
187191
@test result.mod_test == 0
188192
@test result.abs_test == 1
189193
@test result.in_test == 1

test/test.sqlite

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)