11module QuerySQLite
22
3- import Base: ! , & , | , == , != , coalesce, getproperty, in, isequal, isless, ismissing, occursin, startswith
4- using Base: Generator, NamedTuple, tail
3+ import Base: ! , & , | , == , != , coalesce, collect, eltype, getproperty, in,
4+ isdone, isequal, isless, ismissing, iterate, IteratorSize, occursin, show,
5+ startswith
6+ using Base: Generator, NamedTuple, RefValue, SizeUnknown, tail
57import Base. Iterators: drop, take
68using Base. Meta: quot
9+ import Base. Multimedia: showable
10+ using DataValues: DataValue
11+ import IteratorInterfaceExtensions: getiterator, isiterable
712import MacroTools
813using MacroTools: @capture
914import QueryOperators
1015import QueryOperators: orderby, query
1116import SQLite
12- using SQLite: columns, DB, tables
13- import IteratorInterfaceExtensions, TableTraits
14- using DataValues
15- import TableShowUtils
17+ import SQLite: getvalue
18+ using SQLite: columns, DB, execute!, generate_namedtuple, juliatype,
19+ SQLITE_DONE, SQLITE_NULL, SQLITE_ROW, sqlite3_column_count, sqlite3_column_name,
20+ sqlite3_column_type, sqlite3_step, sqlitevalue, Stmt, tables
21+ using TableShowUtils: printdataresource, printHTMLtable, printtable
22+ import TableTraits: isiterabletable
1623
1724map_unrolled (call, variables:: Tuple{} ) = ()
1825map_unrolled (call, variables) =
@@ -412,7 +419,7 @@ translate(code::Expr) =
412419 end , arguments... )
413420 elseif @capture code left_ && right_
414421 translate_call (& , left, right)
415- elseif @capture code left_ | right_
422+ elseif @capture code left_ || right_
416423 translate_call (| , left, right)
417424 elseif @capture code if condition_ yes_ else no_ end
418425 translate_call (if_else, condition, left, right)
@@ -423,90 +430,118 @@ translate(code::Expr) =
423430# collect
424431query (outside_code:: OutsideCode ) = outside_code
425432
426- struct SQLiteCursor{T }
427- stmt :: SQLite. Stmt
428- status:: Base. RefValue{Cint}
429- cur_row :: Base. RefValue{Int}
433+ struct SQLiteCursor{Row }
434+ statement :: Stmt
435+ status:: RefValue{Cint}
436+ cursor_row :: RefValue{Int}
430437end
431438
432- Base. eltype (q:: SQLiteCursor{T} ) where {T} = T
433- Base. IteratorSize (:: Type{<:SQLiteCursor} ) = Base. SizeUnknown ()
434-
435- function isdone (q:: SQLiteCursor )
436- st = q. status[]
437- st == SQLite. SQLITE_DONE && return true
438- st == SQLite. SQLITE_ROW || SQLite. sqliteerror (q. stmt. db)
439- return false
439+ eltype (:: SQLiteCursor{Row} ) where {Row} = Row
440+ IteratorSize (:: Type{<:SQLiteCursor} ) = SizeUnknown ()
441+
442+ function isdone (cursor:: SQLiteCursor )
443+ status = cursor. status[]
444+ if status == SQLITE_DONE
445+ true
446+ elseif status == SQLITE_ROW
447+ false
448+ elseif sqliteerror (cursor. statement. db)
449+ false
450+ else
451+ error (" Unknown SQLite cursor status" )
452+ end
440453end
441454
442- function SQLite . getvalue (q :: SQLiteCursor , col :: Int , :: Type{T } ) where {T }
443- handle = q . stmt . handle
444- t = SQLite . sqlite3_column_type (handle, col )
445- if t == SQLite . SQLITE_NULL
446- return T ()
455+ function getvalue (cursor :: SQLiteCursor , column_number :: Int , :: Type{Value } ) where {Value }
456+ handle = cursor . statement . handle
457+ column_type = sqlite3_column_type (handle, column_number )
458+ if column_type == SQLITE_NULL
459+ Value ()
447460 else
448- TT = SQLite. juliatype (t) # native SQLite Int, Float, and Text types
449- return SQLite. sqlitevalue (ifelse (TT === Any && ! isbitstype (T), T, TT), handle, col)
461+ julia_type = juliatype (column_type) # native SQLite Int, Float, and Text types
462+ sqlitevalue (
463+ if julia_type === Any
464+ if ! isbitstype (Value)
465+ Value
466+ else
467+ julia_type
468+ end
469+ else
470+ julia_type
471+ end , handle, column_number)
450472 end
451473end
452474
453- function Base. iterate (q:: SQLiteCursor{NT} ) where {NT}
454- isdone (q) && return nothing
455- nt = SQLite. generate_namedtuple (NT, q)
456- q. cur_row[] = 1
457- return nt, 1
458- end
475+ iterate (cursor:: SQLiteCursor{Row} ) where {Row} =
476+ if isdone (cursor)
477+ nothing
478+ else
479+ named_tuple = generate_namedtuple (Row, cursor)
480+ cursor. cursor_row[] = 1
481+ named_tuple, 1
482+ end
459483
460- function Base. iterate (q:: SQLiteCursor{NT} , state) where {NT}
461- state != q. cur_row[] && error (" FOO" )
462- q. status[] = SQLite. sqlite3_step (q. stmt. handle)
463- isdone (q) && return nothing
464- nt = SQLite. generate_namedtuple (NT, q)
465- q. cur_row[] = state + 1
466- return nt, state + 1
467- end
484+ iterate (cursor:: SQLiteCursor{Row} , state) where {Row} =
485+ if state != cursor. cursor_row[]
486+ error (" State does not match SQLiteCursor row" )
487+ else
488+ cursor. status[] = sqlite3_step (cursor. statement. handle)
489+ if isdone (cursor)
490+ nothing
491+ else
492+ named_tuple = generate_namedtuple (Row, cursor)
493+ cursor. cursor_row[] = state + 1
494+ named_tuple, state + 1
495+ end
496+ end
468497
469- IteratorInterfaceExtensions . isiterable (:: OutsideCode ) = true
470- TableTraits . isiterabletable (:: OutsideCode ) = true
498+ isiterable (:: OutsideCode ) = true
499+ isiterabletable (:: OutsideCode ) = true
471500
472- Base . collect (source:: OutsideCode ) = collect (IteratorInterfaceExtensions . getiterator (source))
501+ collect (source:: OutsideCode ) = collect (getiterator (source))
473502
474- function IteratorInterfaceExtensions. getiterator (outside_code:: OutsideCode )
475- # TODO REVIEW
476- stricttypes = true
477- nullable = true
478-
479- stmt = SQLite. Stmt (outside_code. outside, translate (outside_code. code))
480- # bind!(stmt, values)
481- status = SQLite. execute! (stmt)
482- cols = SQLite. sqlite3_column_count (stmt. handle)
483- header = Vector {Symbol} (undef, cols)
484- types = Vector {Type} (undef, cols)
485- for i = 1 : cols
486- header[i] = Symbol (unsafe_string (SQLite. sqlite3_column_name (stmt. handle, i)))
503+ second ((value_1, value_2)) = value_2
504+
505+ name_and_type (handle, column_number, nullable = true , strict_types = true ) =
506+ Symbol (unsafe_string (sqlite3_column_name (handle, column_number))),
507+ if strict_types
508+ julia_type = juliatype (handle, column_number)
487509 if nullable
488- types[i] = stricttypes ? DataValue{SQLite . juliatype (stmt . handle, i)} : Any
510+ DataValue{julia_type}
489511 else
490- types[i] = stricttypes ? SQLite . juliatype (stmt . handle, i) : Any
512+ julia_type
491513 end
514+ else
515+ Any
492516 end
493- return SQLiteCursor {NamedTuple{Tuple(header), Tuple{types...}}} (stmt, Ref (status), Ref (0 ))
494- end
495517
496- function Base. show (io:: IO , source:: OutsideCode )
497- TableShowUtils. printtable (io, IteratorInterfaceExtensions. getiterator (source), " SQLite query result" )
498- end
499-
500- function Base. show (io:: IO , :: MIME"text/html" , source:: OutsideCode )
501- TableShowUtils. printHTMLtable (io, IteratorInterfaceExtensions. getiterator (source))
518+ function getiterator (outside_code:: OutsideCode )
519+ # TODO REVIEW
520+ statement = Stmt (outside_code. outside, translate (outside_code. code))
521+ # bind!(statement, values)
522+ status = execute! (statement)
523+ handle = statement. handle
524+ schema = ntuple (
525+ let handle = handle
526+ column_number -> name_and_type (handle, column_number)
527+ end ,
528+ sqlite3_column_count (handle)
529+ )
530+ SQLiteCursor{NamedTuple{
531+ Tuple (map_unrolled (first, schema)),
532+ Tuple{map_unrolled (second, schema)... }
533+ }}(statement, Ref (status), Ref (0 ))
502534end
503535
504- Base. Multimedia. showable (:: MIME"text/html" , source:: OutsideCode ) = true
536+ show (stream:: IO , source:: OutsideCode ) =
537+ printtable (stream, getiterator (source), " SQLite query result" )
505538
506- function Base . show (io :: IO , :: MIME"application/vnd.dataresource+json " , source:: OutsideCode )
507- TableShowUtils . printdataresource (io, IteratorInterfaceExtensions . getiterator ( source))
508- end
539+ showable ( :: MIME"text/html " , source:: OutsideCode ) = true
540+ show (stream :: IO , :: MIME"text/html" , source:: OutsideCode ) =
541+ printHTMLtable (stream, getiterator (source))
509542
510- Base. Multimedia. showable (:: MIME"application/vnd.dataresource+json" , source:: OutsideCode ) = true
543+ showable (:: MIME"application/vnd.dataresource+json" , source:: OutsideCode ) = true
544+ show (stream:: IO , :: MIME"application/vnd.dataresource+json" , source:: OutsideCode ) =
545+ printdataresource (stream, getiterator (source))
511546
512547end # module
0 commit comments