retroforth/example/sqlite3/sql.forth

65 lines
1.8 KiB
Text
Raw Normal View History

This is an experimental set of words allowing use of sqlite3
within RETRO.
Do not use this in anything public facing. It doesn't do any
error checking, input validation, or make any attempt to be
remotely secure. It's also slow due to its design.
A lot of work is needed for this to actually be useful outside
of my tests.
This works by opening pipes to sqlite3, capturing the output,
and then processing it from within RETRO. This is slow, but
allows me to not need to deal with adding an FFI, and is
adaptable to similar external tools.
~~~
{{
'Database var
:setup here buffer:set ;
:pipe @Database 'sqlite3_%s_'%s' s:format file:R unix:popen ;
---reveal---
:sql:set-database s:keep !Database ;
:sql:query
[ setup pipe [ dup file:read dup buffer:add n:-zero? ] while unix:pclose ] buffer:preserve here ASCII:LF s:tokenize dup v:dec ;
:sql:split-line (s-a) $| s:tokenize ;
}}
~~~
# Construct an SQL Statement
~~~
{{
{ 'Action 'Choice 'Table 'Clause } [ var ] a:for-each
:clear { &Action &Choice &Table &Clause } [ v:off ] a:for-each ;
---reveal---
:SELECT 'SELECT !Action !Choice ;
:DROP 'DROP !Action ;
:FROM !Table ;
:WHERE !Clause ;
:sql:statement (q-s)
clear call @Clause n:-zero?
[ @Clause @Table @Choice @Action '%s_%s_FROM_%s_WHERE_%s ]
[ @Table @Choice @Action '%s_%s_FROM_%s ] choose
s:format ;
}}
~~~
# Generate Accessor Words
~~~
{{
'Table var
:set-table (s-s) dup s:keep !Table ;
:get-columns (s-a) 'PRAGMA_table\_info("%s") s:format sql:query ;
:id (a-n) #0 a:fetch s:to-number ;
:column (a-s) #1 a:fetch @Table '%s:%s s:format ;
:generate (ns-) d:create , [ fetch a:fetch ] does ;
---reveal---
:sql:accessors-for (s-)
set-table get-columns
[ sql:split-line [ id ] [ column ] bi generate ] a:for-each ;
}}
~~~