diff --git a/README.md b/README.md index 8ee1561..2d41f0a 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,7 @@ For most systems (FreeBSD, NetBSD, OpenBSD, macOS, Linux): make -You will need a standard C compiler and `make`. The `retro-ri` -binary requires (n)curses, but you can ignore any build/link -errors by doing: - - make -kis - -If you are building on an older Linux system and are running -into problems, try using the alternative Makefile: - - make -f Makefile.linux +You will need a standard C compiler and `make`. ## Executables @@ -77,6 +68,12 @@ fenced blocks: Anything outside the fenced blocks will be ignored. +## Documentation + +The primary documentation is in RETRO-Book.md (and the formatted +RETRO-Book.html.) Additional notes can be found in the `doc` +directory. + ## Commercial Versions I provide proprietary versions of RETRO for iOS and macOS. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index fcdc5a8..9b85b59 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -20,3 +20,7 @@ This is the changelog for the development builds of Retro. - updated Linux build instructions - updated Starting instructions + +## Examples + +- add sqlite3 wrapper diff --git a/example/sqlite3/sql.forth b/example/sqlite3/sql.forth new file mode 100644 index 0000000..62bd0cf --- /dev/null +++ b/example/sqlite3/sql.forth @@ -0,0 +1,64 @@ +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:th fetch s:to-number ; + :column (a-s) #1 a:th fetch @Table '%s:%s s:format ; + :generate (ns-) d:create , [ fetch a:th fetch ] does ; +---reveal--- + :sql:accessors-for (s-) + set-table get-columns + [ sql:split-line [ id ] [ column ] bi generate ] a:for-each ; +}} +~~~ diff --git a/example/sqlite3/test.db b/example/sqlite3/test.db new file mode 100644 index 0000000..452628e Binary files /dev/null and b/example/sqlite3/test.db differ diff --git a/example/sqlite3/test.forth b/example/sqlite3/test.forth new file mode 100644 index 0000000..96a486c --- /dev/null +++ b/example/sqlite3/test.forth @@ -0,0 +1,42 @@ +This is a test case, using an sqlite3 database to track time off +requests at my employer. + +The database schema is: + + CREATE TABLE pto(id integer primary key, + month blob, start blob, end blob, year blob, who blob, + reason blob, status blob); + + +Requests are a range, with a start and ending day. Requests for a single +day off have identical start and end days. + +~~~ +'sql.forth include (include_the_sqlite3_wrapper +'test.db sql:set-database (set_the_database_file +'pto sql:accessors-for (generate_accessors_for_each_column_in_"pto" +~~~ + +I can query for approved requests (status=y) in the current month. + +~~~ +[ 'pto FROM '* SELECT 'status="y"_AND_month=5_ORDER_BY_start WHERE ] sql:statement sql:query +~~~ + +And then iterate over the results, generating some readable output like: + + Charles Childers + From: 2019-4-18 through 2019-4-22 + +(This part should be refactored to aid in readability, but this works +ok for a quick test.) + +~~~ +[ sql:split-line + dup pto:who s:put nl + [ &pto:start &pto:month &pto:year tri + '\tFrom:_%s-%s-%s_through_ s:format s:put ] sip + [ &pto:end &pto:month &pto:year tri + '%s-%s-%s\n s:format s:put ] sip + drop ] a:for-each +~~~