Building data base aps with Rev (Tuviah M Snyder)

Sadhunathan Nadesan sadhu at castandcrew.com
Sun May 25 03:48:01 EDT 2003


| Subject: Re: Building data base aps with Rev
| From: Tuviah M Snyder <diskot123 at juno.com>
| Reply-To: use-revolution at lists.runrev.com
| 
| >| Unfortunatelyt, the query manager is not that advanced
| >| (yet) -- you'll have to employ the trick I described
| >| yesterday whereby you dynamically change the SQL of
| >| the 'detail' queries.
| You can use 
| revSetSQLOfQuery <queryname>,<newsql>
| Also note that as of RC1 you can now link menus, and checkboxes to
| queries.
| 


Yo!  Let's keep this thread alive.  Really happy to see you have joined
the discussion Tuviah.

Swami explained to me how to find the undocumented API so I was able to
browser around in there and understand a bit more of what Jan was up to.
I'm really hoping he will make us some simple master-detail form as an
example but I realize it is a lot to ask.

Now, I wanted to post my progress so far.  My first posts about DB aps
were .. I couldn't even connect!  I have come much farther so those
of you trying to write data base apps, keep trying!  It does work.

At this point I have progressed through the help of Jan, Geoff and others
to actually having a working applicaton.  Ok, it's rather trivial but
it's useful for me.  I will post the code (below) in case anyone might
find examples helpful.  Naturally the server name, login, password etc
have been changed to protect the innocent.

First I would like to mention a conclusion so far - the query builder
is ok at the testing state to prove you are connecting to a data base
and getting back data, after that, you have to write handlers to make it
actually do useful work so why not add one or two more lines of code to
include the query?  In other words, it's an ok start but ends up being
too much trouble without more functionality.  This is not exactly a
complaint, more like, expressing hope for more features in the future,
a truly useful query builder.

I found my programs kept hanging up when the query builder was trying
to do something automatic, it was erratic with queries sometimes being
connected, sometimes not.  So I dropped it and then things started
working much better.

Here's my real wish for the future - an automatic screen builder.
Just give this thing a record type, and connection info, and it builds
a card with all the fields from the record ready for data entry, labels
matching the field names, and add/modify/inquire/delete buttons ready
to go.  This is very realistic, meaning, technically feasible, not some
wild impossible dream.  Furthermore if you could drag tabbed areas around
that could be associated with separate records for the master-detail
type of data input/maintenance.  Ok, so enough with the wish list.

Next before putting code, here's the background.  I have a data base with
two tables, audio and transcript.  The audio table has 3 fields, audio
date, audio url, and title.  These point to audio files stored on the
web server.  The transcript table has 3 fields, audio url, transcript url,
and title.  Ok, title is redundant, its not 3rd normal form.  But helped
when populating with data.  Purpose of this is to connect the two.
The audio files were posted continuously for years in separate 'dated'
directories and then later on they began to be transcribed, and posted
somewhere else.  For someone listening to an audio file if they wanted
the transcript, no way to find it.  Therefore the data base was built
with an html query form allowing the user to search for the transcripts
for the audio files.

However, there is no user interface to this postgres data base except
doing everything manually writing sql queries.  That makes maintenance
a chore!  Enter REV.

Ok, so now we have an application with three cards, one that lists
the two tables in list fields side by side for comparison, one
for maintenance of the audio table, and one for the transcript table.
Each with add, modify, delete buttons, and some other buttons to view
the associated web page, etc.

I think an application like this could have come 80% 'out of the box'
with a button push but hey, I am delighted it could be coded by hand
instead.  

Without further ado, the code.  (You will kindly forgive poor style
and allow for newbie contributions, I hope!)  However, you can flame
me for  no comments.  And also it appears my editor has wrapped some
long lines splitting them in two, so  you will have to join them back if
you want to actually try this.  Sorry!

Aloha,
Sadhu

......................................

global pConnectionID, tSQLQuery, tCursor, tColumnNames
global useIPNumber

---------------------------------------------------------
on openDataBase
   global pConnectionID, tSQLQuery, tCursor, tColumnNames, useIPNumber

   -- note, i took out this chunk of code that connected automatically
   -- upon launch because if the connection wasn't working you had
   -- no control. You sat there twidling thumbs.
   --
   --  --  answer "Stand by, I'm connecting to your data base ..."
   --
   --  put revOpenDatabase("Postgresql","yourservercom","yourdb","yourname","yourpasswd") into pConnectionID
   --  if (pConnectionID) is a number then
   --    put "Your  data base on yourserver opened successfully with connection ID " into tResult
   --    put pConnectionID after tResult
   --    answer tResult
   --    go to card "listCard"
   --  else
   --    answer "Gosh darn, what's up?  The data base connection failed."

   ask "Do you want to try to connect by IP number?" with "put your IP here"
   if (it is not empty) then
     put it into useIPNumber
     put revOpenDatabase("Postgresql","yourservercom","yourdb","yourname","yourpasswd") 
into pConnectionID
     if (pConnectionID) is a number then
       put "Your Cybertalks data base on Gurudeva opened successfully with 
connection ID " into tResult
       put pConnectionID after tResult
       answer tResult
       go to card "listCard"
     else
       answer "THAT DID NOT WORK, tough luck baby ..."
       exit to top
     end if
   else
     answer "Ok, will not attempt a connection"
   end if


   --  repeat for each item thisDB in revOpenDatabases()
   --    answer "Open Data Bases are" && thisDB
   --  end repeat

end openDataBase

---------------------------------------------------------

on closeDataBase
   global pConnectionID, tColumnNames

repeat for each item thisDB in revOpenDatabases()
     revCloseDatabase thisDB
   end repeat

   repeat for each item thisDB in revOpenDatabases()
     answer "Open Data Bases are" && thisDB
   end repeat
end closeDataBase

-------------------------------------------------------

on closeStack
   closeDataBAse
end closeStack

-------------------------------------------------------
on openStack
   openDataBase
end openStack

-------------------------------------------------------

on refreshScreen
   global tCursor, tColumnNames, pConnectionID
   put revDatabaseColumnNames(tCursor) into tColumnNames
   revMoveToFirstRecord pConnectionID

   repeat for each item tColumnName in tColumnNames
     if there is a field tColumnName then
       put revDatabaseColumnNamed(tCursor, tColumnName)into field tColumnName
     end if
   end repeat
end refreshScreen

---------------------------------------------------------

on transcriptClear
   repeat for each item this_item in "transcript_url,audio_url,title,show 
web page"
     put empty  into field this_item
   end repeat
end transcriptClear

-----------------------------------------------------------

on audioClear
   repeat for each item this_item in "audio_date,audio_url,title,show web page"
     put empty  into field this_item
   end repeat
end audioClear

-----------------------------------------------------------

on testURL tURLField
   global useIPNumber

   put "http://" into tURL
   put useIPNumber after tURL
   put "put your path name in here" after tURL
   put field tURLField after tURL
   set the htmlText of field "Show Web Page" \
      to URL tURL
end testURL

-----------------------------------------------------------

on preOpenStack
   repeat for each item thisDB in revOpenDatabases()
     revCloseDatabase thisDB
   end repeat
   repeat for each item thisDB in revOpenDatabases()
     answer "Open Data Bases are" && thisDB
   end repeat

end preOpenStack

---------------------------------------------------------

on audioDateSearch
   global pConnectionID

   if (field "audio_date" is not a date) then answer "Date must be valid"
   else
     put "select * from audio where audio_date = '$AUDIO_DATE'" into tSQLQuery
     replace "$AUDIO_DATE" with field "audio_date" in tSQLQuery
     put revQueryDatabase(pConnectionID, tSQLQuery) into tCursor
     if (char 1 to 8 of tCursor is "revdberr") then
       put cr & "Data base error - EEEK - call support" & cr after tCursor
       answer tCursor
       audioClear
     else
       put revNumberOfRecords(tCursor) into tRecordCount
       if (tRecordCount =0) then
         answer "Sorry, I could not find any records matching" & cr & cr & 
field "audio_date" & cr & cr
       else
         put revDatabaseColumnNames(tCursor) into tColumnNames
         revMoveToFirstRecord pConnectionID
         audioClear
         refreshScreen
         if (tRecordCount is a number and tRecordCount > 1) then
           repeat for tRecordCount - 1 times
             revMoveToNextRecord tCursor
             visual effect scroll left
             clone this card
             refreshScreen
           end repeat
         end if
       end if
     end if
   end if
end audioDateSearch

---------------------------------------------------------

on audioURLSearch recordType
   --  global pConnectionID
   --
   if (field "audio_url" is empty) then
     answer "Audio URL must be filled in"

   else

     if (recordType = "audio") then
       put "select * from audio where audio_url ~* '$AUDIO_URL'" into tSQLQuery
     else
       if (recordType = "transcript") then
         put "select * from transcript where audio_url = '$AUDIO_URL'" into 
tSQLQuery
       else
         answer "Unknown record type"
       end if // transcrip type
     end if //record types

     replace "$AUDIO_URL" with field "audio_url" in tSQLQuery

     put revQueryDatabase(pConnectionID, tSQLQuery) into tCursor

     if (char 1 to 8 of tCursor is "revdberr") then
       put cr & "Data base error - EEEK - call support" & cr after tCursor
       answer tCursor


       if (recordType = "audio") then
         audioClear
       else
         transcriptClear
       end if


     else  // no db error
       put revNumberOfRecords(tCursor) into tRecordCount
       if (tRecordCount =0) then
         answer "Sorry, I could not find any records matching" & cr & cr & 
field "audio_url" & cr & cr
       else  // column names
         put revDatabaseColumnNames(tCursor) into tColumnNames
         revMoveToFirstRecord pConnectionID


         if (recordType = "audio") then
           audioClear
         else
           transcriptClear
         end if


         refreshScreen

         if (tRecordCount is a number and tRecordCount > 1) then
           repeat for tRecordCount - 1 times
             revMoveToNextRecord tCursor
             visual effect scroll left
             clone this card
             refreshScreen
           end repeat
         end if

       end if //no db error

     end if // record count 0


   end if //audio url empy
end audioURLSearch

---------------------------------------------------------
on audioList

   go to card "listCard"
   put empty into field "audio"
   put "select * from audio order by audio_url" into tSQLQuery
   put revQueryDatabase(pConnectionID, tSQLQuery) into tCursor
   put revNumberOfRecords(tCursor)into tRecordCount
   if (tRecordCount is zero) then
     answer "Sorry, your data base is empty" & cr
   else
     revMoveToFirstRecord tCursor -- start at the beginning
     repeat for tRecordCount times
       put revDatabaseColumnNamed(tCursor, "audio_date") & tab after field 
"audio"
       put revDatabaseColumnNamed(tCursor, "audio_url")  & tab after field 
"audio"
       put revDatabaseColumnNamed(tCursor, "title")      &  cr after field 
"audio"
       revMoveToNextRecord tCursor
     end repeat
   end if
end audioList

---------------------------------------------------------

on transcriptList

   go to card "listCard"
   put empty into field "transcript"
   put "select * from transcript order by audio_url" into tSQLQuery
   put revQueryDatabase(pConnectionID, tSQLQuery) into tCursor
   put revNumberOfRecords(tCursor)into tRecordCount
   if (tRecordCount is zero) then
     answer "Sorry, your data base is empty" & cr
   else
     revMoveToFirstRecord tCursor -- start at the beginning
     repeat for tRecordCount times
       put revDatabaseColumnNamed(tCursor, "transcript_url") & tab after 
field "transcript"
       put revDatabaseColumnNamed(tCursor, "audio_url")  & tab after field 
"transcript"
       put revDatabaseColumnNamed(tCursor, "title")      &  cr after field 
"transcript"
       revMoveToNextRecord tCursor
     end repeat
   end if
end transcriptList

---------------------------------------------------------

on transcriptDelete
   global pConnectionID

   if (field "title" is empty or field "audio_url" is empty or field 
"transcript_url" is empty) then
     answer "All fields must be filled in to process a delete"
   else
     put "delete from transcript where transcript_url = '$TRANSCRIPT_URL' 
and title = '$TITLE' and audio_url = '$AUDIO_URL'" into tSQLQuery
     replace "$TRANSCRIPT_URL" with field "transcript_url" in tSQLQuery
     replace "$AUDIO_URL" with field "audio_url" in tSQLQuery
     replace "$TITLE" with field "title" in tSQLQuery
     revExecuteSQL pConnectionID, tSQLQuery
     put the result into deleteError

     if (deleteError is a number and deleteError >= 1) then
       answer "Your deletion was successful on" & cr & deleteError & field 
"transcript_url"
       transcriptClear
     else
       answer "Sorry, I could not delete that record" & cr & cr & field 
"transcript_url"
     end if
   end if
end transcriptDelete

---------------------------------------------------------


on audioDelete
   global pConnectionID

   if (field "title" is empty or field "audio_url" is empty or field 
"audio_date" is empty) then
     answer "All fields must be filled in to process a delete"
   else
     put "delete from audio where audio_date = '$AUDIO_DATE' and title = 
'$TITLE' and audio_url = '$AUDIO_URL'" into tSQLQuery
     replace "$AUDIO_DATE" with field "audio_date" in tSQLQuery
     replace "$AUDIO_URL" with field "audio_url" in tSQLQuery
     replace "$TITLE" with field "title" in tSQLQuery
     revExecuteSQL pConnectionID, tSQLQuery
     put the result into deleteError

     if (deleteError is a number and deleteError >= 1) then
       answer "Your deletion was successful on" & cr & deleteError & field 
"audio_date"
       audioClear
     else
       answer "Sorry, I could not delete that record" & cr & cr & field 
"audio_date"
     end if
   end if
end audioDelete

---------------------------------------------------------

on transcriptAdd
   global pConnectionID

   put "insert into transcript (transcript_url, audio_url, title) values 
('$TRANSCRIPT_URL', '$AUDIO_URL', '$TITLE');" into tSQLQuery
   replace "$TRANSCRIPT_URL" with field "transcript_url" in tSQLQuery
   replace "$AUDIO_URL" with field "audio_url" in tSQLQuery
   replace "$TITLE" with field "tITLE" in tSQLQuery
   revExecuteSQL pConnectionID, tSQLQuery
   put the result into addError

   if (addError is a number and addError >= 1) then
     answer "Your Addition was successful on" & cr & addError & field 
"transcript_url"
   else
     answer "Sorry, I could not add that record" & cr & addError & field 
"transcript_url"
   end if
end transcriptAdd

---------------------------------------------------------

on audioAdd
   global pConnectionID

   put "insert into audio (audio_date, audio_url, title) values 
('$AUDIO_DATE', '$AUDIO_URL', '$TITLE');" into tSQLQuery
   replace "$AUDIO_DATE" with field "audio_date" in tSQLQuery
   replace "$AUDIO_URL" with field "audio_url" in tSQLQuery
   replace "$TITLE" with field "tITLE" in tSQLQuery
   revExecuteSQL pConnectionID, tSQLQuery
   put the result into addError

   if (addError is a number and addError >= 1) then
     answer "Your Addition was successful on" & cr & addError & field 
"audio_date"
   else
     answer "Sorry, I could not add that record" & cr & addError & field 
"audio_date"
   end if
end audioAdd

---------------------------------------------------------

on transcriptChange
   global pConnectionID

   put "update transcript set audio_url = '$AUDIO_URL', transcript_url = 
'$TRANSCRIPT_URL', title = '$TITLE' where transcript_url = 
'$TRANSCRIPT_URL'" into tSQLQuery

   replace "$TRANSCRIPT_URL" with field "transcript_url" in tSQLQuery
   replace "$AUDIO_URL" with field "audio_url" in tSQLQuery
   replace "$TITLE" with field "title" in tSQLQuery
   revExecuteSQL pConnectionID, tSQLQuery
   put the result into changeError

   if (changeError is a number and changeError >= 1) then
     answer "Your Modification was successful on" & cr & changeError & " 
records"  & cr & field "transcript_url"
   else
     answer "Sorry, I could not modify that record" & cr & changeError & 
field "transcript_url"
   end if
end transcriptChange

---------------------------------------------------------

on audioChange
   global pConnectionID

   put "update audio set audio_url = '$AUDIO_URL', audio_date = 
'$AUDIO_DATE', title = '$TITLE' where audio_date = '$AUDIO_DATE'" into 
tSQLQuery

   replace "$AUDIO_DATE" with field "audio_date" in tSQLQuery
   replace "$AUDIO_URL" with field "audio_url" in tSQLQuery
   replace "$TITLE" with field "title" in tSQLQuery
   revExecuteSQL pConnectionID, tSQLQuery
   put the result into changeError

   if (changeError is a number and changeError >= 1) then
     answer "Your Modification was successful on" & cr & changeError & " 
records"  & cr & field "audio_date"
   else
     answer "Sorry, I could not modify that record" & cr & changeError & 
field "audio_date"
   end if
end audioChange

---------------------------------------------------------

on listSearch recordType

   if (recordType is "audio") then
     put the selectedText of field "audio" into searchPattern
     put getFieldOne(searchPattern) into audioDate
     retrieveAudioByDate audioDate
   else
     if (recordType is "transcript") then
       put the selectedText of field "transcript" into searchPattern
       put getFieldOne(searchPattern) into transcriptURL
       retrieveTranscriptByURL transcriptURL
     end if
   end if

end listSearch

------------------------------------------------------------
on retrieveTranscriptByURL transcriptURL
   global pConnectionID

   go to card "transcriptCard"
   put "select * from transcript where transcript_url = '$TRANSCRIPT_URL'" 
into tSQLQuery
   replace "$TRANSCRIPT_URL" with transcriptURL in tSQLQuery
   put revQueryDatabase(pConnectionID, tSQLQuery) into tCursor

   if (char 1 to 8 of tCursor is "revdberr") then
     put cr & cr & "Sorry, I could not find that entry." & cr & cr after 
tCursor
     answer tCursor
     transcriptClear
   else
     refreshScreen
   end if
end retrieveTranscriptByURL

-------------------------------------------------------------

on retrieveAudioByDate audioDate
   global pConnectionID, tCursor

   go to card "audioCard"
     put "select * from audio where audio_date = '$AUDIO_DATE'" into tSQLQuery
   replace "$AUDIO_DATE" with audioDate in tSQLQuery
   put revQueryDatabase(pConnectionID, tSQLQuery) into tCursor

   if (char 1 to 8 of tCursor is "revdberr") then
     put cr & cr & "Sorry, I could not find that entry." & cr & cr after 
tCursor
     answer tCursor
     audioClear
   else
     refreshScreen
   end if
end retrieveAudioByDate

-------------------------------------------------------------

function getFieldOne thisLine
   -- return the contents of the first cell of a line in a table
   if (thisLine contains tab) then //valid type of line
     put offset(tab, thisLine) into pipeOff
     put char 1 to (pipeOff  - 1) of thisLine into fieldOne
     return fieldOne
   else
     return "Error"
   end if
end getFieldOne

------------------------------------------------------------




More information about the use-livecode mailing list