[REBOL] REBOL Relational Object-oriented Database
From: louisaturk::eudoramail::com at: 20-Jun-2001 4:09
Dear Carl and anyone else that might be able to help,
I am hoping you can spare a few minutes to help me past a few problems. I
am still working on a very simple character-based user interface for your
database functions---see my unfinished work below. Once it is finished, I
may try to put a View GUI on it, but for right now I want to keep it real
simple so I can understand what is going on. I know I could use MySQL and
avoid having to learn this, but I have reasons for wanting a full REBOL
relational object-oriented dbms.
I would really appreciate it if Carl Sassenrath would help with the core
database functions as he is the most knowledgeable about the inner workings
of REBOL, and it is he that provided the original functions that showed me
the great potential of REBOL to do what I need done. I think that many
others will also appreciate his concise, elegant contributions of basic
building components to help us learn basic, practical skills. If Carl
would please take out a few minutes to whip out the remaining needed
function, I would be most thankful. Sorry to impose on him like this, but
ask and ye shall receive.
"Ye have not because ye ask not."
You might want to do the program below, add a few records, and then step
through the menu choices so that you can see what I am talking about in the
following questions:
1. How can a field in a record be edited (not just replaced)? Carl, a
function please.
2. What is the purpose of the 2 in the remove-data function?
3. Every time the insert-data function is called a box opens asking me for
permission to write to disk. How do I prevent this in such a way as to not
open my computer up for possible invasion? (Later: well, its not asking me
now, but I don't know why.)
4. How do I print out a list of all or some of the fields in all of the
records (say for a report)? I am using probe right now so I can at least
see what is in the database, but I need formatted reports.
5. How can this database be related to a second database by say the phone
number field? How can the data from both databases be accessed at once?
6. How can data be exported from a database as a comma separated file.
7. How can data be imported into a database from a comma separated file.
8. What is the maximum number of records practical to search with REBOL on
a computer with 512 MB of RAM? With 20,000 records or so what would
performance be like?
9. How can I get instant action upon pressing a key (say for a menu
choice), without having to also hit the enter key? I hate to have to hit 2
keys when hitting one would work just as well.
Thanks,
Louis
REBOL [Title: "REBOL Relational Object DBMS"
Date: "19 June 2001"
Version: 0.01
File: %db.r
Author: "Carl Sessenrath and Louis A. Turk"
Email: [louisaturk--eudoramail--com]
Language: 'English
Purpose: "A simple but complete relational object-oriented dbms."
Comments: {Carl Sessenrath made these object oriented database
management system functions as an example to teach me,
Louis A. Turk, how to program an object database myself.
Many thanks Carl! The comments about features below are
mostly Carl's, edited by Louis for this script header.
Features:
1. The db works from memory. Load-data brings it into
memory
where the find, remove and other functions operate on
it.
So, you have to load it first, or at least insert-data a
few times to create some data records.
2. You can expand or reduce the record definition without
corrupting or affecting the database.
3. If you expect to grow this database to a large size,
you will want to MAKE HASH! the database when you
load it. make the hash after the database is created
(after the foreach loop).
database: make hash! database
But, don't worry about that until your database gets big.
For a few hundred names, you don't need it.
4. The functions work like this:
rec: find-data [bob--example--com]
print rec/name
print rec/phone
etc.
remove-data [bob--example--com]
save-data ; write back to disk
insert-data [kit--example--com] "Kitty Carson" none
http:/www.a.com
save-data ; write back to disk
5. You can use NONE for any missing value above. You don't
need to do the save-data each time... but you must do it
sooner or later.
6. The data is organized (keyed) by email. To change an
email address, but keep the rest of the record intact,
use the function change-data. Let's examine change-data:
change-data: func [email-old email-new /local record] [
record: find database email-old
if none? record [alert reform ["Missing record:"
email-old] exit]
insert clear first record email-new ; see note below
]
Note: This is subtle, so should be noted... I'm
clearing
out the actual memory string for the old email, then
inserting
the new string into it.
Also, this string is shared. It is used both in the
database
block (as the key) and in the record object
itself. So changing
it here will change it in both places.
Please send any bug reports or features you add to:
[louisaturk--eudoramail--com]
} ; End of Comments
] ;End of Rebol Script Header
;#!/rebol/rebol -cs
;open/allow %data.r [read write]
db-file: %data.r
record: context [name: email: phone: web: none] ;Place the none value in
all the varables.
database: []
load-data: has [data] [
data: load/all db-file
clear database
foreach item data [
item: make record item
repend database [item/email item]
]
]
change-data: func [email-old email-new /local record] [
record: find database email-old
if none? record [alert reform ["Missing record:" email-old] exit]
insert clear first record email-new ; See note in feature #6 above.
]
save-data: has [data] [
data: copy []
foreach [key obj] database [
append/only data third obj
]
save db-file data
]
find-data: func [email] [select database email]
remove-data: func [email] [remove/part find database email 2]
insert-data: func [email' name' phone' web'] [
repend database [
email'
make record [
email: email'
name: name'
phone: phone'
web: web'
]
]
]
{Below is a simple character based user interface for REBOL/Core added by
Louis A. Turk}
load-data
forever [
cls: "^(1B)[J" ; Clear the Screen.
print cls
print "^/ REBOL RELATIONAL OBJECT-ORIENTED DBMS" ; ^/ is a line feed.
print " =====================================^/"
print " 1. Add Record."
print " 2. Edit a Field In a Record."
print " 3. Delete Record."
print " 4. Change Email Address Only."
print " 5. Print Reports."
print " 6. Exit.^/"
choice: ask " Enter the number of your choice: "
if choice = "1" [
forever [
print cls
print " ADD A RECORD"
print " ============^/"
email: ask " Email Address : "
if email = "" [break]
rec: find database email
if not rec = none [
print cls
print " Record is already in database.^/"
ask " Hit Any Key To Continue."
break
]
name: ask " Full Name : "
phone: ask " Area Code & Phone# : "
web: ask " Website URL : "
insert-data email name phone web
save-data
] ; End forever loop for choice 1
] ; End if choice 1
if choice = "2" [
forever [
print cls
print " EDIT A FIELD IN A RECORD"
print " ========================^/"
email-old: ask " Email Address: "
record: find database email-old
if record = none [
print cls
print "^/ Missing record: " email-old
ask "^/ Hit Any Key To Continue."
break
]
record: find-data email-old
print ["^/ 1. Email : " record/email]
print [" 2. Name : " record/name]
print [" 3. Phone : " record/phone]
print [" 4. URL : " record/web "^/"]
choice: ask " Enter number of field to change: "
; I'm using this method of accessing fields since records in
databases
; to be expanded from this one may have 10 to 30 fields with
only
; one usually needing editing.
if choice = "1" [
print cls
print " EDIT EMAIL ADDRESS"
print " ==================^/"
ask "New function needed here to edit the email field."
save-data
choice: "0"
;print ["The email address has been changed to "
email-new "."]
]
if choice = "2" [
print cls
print " CHANGE NAME"
print " ===========^/"
name-old: record/name
ask "New function needed here to edit the name field."
save-data
choice: "0"
]
if choice = "3" [
print cls
print " CHANGE PHONE"
print " ===========^/"
ask "New function needed here to edit the phone number field."
save-data
choice: "0"
]
if choice = "4" [
print cls
print " CHANGE URL"
print " ===========^/"
ask "New function needed here to edit the url field."
save-data
choice: "0"
]
] ; End forever loop
] ; End if choice 2
if choice = "3" [
forever [
print cls
print " DELETE A RECORD"
print " ===============^/"
email-old: ask " Email Address Of Record To Delete: "
if email-old = "" [
break
] ; End if.
record: find database email-old
if none? record [
print cls
print " Record not found.^/"
ask " Hit Any Key To Continue."
break
]
remove-data email-old
save-data
] ; End forever loop for choice 3.
] ; End if choice 3
if choice = "4" [
forever [
print cls
print " CHANGE EMAIL ADDRESS ONLY"
print " ==========================^/"
email-old: ask " Email Address To Be Changed: "
record: find database email-old
if none? record [
print cls
print "Missing record: " email-old
ask "Hit Any Key To Continue."
break
]
email-new: ask " New Email Address: "
change-data email-old email-new
save-data
] ; End forever loop for choice 4
] ; End if choice 4
if choice = "5" [
print cls
print " PRINT FORMATTED REPORTS"
print " =======================^/"
print "I need to know how to print formatted reports, instead of
just using probe as below.^/"
probe database
ask "Press Enter To Continue."
]
if choice = "6" [
break
] ; End if choice 6
if choice > "6" [
print "Error: Choice must be number between 1 and 6.^/"
ask "Hit Any Key To Continue."
] ; End if for choice 6.
] ; End forever loop for main program.