Minimum DB/GUI application for PicoLisp

From the interpreter:
Continue to fill the lack of information in Russian about the most interesting dialect of Lisp. Previous: Development of web applications in PicoLisp
The home page of the project: http://picolisp.com
a Few weeks ago my wife asked for a small application — online database for addresses and contact information for family members, relatives, friends and so on.

Normally, PicoLisp database contains objects of different classes. To handle them in the GUI should be able to search, create and delete objects, edit their properties.

Typical PicoLisp application implements the following features:
    the
  • menu Item for each object type or function
  • the search Dialog box, which appears when you choose the menu item the

  • Search for specific criteria in a dialog box
  • the
  • Then click on the found object or the "New" button to create a new object
  • the
  • a form will Appear where you can edit the object
  • the
  • Form has a "Delete" button to delete this object

But in the case of a simple database of addresses is unnecessary. There is only one class of objects. Fortunately, there's an easy way. First, there is no need for the menu. We can go directly to locations. Everything else can be treated one component of the GUI, +QueryChart.

Full listing at end of article.

the

data Model

we Define a class "Person" (for purposes of this article, in slightly abbreviated form) as:
 (class +Prs +Entity)
(rel nm (+Sn +IdxFold +String)) # Name
(rel adr (+IdxFold +String)) # Address
(rel em (+String)) # E-Mail
(rel tel (+String)) # Telephone
(rel dob (+Date)) # Date of birth
If necessary, the class can be easily extended.

Instead of separate properties for street, zip code, city, etc. we have one property in a free format for the full address. We define two non-unique index, one for username and one for the address. The index "name" supports fuzzy search (using Soundex algorithm similar names).

the

Options GUI

we Have only one GUI feature called work. It starts with the standard function app (= set session), action (= event handling forms), and html (= generate an HTML page), which is characteristic for each application PicoLisp. An optional feature of the <ping> uses JavaScript to create the events of keep-alive. the
 (de work ()
(app)
(action
(html 0 Ttl "@lib.css" NIL
(<ping> 2)
Then, as a measure of basic security, it shows the field for entering password in the first form, with the hard-coded password of "mypass". the
 (ifn *Login
(form NIL
(gui 'pw '(+PwField) 20 ,"Password")
(gui '(+Button) ,"login"
'(ifn (= "mypass" (val > (: home pw)))
(error"Permission denied")
(on *Login)
(url "!work") ) ) )
(the Actual application uses a full authentication user/password (using biblioteki "lib/adm.l"). We have omitted it here only for brevity)

In any case, it uses the global variable *Login, which is set by pressing button "login" in the case of coincidence of the password. In this case, the second displays the main form. the
 (form NIL
(<grid> "--."
"Name" (gui 'nm '(+DbHint +TextField) '(nm +Prs) 20)
(searchButton '(init> (: home query)))
"Address" (gui 'adr '(+DbHint +TextField) '(adr +Prs) 20)
(resetButton '(nm adr query)) )
It displays two search fields "Name" and "Address" and two buttons "Search" and "Reset". Search fields use the prefix class +DbHint to display the dropdown list with the relevant names already in the database. The "Reset" button clears all fields.

Now go to the "heart" of the GUI of this application. We use the class+QueryChart for a search of records and their creation and editing.

+QueryChart is used in all the dialogues of search. It uses a Pilog query to search for a given set of criteria, and displays unlimited possible number of outcomes while there is the matching items and the user continues to press the scroll button. the
 (gui 'query '(+QueryChart) 12

(quote
@Nm (val > (: home nm))
@Adr (val > (: home adr))
(select (@@)
((nm +Prs @Nm) (adr +Prs @Adr))
(tolr @Nm @@ nm)
(part @Adr @@ adr) ) ) )
the First argument (here 12) gives the initial number of matches to fill the table. The second argument is a Pilog query that uses the values in search fields "Name" and "Address" for fuzzy and partial searches. Refer to http://software-lab.de/doc/select.html for details.

There are three standard argument for class +Chart
 6
'((This) (list (: nm) (: adr) (em) (tel) (: dob)))
'((L D)
(cond
(D
(mapc
'((K V) (put!> D K V))
'(nm adr tel em dob)
L )
D )
((car L)
(new! '(+Prs) 'nm (car L)) ) ) ) )
: the number of columns (here 6) and the function put and get.

The class +Chart calls these functions whenever something happens in the GUI. the put function converts the logical content of the table row (here, the address of the object) in a physical display of the name, address, email, etc:
 '((This) (list (: nm) (: adr) (em) (tel) (: dob)))
the Argument This to put the function object, and it takes place in the list of values to a table row.

getfunction does the opposite, translating string values to object properties. It takes in L a list of values from the GUI (strings, numbers, dates, etc. entered by the user), and D — the address of the object in the database.
 '((L D)
Then it checks the expression cond if the object exists D.If so, it stores the values of L in the properties of the corresponding object, thus updating the database as needed:
 (D
(mapc
'((K V) (put!> D K V))
'(nm adr tel em dob)
L )
D )
If the object does not exist, but the first column of the table contains the name (which the user just entered),then a new object is created in the database with the same name:
 ((car L)
(new! '(+Prs) 'nm (car L)) ) ) ) )
That's all! This is all the logic needed to create and edit entries.

+Chart or +QueryChart — an internal object that implements the logic of this graphical interface.Now we need physical components to interact with the user.Place them in a table
 (<table> NIL (choTtl "Entries" '+Prs)
headings
 (quote
(NIL "Name")
(NIL "Address")
(NIL "E-Mail")
(NIL "Telephone")
(NIL "Date of birth") )
followed by 12 rows with text fields, email and phone
 (do 12
(<row> NIL
(gui 1 '(+TextField) 30)
(gui 2 '(+TextField) 40)
(gui 3 '(+MailField) 20)
(gui 4 '(+TelField) 15)
(gui 5 '(+DateField) 10)
(6 gui '(+DelRowButton)
'(lose!> (curr))
'(text "Delete Entry @1?" (curr 'nm)) ) ) ) )
note the button +DelRowButton in the last column.It can be used to remove the record from the database. It causes a confirmation dialog if a user really wants to delete the entry. However, when deleting many rows, it will not prompt the user next time.

And in the end displays four standard scroll buttons
 (scroll 12) ) ) ) ) )
it line by line, page by page, to scroll the contents of the table.

Initialization and startup

under the agreement, PicoLisp-the app provides two functions, main and go.The function main must initialize the working environment, and go must run the event loop of the GUI.
(de main ()
(locale "UK")
(pool "adr.db") )

(de go ()
(server 8080 "!work") )
locale is mainly necessary for proper processing of the field +TelField with phone numbers. You can provide your localization settings in the directory loc/.

If you copy the code below into a file "minDbGui.l" or download http://software-lab.de/minDbGui.l, you can run it in this way:
 $ pil minDbGui.l -main-go-wait
or in debug mode:
 $ pil minDbGui.l -main-go +


Source code
 # 11jan15abu
# (c) Software Lab. Alexander Burger

(allowed ()
"!work" "@lib.css" )

(load "@lib/http.l" "@lib/xhtml.l" "@lib/form.l")

(class +Prs +Entity)
(rel nm (+Sn +IdxFold +String)) # Name
(rel adr (+IdxFold +String)) # Address
(rel em (+String)) # E-Mail
(rel tel (+String)) # Telephone
(rel dob (+Date)) # Date of birth

(de work ()
(app)
(action
(html 0 Ttl "@lib.css" NIL
(<ping> 2)
(ifn *Login
(form NIL
(gui 'pw '(+PwField) 20 ,"Password")
(gui '(+Button) ,"login"
'(ifn (= "mypass" (val > (: home pw)))
(error"Permission denied")
(on *Login)
(url "!work") ) ) )
(form NIL
(<grid> "--."
"Name" (gui 'nm '(+DbHint +TextField) '(nm +Prs) 20)
(searchButton '(init> (: home query)))
"Address" (gui 'adr '(+DbHint +TextField) '(adr +Prs) 20)
(resetButton '(nm adr query)) )
(gui 'query '(+QueryChart) 12
'(goal
(quote
@Nm (val > (: home nm))
@Adr (val > (: home adr))
(select (@@)
((nm +Prs @Nm) (adr +Prs @Adr))
(tolr @Nm @@ nm)
(part @Adr @@ adr) ) ) )
6
'((This) (list (: nm) (: adr) (em) (tel) (: dob)))
'((L D)
(cond
(D
(mapc
'((K V) (put!> D K V))
'(nm adr tel em dob)
L )
D )
((car L)
(new! '(+Prs) 'nm (car L)) ) ) ) )
(<table> NIL (choTtl "Entries" '+Prs)
(quote
(NIL "Name")
(NIL "Address")
(NIL "E-Mail")
(NIL "Telephone")
(NIL "Date of birth") )
(do 12
(<row> NIL
(gui 1 '(+TextField) 30)
(gui 2 '(+TextField) 40)
(gui 3 '(+MailField) 20)
(gui 4 '(+TelField) 15)
(gui 5 '(+DateField) 10)
(6 gui '(+DelRowButton)
'(lose!> (curr))
'(text "Delete Entry @1?" (curr 'nm)) ) ) ) )
(scroll 12) ) ) ) ) )

(de main ()
(locale "UK")
(pool "adr.db") )

(de go ()
(server 8080 "!work") )

# vi:et:ts=3:sw=3
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

When the basin is small, or it's time to choose VPS server

Performance comparison of hierarchical models, Django and PostgreSQL

From Tomsk to Silicon Valley and Back