From f3dd6271bf1f459849a83a8611bf37b5e5a0ab9a Mon Sep 17 00:00:00 2001 From: crc Date: Wed, 1 May 2019 14:02:34 +0000 Subject: [PATCH] add example of using sqlite3 via pipes FossilOrigin-Name: c5afff65edeeeff084caba6726c10369770fea6f5d8cd9676fb6f6e82f808573 --- README.md | 17 ++++------ RELEASE_NOTES.md | 4 +++ example/sqlite3/sql.forth | 64 +++++++++++++++++++++++++++++++++++++ example/sqlite3/test.db | Bin 0 -> 19456 bytes example/sqlite3/test.forth | 42 ++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 example/sqlite3/sql.forth create mode 100644 example/sqlite3/test.db create mode 100644 example/sqlite3/test.forth 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 0000000000000000000000000000000000000000..452628e859ff4ac01009f4ab93b260e69704f1f1 GIT binary patch literal 19456 zcmeHNU2GiH6`p(V?#}P79Z$v+d$Qh1B7Ra5QlJq2gPl0euS4trO%bGPdlPT7@rK=X zqAdk_t5T$b@_i7SN-GuGrc_0hN*}691*uSpideJ~FCd^2r4RJnb7lsT zELDFbP}IB0c<-6}?LFUoJNM3ak3GG2SG`k<4>nszs-5^MBWEyX+!DtI=Uu}vd^qxO z*l^^M1K#k((#A)=t1;I9g%<&kV{aMa9>MrGprK!%paQazGs8-SeWlo`&NON>)y{mY z**wzD8usR?@zH(b@xIZqUE^_f`qKJbTwmza4%J%m(N_IPwbhLe*ShQCBh7`*d_2== z&a8{)s@}bdM)~&9S1Y1ULA9rmE zhB2@x7*c^_s=&8{u{~o>f!fPeJ5OyN+5b#tB2bBVH3Pi{FV~h^NGN#iQbDqATj+F0ogPimS!NA`~uvpTEhM_#gT6 z{O9}!{5$+n{vcoEhxna*C%=iW=Vji{1$&#l#$IC2v!Ah3>?AwEB)f;rvOCxWyN<18 zL(DVYH{LK_HC{A+ZT!SIWt@cc$;+L_r75?3YX9hDX-WlAZu#iszHNIZ_d9!W4a=!D z(1VQ&V_~kiV{~eKOKFmjMYX!ddoFi&6SAm~I|*4Bo7xUz?jU3Vkz<#;+f^Lo3b^`C zU?4^?`&LAXktBO*Jc&1N8=cxUKJ9H*aVSD!Fh;#$%3xH*z6ceAO@!#NboZYo`pLxC9Kitr%QFNKOncCM0nM1{bL~ z;2a-&Yx0K8f?-9VxLUQN;Us@?6@^K9x1z$($Lz%s?DLc4c3FkKdPcet!aPh}97dRz zsP7D^Fz_&Oi0wQk9z<9^O&m~|BzAnfGOs+beY7-y*W#7at6rA$L1w3q+Jg#LBHUn- z*)6I#@CGq8+5_L~Q$TbFk=K`sjs^kZG&$J<&r(>l1(9c^ePj(h3zFN)2H3s_u%deU z+fjDW$^h7O(M983W7ycoVK)Cs42v7Z-Qr&HZE>1E!`~CH@GtRAd=<>;SJ|`dUbdfY zWP$Or@wD-nam?74{7WZq_Fj>DY`8YY*BgCy7@12G^=f=;^-!Z)pPj9BI`yMvISB~c zRtT#{e?{)jMzBUk%%#oq)mEd{jyKQO8*{Z*yIYaFGK87W_drB)Cm}8}`ts$9xiq>k z*QycU*J)h)|g=(Et97w7i_+kYkV%^9_V zguPYyxR}f+ie7NA5OCR#cUGYj; z-k4Fx%RcAQD)KW~g51DhPie2o5P1Rj;CWx*u-uqY5NeDMS@Q0Pyp}EwCP80ck57-t z>oP!pe^0>m8K7M50jS8EGKRe8ZK|ICpJqdbctgA*elLC{eh5$hZ;G#qMKLF)#kkmr z&whvhoxjds;=kcP?!s=_85DR9bB%PxTg7uw5}v$R03#3!MgQBmZrOjl)DO->|BuO|pchXYeGMD~DV|Ns_yA(nqK((Ov}(ItN#x!3rGo4kbwj%Sqis zNutAwoP0(FT~=tXOuiuUSrDdF&}jMgN~A(A3+e#qU?tfsn{F&HPZE7rU{3ES&3{WUL;P8shM6zL0kK7_ffM?r75INpAhs-6X@{aAAJ)g) zruS{1Or{FW#WP=ixMC_qs1P(?lc|G%F#rq|5a0*CJ3O^#Vtfi_t(uF_73Z_j!;cs} zmyJ$Oj`Kzr+35bcqw{R^{*M@)WuupHtvPpeHUGKzr6JD15B<^#Xaz1P1uAlH=I~v$ z2RLu19LZY=q4vQR>@%i2HP}UMX&!~Y2RInx#St6r?b)nFV5-L<0f-qGDYeT*nAr&kPh34{v3e|?p8ec?Y zfy!gxR=X+=3S}g5oPt5*aEy?HDTT!(P8qaS92WYBL5q6(QYr3Hv0vy@44Q*kV&EKxzzzzEK=BKz9Tk%N#X5y)`a|ktVSb3xA5>8UQSwdHRP5)6RC?Sv zhWPmKr5gX&3+>r0q literal 0 HcmV?d00001 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 +~~~