@@ -4,13 +4,15 @@ import Base: !, &, |, ==, !=, coalesce, getproperty, in, isequal, isless, ismiss
44using Base: Generator, NamedTuple, tail
55import Base. Iterators: drop, take
66using Base. Meta: quot
7- import DataFrames: DataFrame
87import MacroTools
98using MacroTools: @capture
109import QueryOperators
1110import QueryOperators: orderby, query
1211import SQLite
1312using SQLite: columns, DB, tables
13+ import IteratorInterfaceExtensions, TableTraits
14+ using DataValues
15+ import TableShowUtils
1416
1517map_unrolled (call, variables:: Tuple{} ) = ()
1618map_unrolled (call, variables) =
@@ -56,14 +58,6 @@ get_column_names(outside::DB, table_name) =
5658 as_symbols (columns (outside, String (table_name)). name)
5759export get_column_names
5860
59- """
60- submit_to(outside, text)
61-
62- Send `text` to `outside`
63- """
64- submit_to (outside:: DB , text) = DataFrame (Query (outside, text))
65- export submit_to
66-
6761"""
6862 abstract type OutsideTables{Outside} end
6963
@@ -408,14 +402,11 @@ column_or_columns(outside_code::OutsideCode) = (translate(outside_code.code),)
408402
409403# SQLite interface
410404
411- using DataFrames: DataFrame
412-
413405to_symbols (them) = map_unrolled (Symbol, (them... ,))
414406
415407get_table_names (database:: DB ) = to_symbols (tables (database). name)
416408get_column_names (database:: DB , table_name) =
417409 to_symbols (SQLite. columns (database, String (table_name)). name)
418- submit_to (database:: DB , text) = DataFrame (SQLite. Query (database, text))
419410
420411# dispatch
421412
@@ -444,10 +435,75 @@ translate(code::Expr) =
444435# collect
445436query (outside_code:: OutsideCode ) = outside_code
446437
447- DataFrame (outside_code:: OutsideCode ) =
448- submit_to (
449- outside_code. outside,
450- translate (outside_code. code)
451- )
438+ struct SQLiteCursor{T}
439+ stmt:: SQLite.Stmt
440+ status:: Base.RefValue{Cint}
441+ cur_row:: Base.RefValue{Int}
442+ end
443+
444+ Base. eltype (q:: SQLiteCursor{T} ) where {T} = T
445+ Base. IteratorSize (:: Type{<:SQLiteCursor} ) = Base. SizeUnknown ()
446+
447+ function isdone (q:: SQLiteCursor )
448+ st = q. status[]
449+ st == SQLite. SQLITE_DONE && return true
450+ st == SQLite. SQLITE_ROW || SQLite. sqliteerror (q. stmt. db)
451+ return false
452+ end
453+
454+ function SQLite. getvalue (q:: SQLiteCursor , col:: Int , :: Type{T} ) where {T}
455+ handle = q. stmt. handle
456+ t = SQLite. sqlite3_column_type (handle, col)
457+ if t == SQLite. SQLITE_NULL
458+ return T ()
459+ else
460+ TT = SQLite. juliatype (t) # native SQLite Int, Float, and Text types
461+ return SQLite. sqlitevalue (ifelse (TT === Any && ! isbitstype (T), T, TT), handle, col)
462+ end
463+ end
464+
465+
466+
467+ function Base. iterate (q:: SQLiteCursor{NT} ) where {NT}
468+ isdone (q) && return nothing
469+ nt = SQLite. generate_namedtuple (NT, q)
470+ q. cur_row[] = 1
471+ return nt, 1
472+ end
473+
474+ function Base. iterate (q:: SQLiteCursor{NT} , state) where {NT}
475+ state != q. cur_row[] && error (" FOO" )
476+ q. status[] = SQLite. sqlite3_step (q. stmt. handle)
477+ isdone (q) && return nothing
478+ nt = SQLite. generate_namedtuple (NT, q)
479+ q. cur_row[] = state + 1
480+ return nt, state + 1
481+ end
482+
483+ IteratorInterfaceExtensions. isiterable (:: OutsideCode ) = true
484+ TableTraits. isiterabletable (:: OutsideCode ) = true
485+
486+ function IteratorInterfaceExtensions. getiterator (outside_code:: OutsideCode )
487+ # TODO REVIEW
488+ stricttypes = true
489+ nullable = true
490+
491+ stmt = SQLite. Stmt (outside_code. outside, translate (outside_code. code))
492+ # bind!(stmt, values)
493+ status = SQLite. execute! (stmt)
494+ cols = SQLite. sqlite3_column_count (stmt. handle)
495+ header = Vector {Symbol} (undef, cols)
496+ types = Vector {Type} (undef, cols)
497+ for i = 1 : cols
498+ header[i] = Symbol (unsafe_string (SQLite. sqlite3_column_name (stmt. handle, i)))
499+ if nullable
500+ types[i] = stricttypes ? DataValue{SQLite. juliatype (stmt. handle, i)} : Any
501+ else
502+ types[i] = stricttypes ? SQLite. juliatype (stmt. handle, i) : Any
503+ end
504+ end
505+ return SQLiteCursor {NamedTuple{Tuple(header), Tuple{types...}}} (stmt, Ref (status), Ref (0 ))
506+ end
507+
452508
453509end # module
0 commit comments