1
function generate_namedtuple(::Type{NamedTuple{names,types}}, q) where {names,types}
2 1
    if @generated
3 1
        vals = Tuple(:(getvalue(q, $i, $(fieldtype(types, i)))) for i = 1:fieldcount(types))
4 1
        return :(NamedTuple{names,types}(($(vals...),)))
5
    else
6
        return NamedTuple{names,types}(Tuple(getvalue(q, i, fieldtype(types, i)) for i = 1:fieldcount(types)))
7
    end
8
end
9

10
# This section of the code hijacks SQLite internals to make queryverse-compatible iterators
11
# TODO: submit as a PR to SQLite
12
struct SQLiteCursor{Row}
13 1
    statement::Stmt
14
    status::RefValue{Cint}
15
    cursor_row::RefValue{Int}
16
end
17

18
function eltype(::SQLiteCursor{Row}) where {Row}
19 0
    Row
20
end
21
function IteratorSize(::Type{<:SQLiteCursor})
22 0
    SizeUnknown()
23
end
24

25
function isdone(cursor::SQLiteCursor)
26 1
    status = cursor.status[]
27 1
    if status == SQLITE_DONE
28 1
        true
29 1
    elseif status == SQLITE_ROW
30 1
        false
31 0
    elseif sqliteerror(cursor.statement.db)
32 0
        false
33
    else
34 0
        error("Unknown SQLite cursor status")
35
    end
36
end
37

38
function getvalue(cursor::SQLiteCursor, column_number::Int, ::Type{Value}) where {Value}
39 1
    handle = cursor.statement.handle
40 1
    column_type = sqlite3_column_type(handle, column_number)
41 1
    if column_type == SQLITE_NULL
42 1
        Value()
43
    else
44 1
        julia_type = juliatype(column_type) # native SQLite Int, Float, and Text types
45 1
        sqlitevalue(
46
            if julia_type === Any
47
            if !isbitstype(Value)
48 0
                Value
49
            else
50 0
                julia_type
51
            end
52
        else
53 1
            julia_type
54
        end, handle, column_number)
55
    end
56
end
57

58
function iterate(cursor::SQLiteCursor{Row}) where {Row}
59 1
    if isdone(cursor)
60 0
        nothing
61
    else
62 1
        named_tuple = generate_namedtuple(Row, cursor)
63 1
        cursor.cursor_row[] = 1
64 1
        named_tuple, 1
65
    end
66
end
67

68
function iterate(cursor::SQLiteCursor{Row}, state) where {Row}
69 1
    if state != cursor.cursor_row[]
70 0
        error("State does not match SQLiteCursor cursor_row")
71
    else
72 1
        cursor.status[] = sqlite3_step(cursor.statement.handle)
73 1
        if isdone(cursor)
74 1
            nothing
75
        else
76 1
            named_tuple = generate_namedtuple(Row, cursor)
77 1
            cursor.cursor_row[] = state + 1
78 1
            named_tuple, state + 1
79
        end
80
    end
81
end
82

83
function isiterable(::SourceCode)
84 0
    true
85
end
86
function isiterabletable(::SourceCode)
87 0
    true
88
end
89
function collect(source::SourceCode)
90 1
    collect(getiterator(source))
91
end
92

93
function second((value_1, value_2))
94 0
    value_2
95
end
96

97
function name_and_type(handle, column_number, nullable=true, strict_types=true)
98 0
    Symbol(unsafe_string(sqlite3_column_name(handle, column_number))),
99
    if strict_types
100 0
        julia_type = juliatype(handle, column_number)
101 0
        if nullable
102 0
            DataValue{julia_type}
103
        else
104 0
            julia_type
105
        end
106
    else
107 0
        Any
108
    end
109
end
110

111
function getiterator(source_code::SourceCode)
112 1
    statement = Stmt(
113
        source_code.source,
114
        string(finalize(translate(source_code.code)))
115
    )
116
    # bind!(statement, values)
117 1
    status = execute(statement)
118 1
    handle = statement.handle
119
    schema = ntuple(
120
        let handle = handle
121 1
            column_number -> name_and_type(handle, column_number)
122
        end,
123
        sqlite3_column_count(handle)
124
    )
125 1
    SQLiteCursor{NamedTuple{Tuple(map(first, schema)),Tuple{map(second, schema)...}}}(statement, Ref(status), Ref(0))
126
end
127

128
# Use default show methods from the queryverse
129
function show(stream::IO, source::SourceCode)
130 1
    printtable(stream, getiterator(source), "SQLite query result")
131
end
132

133
function showable(::MIME"text/html", source::SourceCode)
134 0
    true
135
end
136
function show(stream::IO, ::MIME"text/html", source::SourceCode)
137 0
    printHTMLtable(stream, getiterator(source))
138
end
139

140
function showable(::MIME"application/vnd.dataresource+json", source::SourceCode)
141 0
    true
142
end
143
function show(stream::IO, ::MIME"application/vnd.dataresource+json", source::SourceCode)
144 0
    printdataresource(stream, getiterator(source))
145
end

Read our documentation on viewing source code .

Loading