Simple database: Difference between revisions

Applesoft BASIC
(Undo revision 231640 by Gerard Schildberger (talk) Restored most of the page and attempted to put Gerard's changes back in...)
(Applesoft BASIC)
(39 intermediate revisions by 15 users not shown)
Line 37:
*   [[Take notes on the command line]]
<br><br>
 
=={{header|11l}}==
{{trans|Kotlin}}
 
<syntaxhighlight lang="11l">T Item
String name, date, category
 
F (name, date, category)
.name = name
.date = date
.category = category
 
F String()
R .name‘, ’(.date)‘, ’(.category)
 
V db_filename = ‘simdb.csv’
 
F load()
[Item] db
L(line) File(:db_filename).read().rtrim("\n").split("\n")
V item = line.split(‘, ’)
db.append(Item(item[0], item[1], item[2]))
R db
 
F store(item)
File(:db_filename, APPEND).write(String(item)"\n")
 
F printUsage()
print(|‘
Usage:
simdb cmd [categoryName]
add add item, followed by optional category
latest print last added item(s), followed by optional category
all print all
For instance: add "some item name" "some category name’)
 
F addItem(args)
I args.len < 2
printUsage()
R
 
V date = Time().strftime(‘%Y-%m-%d %H:%M:%S’)
V cat = I args.len == 3 {args[2]} E ‘none’
store(Item(args[1], date, cat))
 
F printLatest(a)
V db = load()
I db.empty
print(‘No entries in database.’)
R
 
I a.len == 2
L(item) reversed(db)
I item.category == a[1]
print(item)
L.break
L.was_no_break
print(‘There are no items for category '’a[1]‘'’)
E
print(db.last)
 
F printAll()
V db = load()
I db.empty
print(‘No entries in database.’)
R
 
L(item) db
print(item)
 
:start:
I :argv.len C 2..4
S :argv[1].lowercase()
‘add’
addItem(:argv[1..])
‘latest’
printLatest(:argv[1..])
‘all’
printAll()
E
printUsage()
E
printUsage()</syntaxhighlight>
 
{{out}}
The same as in Kotlin.
 
=={{header|BASIC}}==
==={{header|Applesoft BASIC}}===
This program relies on DOS 3.3 to read and write the simple database as a text file on disk. Running the program with no options displays help on how to run the program with the various options.
<syntaxhighlight lang="gwbasic"> 10 FOR I = 0 TO 255:C = PEEK (512 + I):EOL = C = 0 OR C = 141: IF NOT EOL THEN C$ = C$ + CHR$ (C): NEXT I: STOP
20 DOS = (C = 141) * 128:AC = 0: FOR C = I - 1 TO 0 STEP - 1: IF PEEK (512 + C) = ASC (",") + DOS THEN AC = AC + 1: NEXT C
30 D$ = CHR$ (4):M$ = CHR$ (13): READ P$,C$(1),C$(2),C$(3),C$(4):F$ = P$ + ".TXT": ON AC GOTO 100,40,40,40: GOTO 500USAGE
40 C = 0: PRINT D$"OPEN "F$: PRINT D$"READ "F$
50 ONERR GOTO 80
60 INPUT "";NA$,GE$,DA$
70 C = C + 1: GOTO 60
80 POKE 216,0: IF PEEK (222) = 5 THEN PRINT D$"CLOSE "F$: ON AC GOTO 100,200,300,400
90 RESUME
 
REM ADD
100 PRINT M$C$(AC)M$
110 INPUT " NAME: ";NAME$
120 INPUT " GENRE: ";GENRE$
130 INPUT "DATE YYYY-MM-DD: ";DA$
140 PRINT D$"OPEN "F$: PRINT D$"APPEND "F$: PRINT D$"WRITE "F$: PRINT NAME$","GENRE$","DA$: PRINT D$"CLOSE "F$
150 GOTO 600"DONE
 
REM LATEST
200 PRINT M$C$(AC)M$M$" NAME: "NA$M$"GENRE: "GE$M$" DATE: "DA$;
210 GOTO 600"DONE
 
REM LATEST OF EACH GENRE
300 DIM NA$(C),GE$(C),DA$(C):GC = 0: PRINT D$"OPEN "F$: PRINT D$"READ "F$: FOR I = 1 TO C: GOSUB 350:NA$(J) = NA$:GE$(J) = GE$:DA$(J) = DA$: NEXT I: PRINT D$"CLOSE "F$
310 PRINT M$C$(AC)M$: FOR I = 1 TO GC: PRINT M$NA$(I)","GE$(I)","DA$(I);: NEXT I
320 GOTO 600"DONE
350 INPUT "";NA$,GE$,DA$: FOR J = 1 TO GC: IF GE$ = GE$(J) THEN RETURN
360 NEXT J:GC = GC + 1:J = GC: RETURN
 
REM ALL SORTED BY DATE
400 DIM NA$(C),GE$(C),DA$(C),DA(C):DC = 0: PRINT D$"OPEN "F$: PRINT D$"READ "F$: FOR I = 1 TO C: GOSUB 450:NA$(DC) = NA$:GE$(DC) = GE$:DA$(DC) = DA$:DA(DC) = DA(DP):DA(DP) = DC: NEXT I: PRINT D$"CLOSE "F$
410 PRINT M$C$(AC)M$:DA = DA(0): FOR I = 1 TO DC: PRINT M$NA$(DA)","GE$(DA)","DA$(DA);:DA = DA(DA): NEXT I
420 GOTO 600"DONE
450 DP = 0: INPUT "";NA$,GE$,DA$: IF NOT DC THEN DC = 1: RETURN
460 FOR J = 1 TO DC:DA = DA(DP): IF DA$ > DA$(DA) THEN DP = DA:DA = DA(DA): NEXT J:DA = DP
470 DC = DC + 1: RETURN
 
REM USAGE
500 DATA "SIMPLE DATABASE"
510 DATA " RUN: , ADD A NEW ENTRY"
520 DATA " RUN: ,, PRINT THE LATEST ENTRY"
530 DATA " RUN: ,,, LATEST OF EACH GENRE"
540 DATA " RUN: ,,,, ALL SORTED BY DATE"
550 IF NOT DOS THEN C$ = "RUN " + P$
560 PRINT "USAGE:"M$" "C$" ,..."M$" OR";: FOR I = 1 TO 4: PRINT M$C$(I);: NEXT I
 
REM DONE
600 END</syntaxhighlight>
==={{header|Run BASIC}}===
<syntaxhighlight lang="runbasic">sqliteconnect #sql, "f:\client.db" ' Connect to the DB
 
' -------------------------------
' show user options
' -------------------------------
[sho]
cls ' clear screen
button #acd, "Add a new entry", [add]
button #acd, "Print the latest entry", [last]
button #acd, "Print the latest entry for each category", [lastCat]
button #acd, "Print all entries sorted by a date", [date]
button #ex, "Exit", [exit]
wait
 
' ------------------------------------
' add a new entry (user input screen)
' ------------------------------------
[add]
cls ' clear the screen
html "<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 bgcolor=wheat>"
html "<TR align=center BGCOLOR=tan><TD colspan=2>Client Maintenance</TD></TR><TR>"
html "<TD bgcolor=tan align=right>Client Num</TD><TD>"
textbox #clientNum,clientNum$,5
 
html "</TD></TR><TR><TD bgcolor=tan align=right>Name</TD><TD>"
textbox #name,name$,30
 
html "</TD></TR><TR><TD bgcolor=tan align=right>Client Date</TD><TD>"
textbox #clientDate,clientDate$,19
 
html "</TD></TR><TR><TD bgcolor=tan align=right>Category</TD><TD>"
textbox #category,category$,10
 
html "</TD></TR><TR><TR bgcolor=tan><TD colspan=2 ALIGN=CENTER>"
button #acd, "Add", [addIt]
button #ex, "Exit", [sho]
html "</TD></TR></TABLE>"
wait
 
' ---------------------------------------------
' Get data from the screen
' ---------------------------------------------
[addIt]
clientNum = #clientNum contents$()
name$ = trim$(#name contents$())
clientDate$ = trim$(#clientDate contents$())
category$ = trim$(#category contents$())
dbVals$ = clientNum;",'";name$;"','";clientDate$;"','";category$;"'"
sql$ = "INSERT into client VALUES ("; dbVals$ ; ")"
#sql execute(sql$)
goto [sho]
 
' ------------------------------------
' Select last entry
' ------------------------------------
[last]
sql$ = "SELECT *,client.rowid as rowid FROM client ORDER BY rowid desc LIMIT 1"
what$ = "---- Last Entry ----"
goto [shoQuery]
 
' ------------------------------------
' Select by category (Last date only)
' ------------------------------------
[lastCat]
sql$ = "SELECT * FROM client
WHERE client.clientDate = (SELECT max(c.clientDate)
FROM client as c WHERE c.category = client.category)
ORDER BY category"
what$ = "---- Last Category Sequence ----"
goto [shoQuery]
 
' ------------------------------------
' Select by date
' ------------------------------------
[date]
sql$ = "SELECT * FROM client ORDER BY clientDate"
what$ = "---- By Date ----"
 
[shoQuery]
cls
print what$
html "<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>"
html "<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>" ' heading
#sql execute(sql$)
WHILE #sql hasanswer()
#row = #sql #nextrow()
clientNum = #row clientNum()
name$ = #row name$()
clientDate$ = #row clientDate$()
category$ = #row category$()
 
html "<TR><TD align=right>";clientNum;"</TD><TD>";name$;"</TD><TD>";clientDate$;"</TD><TD>";category$;"</TD></TR>"
WEND
html "</TABLE>"
button #c, "Continue", [sho]
wait
 
' ------ the end -------
[exit]
end</syntaxhighlight>
Output:
 
---- User Input ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 bgcolor=wheat>
<TR align=center BGCOLOR=tan><TD colspan=2>Client Maintenance</TD></TR>
<TR><TD bgcolor=tan align=right>Client Num</TD><TD>5</TD></TR>
<TR><TD bgcolor=tan align=right>Name</TD><TD>Dawnridge Winery</TD></TR>
<TR><TD bgcolor=tan align=right>Client Date</TD><TD>2008-06-18 22:16</TD></TR>
<TR><TD bgcolor=tan align=right>Category</TD><TD>wine</TD></TR>
<TR><TR bgcolor=tan><TD colspan=2 ALIGN=CENTER>[Add] [Exit]</TD></TR></TABLE>
 
---- Last Entry ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>
<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>
<TR><TD align=right>5</TD><TD>Dawnridge Winery</TD><TD>2008-06-18 22:16</TD><TD>wine</TD></TR></TABLE>
 
---- Last category Sequence ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>
<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>
<TR><TD align=right>1</TD><TD>Home Sales</TD><TD>2012-01-01 10;20</TD><TD>broker</TD></TR>
<TR><TD align=right>4</TD><TD>Back 40 Equipment</TD><TD>2009-09-18 20:18</TD><TD>farm</TD></TR>
<TR><TD align=right>3</TD><TD>Floral Designs</TD><TD>2010-10-14 09:16</TD><TD>flowers</TD></TR>
<TR><TD align=right>2</TD><TD>Best Foods</TD><TD>2011-02-02 12:33</TD><TD>food</TD></TR>
<TR><TD align=right>5</TD><TD>Dawnridge Winery</TD><TD>2008-06-18 22:16</TD><TD>wine</TD></TR></TABLE>
 
---- Date Sequence ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>
<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>
<TR><TD align=right>5</TD><TD>Dawnridge Winery</TD><TD>2008-06-18 22;16</TD><TD>wine</TD></TR>
<TR><TD align=right>4</TD><TD>Back 40 Equipment</TD><TD>2009-09-18 20:18</TD><TD>farm</TD></TR>
<TR><TD align=right>3</TD><TD>Floral Designs</TD><TD>2010-10-14 09:16</TD><TD>flowers</TD></TR>
<TR><TD align=right>2</TD><TD>Best Foods</TD><TD>2011-02-02 12:33</TD><TD>food</TD></TR>
<TR><TD align=right>1</TD><TD>Home Sales</TD><TD>2012-01-01 10:20</TD><TD>broker</TD></TR></TABLE>
 
=={{header|Bracmat}}==
This is a rather minimal solution. The program is run from the command line of the operating system, in this example the Windows command prompt. The program is stored in a file called 'sdb':
<langsyntaxhighlight lang="bracmat"> whl
' ( arg$:?command
& ( get'db
Line 119 ⟶ 391:
)
);
</syntaxhighlight>
</lang>
First we add some records, a some ships that arrived at the harbour in Rotterdam today.
<pre>bracmat "get$sdb" add name "CORONA BULKER" tag "BULK CARRIER" date "2014.10.21.04:00"
Line 161 ⟶ 433:
* "CRUDE OIL"^(("2014.10.10.02:00"."HS MEDEA")+("2014.10.10.12:00".GHAZAL));</pre>
 
Use is made of Bracmat's automatic normalization of algebraic formula to turn the data into a hierarchical structure, with the tag as the top level and the date/time immediately below that level.
 
=={{header|C}}==
Line 172 ⟶ 444:
"Treasure Beach","Argus","Jemky","09-22-1999","Lancast"
 
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <stdlib.h> /* malloc */
#include <string.h> /* strlen */
Line 364 ⟶ 636:
}
else return ((*p1)->date > (*p2)->date);
}</langsyntaxhighlight>
 
=={{header|C sharp|C#}}==
<syntaxhighlight lang="c sharp">
using System;
using System.IO;
 
namespace Simple_database
{
class Program
{
public static void Main(string[] args)
{
//
// For appropriate use of this program
// use standard Windows Command Processor or cmd.exe
//
// Create cmd.bat file at the same folder with executive version
// of program Simple_database.exe, so when started, the correct
// file path will be automatically set to cmd console.
//
// Start notepad, write only cmd.exe and save file as cmd.bat
//
// To start cmd just double click at cmd.bat file.
//
//
//
// Console application command line start command
//
// application name.exe [argument] [argument parameters]
//
//
// Command line argument followed by parameters
//
// [a] - Add new entry
//
// ["data1"]["data2"]["data3"]...["data n"]
//
// ["data1"] - Data category !
// ["data2"] - Data
// ["data3"] - Data
//
//
// NOTICE !
//
// First parameter is taken for data category.
//
//
//
// Command line argument with no parameters
//
// [p1] - Print the latest entry
//
// [p2] - Print the latest entry for each category
//
// [p3] - Print all entries sorted by a date
//
//
//
//
// Command line example
//
// Small_database.exe [a] ["home"] ["+398125465458"] ["My tel number"]
//
// Small_database.exe [a] ["office"] ["+398222789000"] ["Boss"]
//
// Small_database.exe [a] [cd] ["Action movie"] ["Movie title"]
// Small_database.exe [a] [cd] ["SF movie"] ["Movie title"]
// Small_database.exe [a] [dvd] ["Action movie"] ["Movie title"]
//
//
// NOTICE !
//
// Brackets and space between arguments and parameters are necessary.
// Quotes must be used when parameters have more than one word.
//
// If not used as shown in examples, program will show error message.
//
//
//
// Check command line for arguments
//
//
if(args.Length==0)
{
Console.WriteLine();
Console.WriteLine(" Missing Argument Error. ");
Console.WriteLine();
}
else
{
switch (args[0])
{
case "[a]" : Add_New_Entry(args);
break;
case "[p1]": Print_Document("Print the latest entry.txt");
break;
case "[p2]": Print_Document("Print the latest entry for each category.txt");
break;
case "[p3]": Print_Document("Print all entries sorted by a date.txt");
break;
default :
{
Console.WriteLine();
Console.WriteLine(" Incorrect Argument Error. ");
Console.WriteLine();
}
break;
}
}
}
static void Add_New_Entry(string [] args)
{
//
// Check parameters
//
//
// Minimum one parameter, category
//
if(args.Length==1)
{
Console.WriteLine();
Console.WriteLine(" Missing Parameters Error..... ");
Console.WriteLine();
}
else
{
bool parameters_ok = true;
foreach (string a in args)
{
if(!a.StartsWith("[") || !a.EndsWith("]"))
{
parameters_ok = !parameters_ok;
break;
}
}
//
// Add new entry to Data base document
//
if(parameters_ok)
{
//
//
//
Console.WriteLine();
Console.WriteLine(" Parameters are ok..... ");
Console.WriteLine();
Console.WriteLine(" Writing new entry to database..... ");
//
// Create new Data base entry
//
args[0] = string.Empty;
string line = string.Empty;
foreach (string a in args)
{
line+=a;
}
line+="[" + DateTime.Now.ToString() + "]";
args[0] = "[" + DateTime.Now.ToString() + "]";
//
// Write entry to Data base
//
StreamWriter w = new StreamWriter("Data base.txt",true);
w.WriteLine(line);
//
// Close and dispose stream writer
//
w.Close();
w.Dispose();
//
//
//
Console.WriteLine();
Console.WriteLine(" New entry is written to database. ");
 
Create_Print_Documents(args);
//
//
//
Console.WriteLine();
Console.WriteLine(" Add new entry command executed. ");
//
//
//
}
else
{
Console.WriteLine();
Console.WriteLine(" ! Parameters are not ok ! ");
Console.WriteLine();
Console.WriteLine(" Add new entry command is not executed. ");
Console.WriteLine();
}
}
}
static void Create_Print_Documents(string [] args)
{
//
//
//
Console.WriteLine();
Console.WriteLine(" Creating new print documents. ");
//
// Create "Print all entries sorted by a date.txt"
//
File.Copy("Data base.txt","Print all entries sorted by a date.txt",true);
//
//
//
Console.WriteLine();
Console.WriteLine(" Print all entries sorted by a date.txt created. ");
//
// Create "Print the latest entry.txt"
//
//
// Create new entry
//
string line = string.Empty;
foreach (string a in args)
{
line+=a;
}
//
StreamWriter w = new StreamWriter("Print the latest entry.txt");
//
w.WriteLine(line);
//
w.Close();
w.Dispose();
//
//
//
Console.WriteLine();
Console.WriteLine(" Print the latest entry.txt created. ");
//
// Create "Print the latest entry for each category.txt"
//
string latest_entry = string.Empty;
foreach (string a in args)
{
latest_entry+=a;
}
if(!File.Exists("Print the latest entry for each category.txt"))
{
File.WriteAllText("Print the latest entry for each category.txt",latest_entry);
}
else
{
StreamReader r = new StreamReader("Print the latest entry for each category.txt");
//
w = new StreamWriter("Print the latest entry for each category 1.txt",true);
//
line = string.Empty;
//
while(!r.EndOfStream)
{
line = r.ReadLine();
if(line.Contains(args[1].ToString()))
{
w.WriteLine(latest_entry);
latest_entry = "ok";
}
else
{
w.WriteLine(line);
}
}
// add new category
if(latest_entry != "ok")
w.WriteLine(latest_entry);
//
w.Close();
w.Dispose();
//
r.Close();
r.Dispose();
//
File.Copy("Print the latest entry for each category 1.txt",
"Print the latest entry for each category.txt",true);
//
File.Delete("Print the latest entry for each category 1.txt");
//
//
//
Console.WriteLine();
Console.WriteLine(" Print the latest entry for each category.txt created. ");
Console.WriteLine();
}
}
static void Print_Document(string file_name)
{
//
// Print document
//
Console.WriteLine();
Console.WriteLine(file_name.Replace(".txt","")+ " : ");
Console.WriteLine();
//
StreamReader r = new StreamReader(file_name);
//
string line = string.Empty;
//
line = r.ReadToEnd();
//
Console.WriteLine(line);
//
r.Close();
r.Dispose();
//
//
//
}
}
}
</syntaxhighlight>
{{out| Program Input and Output}}
<pre>
Data base can be filled by creating cmd.bat file with following contents:
</pre>
<pre>
Simple_database.exe [a] [cd] ["Action"] ["Movie name"]
Simple_database.exe [a] [cd] ["Fiction"] ["Movie name"]
Simple_database.exe [a] [cd] ["Drama"] ["Movie name"]
Simple_database.exe [a] [cd] ["SF"] ["Movie name"]
Simple_database.exe [a] [cd] ["Comedy"] ["Movie name"]
Simple_database.exe [a] [cd] ["Horor"] ["Movie name"]
 
Simple_database.exe [a] [dvd] ["Action"] ["Movie name"] ["Fiction"] ["Movie name"]
Simple_database.exe [a] [dvd] ["SF"] ["Movie name"] ["SF"] ["Movie name"]
Simple_database.exe [a] [dvd] ["Drama"] ["Movie name"] ["Action"] ["Movie name"]
Simple_database.exe [a] [dvd] ["Comedy"] ["Movie name"] ["SF"] ["Movie name"]
Simple_database.exe [a] [dvd] ["Horor"] ["Movie name"] ["Fiction"] ["Movie name"]
 
pause
</pre>
<pre>
When data base is formed use start command with parameters for data base query:
 
C:\PROJECTS\Roseta\Simple database\Simple database\bin\Debug>Simple_database.exe [p2]
 
And the result is
</pre>
<pre>
Print the latest entry for each category :
 
[28.3.2018 15:06:18][cd][Horor][Movie name]
[28.3.2018 15:06:18][dvd][Horor][Movie name][Fiction][Movie name]
</pre>
 
=={{header|COBOL}}==
This is a souped-up version of the task from [[Take notes on the command line]]. It stores the current date, a tag, a title and a note as an entry in a file. The database produced is not particularly human-readable or easy to modify, but it is in a well-structured format.
{{works with|OpenCOBOL}}
<langsyntaxhighlight lang="cobol"> IDENTIFICATION DIVISION.
PROGRAM-ID. simple-database.
 
Line 630 ⟶ 1,262:
"The title should be specified as shown for -c."
DISPLAY " -t - Show all the entries sorted by tag."
.</langsyntaxhighlight>
 
Sample session:
Line 666 ⟶ 1,298:
 
=={{header|Common Lisp}}==
{{incorrect|Lisp|"add" operation fails to create database if it doesn't exist.}}
A tool to track the episodes you have watched in a series.
Tested with [[SBCL]] but should work with other implementations.
 
Tested with [[Common Lisp]]. ''(Save the code below as db.lisp)''
Run from the commandline as:
sbcl --script watch.lisp
 
<syntaxhighlight lang="lisp">(defvar *db* nil)
Without arguments the function <code>(watch-list)</code> is invoked to show the last episode of each series.
With the argument <code>add</code> the function <code>(watch-add)</code> will allow you to add a new episode with series name, episode title, episode number and date watched. If the series does not yet exist, you will be asked if you want to create it.
 
(defvar *db-cat* (make-hash-table :test 'equal))
This code is also available under the GNU GPLv3.
<lang lisp>(defvar *db* nil)
 
(defvar *db-file* "db.txt")
(defstruct series description tags episodes)
 
(defstruct item
(defstruct (episode (:print-function print-episode-struct))
"this is the unit of data stored/displayed in *db*"
series title season episode part date tags)
(title " ")
(category "default")
(date (progn (get-universal-time))))
 
(defun formatset-ymd category(datenew-item)
(setf (gethash (item-category new-item) *db-cat*) 't))
(format nil "~{~a.~a.~a~}" date))
 
(defun printfind-episodeitem-structin-db (ep stream&optional levelcategory)
(letif ((*print-pretty*null nil)category)
(format stream (ifcar *print-escapedb*)
(find category *db* :key #'item-category :test #'string=)))
"#s(episode~@{~*~@[ :~1:*~a ~s~]~})"
"~32<~*~a~; ~*~@[~d-~]~*~d~> ~45<~*~@[~a ~]~*~@[(~a) ~]~;~*~@[(~a)~]~>~*~@[ (~{~a~^ ~})~]")
:series (episode-series ep)
:season (episode-season ep)
:episode (episode-episode ep)
:title (episode-title ep)
:part (episode-part ep)
:date (if *print-escape*
(episode-date ep)
(when (episode-date ep)
(format-ymd (episode-date ep))))
:tags (episode-tags ep))))
 
(defun getscan-valuecategory (key alist)
"scan categories from an existing database -- after reading it from disk"
(cdr (assoc key alist)))
(dolist (itm *db*) (set-category itm)))
 
(defun pr-univ-time (utime)
 
(defun get-latest (database)
(when database
(cons (car (series-episodes (cdar database))) (get-latest (cdr database)))))
 
(defun get-all (database)
(when database
(append (series-episodes (cdar database)) (get-all (cdr database)))))
 
(defun compare-date (a b)
(cond ((not a) t)
((not b) nil)
((= (first a) (first b))
(compare-date (rest a) (rest b)))
(t (< (first a) (first b)))))
 
(defun compare-by-date (a b)
(compare-date (episode-date a) (episode-date b)))
 
(defun prompt-read (prompt &optional default)
(format *query-io* "~a~@[ (~a)~]: " prompt default)
(force-output *query-io*)
(let ((answer (read-line *query-io*)))
(if (string= answer "")
default
answer)))
 
(defun split (seperator string)
(loop for i = 0 then (1+ j)
as j = (search seperator string :start2 i)
collect (subseq string i j)
while j))
 
(defun get-current-date ()
(multiple-value-bind
(second minute hour date month year day-of-week dst-p tz)
(getdecode-decodeduniversal-time utime)
(declare (ignore second minute hour day-of-week dst-p tz))
(format nil "~4,'0d-~2,'0d-~2,'0d ~2,'0d:~2,'0d:~2,'0d" year month date hour minute second)))
(list date month year)))
 
(defun pr (&optional (item (find-item-in-db)) (stream t))
"print an item"
(when item
(format stream "~a: (~a) (~a)~%"
(item-title item)
(item-category item)
(pr-univ-time (item-date item)))))
 
(defun parsepr-dateper-category (date)
"print the latest item from each category"
(reverse (mapcar #'parse-integer (split "." date))))
(loop for k being the hash-keys in *db-cat*
do (pr (find-item-in-db k))))
 
(defun parsepr-tagsall (tags)
"print all the items, *db* is sorted by time."
(when (and tags (string-not-equal "" tags))
(mapcar #'interndolist (splititm "*db*) " (string-upcasepr tags))itm)))
 
(defun parsepr-numberall-categories (number&optional (stream t))
(loop for k being the hash-keys in *db-cat*
(if (stringp number)
do (format stream "(~a) " k)))
(parse-integer number :junk-allowed t)
number))
(defun insert-item (item)
"insert item into database in a time sorted list. okay for a small list, as per spec."
(let ((first-item (car *db*)) (new-itm item))
(set-category new-itm)
(push new-itm *db*)
(when (and first-item (>= (item-date new-itm) (item-date first-item)))
(setf *db* (sort *db* #'> :key #'item-date)))
*db*))
 
(defun promptread-fordb-episodefrom-file (&optional last(file *db-file*))
(with-open-file (in file :if-does-not-exist nil)
(when (not last)
(when in
(setf last (make-episode)))
(with-standard-io-syntax (setf *db* (read in)))
(let* ((series (prompt-read "Series Title" (episode-series last)))
(title (promptscan-read "Title"category))))
(season (parse-number (prompt-read "Season" (episode-season last))))
(episode (parse-number (prompt-read "Episode"
(if (eq (episode-season last) season)
(1+ (episode-episode last))
1))))
(part (parse-number (prompt-read "Part"
(when (and (episode-part last)
(or (eq (episode-season last) season)
(eq (episode-part last) 1)))
(1+ (episode-part last))))))
(date (parse-date (prompt-read "Date watched" (format-ymd (get-current-date)))))
(tags (parse-tags (prompt-read "Tags"))))
(make-episode
:series series
:title title
:season season
:episode episode
:part part
:date date
:tags tags)))
 
(defun parsesave-integerdb-quietlyto-file (&restoptional args(file *db-file*))
(with-open-file (out file :direction :output :if-exists :supersede)
(ignore-errors (apply #'parse-integer args)))
(with-standard-io-syntax
(print *db* out))))
 
(defun getdel-next-versiondb (basename)
(setf *db* nil)
(flet ((parse-version (pathname)
(save-db-to-file))
(or (parse-integer-quietly
(string-left-trim (file-namestring basename)
(file-namestring pathname))
:start 1) 0)))
(let* ((files (directory (format nil "~A,*" (namestring basename))))
(max (if files
(reduce #'max files :key #'parse-version)
0)))
(merge-pathnames (format nil "~a,~d" (file-namestring basename) (1+ max))
basename))))
 
(defun savedel-dbitem (dbfile databaseitm)
(let ((file (proberead-db-from-file dbfile)))
(setf *db* (remove itm *db* :key #'item-title :test #'string=))
(rename-file file (get-next-version file))
(save-db-to-file))
(with-open-file (out file :direction :output)
(with-standard-io-syntax
(let ((*print-case* :downcase))
(pprint database out))))))
 
(defun watchadd-saveitem-to-db (dbfileargs)
(saveread-db dbfile *db*)-from-file)
(insert-item (make-item :title (first args) :category (second args)))
(save-db-to-file))
 
(defun loadhelp-dbmenu (dbfile)
(format t "clisp db.lisp ~{~15T~a~^~% ~}"
(with-open-file (in dbfile)
'("delete <item-name> ------------------- delete an item"
(with-standard-io-syntax
"delete-all --------------------------- delete the database"
(read in))))
"insert <item-name> <item-category> --- insert an item with its category"
"show --------------------------------- shows the latest inserted item"
"show-categories ---------------------- show all categories"
"show-all ----------------------------- show all items"
"show-per-category -------------------- show the latest item per category")))
 
(defun getdb-seriescmd-run (name databaseargs)
(cdrcond (assoc(and name(> database(length :testargs) #'string-1) (equal (first args) "delete"))
(del-item (second args)))
((equal (first args) "delete-all") (del-db))
((and (> (length args) 2) (equal (first args) "insert"))
(add-item-to-db (rest args)))
((equal (first args) "show") (read-db-from-file) (pr))
((equal (first args) "show-categories") (read-db-from-file) (pr-all-categories))
((equal (first args) "show-all") (read-db-from-file) (pr-all))
((equal (first args) "show-per-category") (read-db-from-file) (pr-per-category))
(t (help-menu))))
 
;; modified https://rosettacode.org/wiki/Command-line_arguments#Common_Lisp
(defun get-episode-list (series database)
(defun db-argv ()
(series-episodes (get-series series database)))
(or
#+clisp ext:*args*
#+sbcl (cdr sb-ext:*posix-argv*)
#+allegro (cdr (sys:command-line-arguments))
#+lispworks (cdr sys:*line-arguments-list*)
nil))
 
(db-cmd-run (db-argv))</syntaxhighlight>
(defun print-series (title series)
(format t "~&~30a ~@[ (~{~a~^ ~})~]~%~@[ ~a~%~]" title (series-tags series)
(series-description series))
(format t "~{~& ~a~%~}" (reverse (series-episodes series))))
 
(defun watch-series (title)
(let ((series (get-series title *db*)))
(when series
(print-series title series))))
 
Help menu:
(defun print-all-series (database)
$ clisp db.lisp
(loop for (title . series)
clisp db.lisp delete <item-name> ------------------- delete an item
in (sort database #'(lambda (a b)(compare-by-date (car (series-episodes (cdr a)))
delete-all --------------------------- delete the database
(car (series-episodes (cdr b))))))
insert <item-name> <item-category> --- insert an item with its category
do (terpri) (print-series title series)))
show --------------------------------- shows the latest inserted item
show-categories ---------------------- show all categories
show-all ----------------------------- show all items
show-per-category -------------------- show the latest item per category
 
Here are a few steps to add a few titles, and their categories:
(defun watch-all-series ()
$ clisp db.lisp insert "title-vinyl-1" "vinyl"
(print-all-series *db*))
$ clisp db.lisp insert "title-cd-1" "cd"
$ clisp db.lisp insert "title-dvd-1" "dvd"
$ clisp db.lisp insert "title-tape-1" "tape"
$ clisp db.lisp insert "title-tape-2" "tape"
 
Here is the very latest entry in the db:
(defun watch-latest ()
$ clisp db.lisp show
(format t "~{~& ~a~%~}" (sort (get-latest *db*) #'compare-by-date)))
title-tape-2: (tape) (2017-04-04 20:19:06)
 
Here is a (sorted time wise) list of all the entries:
(defun timeline-all (database)
$ clisp db.lisp show-all
(let* ((all (get-all database))
title-tape-2: (tape) (2017-04-04 20:19:06)
(max (length all))
title-tape-1: (tape) (2017-04-04 20:19:00)
(count max)
title-dvd-1: (dvd) (2017-04-04 20:18:55)
(all-series-names nil)
title-cd-1: (cd) (2017-04-04 20:18:48)
(all-series (make-hash-table :test 'equal)))
title-vinyl-1: (vinyl) (2017-04-04 20:18:41)
(loop for episode in (reverse (sort all #'compare-by-date))
do (unless (gethash (episode-series episode) all-series)
(setf (gethash (episode-series episode) all-series)
(make-array max :initial-element nil))
(setf all-series-names
(cons (episode-series episode) all-series-names)))
(setf (elt (gethash (episode-series episode) all-series) (decf count))
episode))
(values all-series all-series-names max)))
 
Here is the latest entry for each category:
(defun watch-timeline ()
$ clisp db.lisp show-per-category
(multiple-value-bind (all-series all-series-names max) (timeline-all *db*)
title-vinyl-1: (vinyl) (2017-04-04 20:18:41)
(loop for series in all-series-names
title-cd-1: (cd) (2017-04-04 20:18:48)
do (format t "~30a (~{~:[ ~;•~]~})~%" series
title-dvd-1: (dvd) (2017-04-04 20:18:55)
(coerce (subseq (gethash series all-series) (- max 60)) 'list)))))
title-tape-2: (tape) (2017-04-04 20:19:06)
 
Here is the list of all categories:
(defun watch-timelinec ()
$ clisp db.lisp show-categories
(multiple-value-bind (all-series all-series-names max) (timeline-all *db*)
(vinyl) (cd) (dvd) (tape)
(let ((chart (make-array (list (length all-series-names) max) :initial-element nil))
(newcol 0)
(oldrow -1))
(loop for oldcol upto (1- max)
do (loop for series in all-series-names
for row from 0 upto (length all-series-names)
do (when (elt (gethash series all-series) oldcol)
(when (<= row oldrow)
(incf newcol))
(setf (aref chart row newcol)
(elt (gethash series all-series) oldcol))
(setf oldrow row))))
(loop for series in all-series-names
for i from 0 upto (length all-series-names)
do (format t "~30a (" series)
(loop for j from (- newcol 60) upto newcol
do (format t "~:[ ~;•~]" (aref chart i j))
(if (= j newcol)
(format t ")~%")))))))
 
To delete an entry:
(defun watch-timelinev ()
$ clisp db.lisp delete "title-tape-2"
(multiple-value-bind (all-series all-series-names max) (timeline-all *db*)
(loop for series in all-series-names
counting series into count
do (format t "~va ~30a~%" count " " series ))
(loop for i from 0 upto (1- max)
do (let ((episode nil))
(loop for series in all-series-names
do (format t "~:[ ~;~:*~02a~]"
(when (elt (gethash series all-series) i)
(setf episode (elt (gethash series all-series) i))
(episode-episode episode))))
(format t " (~a)~%" (episode-series episode))))))
 
To delete all entries:
(defun watch-all ()
$ clisp db.lisp delete-all
(format t "~{~& ~a~%~}" (sort (get-all *db*) #'compare-by-date)))
 
(defun watch-new-series (&key name description tags)
(cdar (push (cons name (make-series :description description :tags tags)) *db*)))
 
(defun get-or-add-series (name database)
(or (get-series name database)
(if (y-or-n-p "Add new series? [y/n]: ")
(watch-new-series
:name name
:description (prompt-read "Description" name)
:tags (parse-tags (prompt-read "Tags" "active")))
nil)))
 
(defun watch-add ()
(let* ((series (loop thereis (get-or-add-series (prompt-read "Series") *db*)))
(episode (prompt-for-episode (car (series-episodes series)))))
(push episode (series-episodes series))))
 
(defun watch-series-names ()
(format T "~{~& ~a~%~}"
(sort (mapcar #'car *db*)
(lambda (series1 series2)
(compare-by-date (car (series-episodes (get-value series1 *db*)))
(car (series-episodes (get-value series2 *db*))))))))
 
(defun exact-match (term text)
(string-equal (format nil "~{~a~^ ~}" term) text))
 
(defun fuzzy-match (term text)
(loop for word in term
when (search word text :test 'string-equal)
collect it))
 
(defun match-tags (term tags)
(intersection (mapcar #'intern term) tags))
 
(defun search-title (term database)
(loop for episode in (get-all database)
when (exact-match term (episode-title episode))
collect episode))
 
(defun search-tags (term database)
(sort (loop for episode in (get-all database)
for matches = (match-tags term (episode-tags episode))
when matches collect (list (length matches) episode))
#'> :key #'car))
 
(defun search-title-fuzzy (term database)
(sort (loop for episode in (get-all database)
for matches = (fuzzy-match term (episode-title episode))
when matches collect (list (length matches) episode))
#'> :key #'car))
 
(defun search-all (term database)
(let ((exact-results '())
(fuzzy-results '())
(tag-results '()))
(dolist (episode (get-all database))
(cond ((exact-match term (episode-title episode))
(push episode exact-results))
((fuzzy-match term (episode-title episode))
(push episode fuzzy-results))
((match-tags term (episode-tags episode))
(push episode tag-results))))
(append (sort exact-results #'compare-by-date)
(sort tag-results #'compare-by-date)
(sort fuzzy-results #'compare-by-date))))
 
(defun watch-search (term)
(format t "~{~& ~a~%~}" (search-all term *db*)))
 
(defun list-all-tags (database)
(let ((tags (make-hash-table :test 'equal)))
(dolist (tag (apply #'append (mapcar #'episode-tags (get-all database))))
(setf (gethash tag tags) (1+ (or (gethash tag tags) 0))))
tags))
 
(defun watch-tags ()
(maphash #'(lambda (tag count) (format t "~a (~d) " tag count))
(list-all-tags *db*))
(terpri))
 
(defun find-series-episode (term database)
(let ((series (get-series (format nil "~{~a~^ ~}" (butlast term)) database)))
(if series
(let* ((season-episode (car (last term)))
(pos (position #\- season-episode))
(season-str (when pos (subseq season-episode 0 pos)))
(season (or (parse-integer-quietly season-str) season-str))
(episode-str (if pos
(subseq season-episode (1+ pos))
season-episode))
(episode-nr (or (parse-integer-quietly episode-str) episode-str)))
(loop for episode in (series-episodes series)
when (and (equal (episode-episode episode) episode-nr)
(equal (episode-season episode) season))
collect episode))
(let ((series (get-series (format nil "~{~a~^ ~}" term) database)))
(if series
(list (car (series-episodes series))))))))
 
 
(defun find-episode (term database)
(or (find-series-episode term database)
(search-title term database)
(let* ((res (or (search-tags term database)
(search-title-fuzzy term database)))
(max (caar res)))
(loop for (matches episode) in res when (equal matches max) collect episode))))
 
(defun edit-episode (episode database)
(format t "editing:~%~a~%" episode)
(setf (episode-series episode)
(prompt-read "Series Title" (episode-series episode)))
(setf (episode-title episode)
(prompt-read "Title" (episode-title episode)))
(setf (episode-season episode)
(parse-number (prompt-read "Season" (episode-season episode))))
(setf (episode-episode episode)
(parse-number (prompt-read "Episode" (episode-episode episode))))
(setf (episode-part episode)
(parse-number (prompt-read "Part" (episode-part episode))))
(setf (episode-date episode)
(parse-date (prompt-read "Date watched" (format-ymd (episode-date episode)))))
(setf (episode-tags episode)
(parse-tags (prompt-read "Tags" (format nil "~{~a~^ ~}" (episode-tags episode))))))
 
(defun watch-edit (term)
(let ((episodes (find-episode term *db*)))
(if (> (length episodes) 1)
(format t "found more than one episode, please be more specific:~%~{~& ~a~%~}" episodes)
(edit-episode (car episodes) *db*))))
 
(defun watch-load (dbfile)
(setf *db* (load-db dbfile)))
 
 
(defun argv ()
(or
#+clisp (ext:argv)
#+sbcl sb-ext:*posix-argv*
#+clozure (ccl::command-line-arguments)
#+gcl si:*command-args*
#+ecl (loop for i from 0 below (si:argc) collect (si:argv i))
#+cmu extensions:*command-line-strings*
#+allegro (sys:command-line-arguments)
#+lispworks sys:*line-arguments-list*
nil))
 
(defun main (argv)
(let ((dbfile (make-pathname :name "lwatch" :type nil :defaults *load-pathname*)))
(watch-load dbfile)
(format t "loaded db~%")
(cond ((equal (cadr argv) "add") (watch-add) (watch-save dbfile))
((equal (cadr argv) "latest") (watch-latest))
((null (cadr argv)) (watch-latest))
((equal (cadr argv) "series") (watch-series-names))
((and (equal (cadr argv) "all") (equal (caddr argv) "series")) (watch-all-series))
((equal (cadr argv) "all") (watch-all))
((equal (cadr argv) "tags") (watch-tags))
((equal (cadr argv) "search") (watch-search (cddr argv)))
((equal (cadr argv) "edit") (watch-edit (cddr argv)) (watch-save dbfile))
((equal (cadr argv) "timeline") (watch-timeline))
((equal (cadr argv) "timelinev") (watch-timelinev))
((equal (cadr argv) "timelinec") (watch-timelinec))
(T (watch-series (format nil "~{~a~^ ~}" (cdr argv)))))))
 
(main (argv))</lang>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.algorithm, std.string, std.conv, std.array,
std.file, std.csv, std.datetime;
 
Line 1,161 ⟶ 1,554:
default: printUsage(); break;
}
}</langsyntaxhighlight>
{{out}}
<pre>C:\>simdb add item1 cat1
Line 1,210 ⟶ 1,603:
item6,2014-06-04T16:01:55,cat4
item7,2014-06-04T16:02:01,cat4</pre>
 
=={{header|Emacs Lisp}}==
<syntaxhighlight lang="lisp">
(defun dbe-next-id ()
(unless (boundp '**dbe-current-id**) (setq **dbe-current-id** 1))
(let ((id **dbe-current-id**))
(cl-incf **dbe-current-id**)
id ) )
 
(defun dbe-rows (fn-handle-row &rest params)
(let ((has-more 't) current-line linum1 linum2
(fn-continue (plist-get params :continue)))
(save-window-excursion
(switch-to-buffer "**content**")
(beginning-of-buffer)
(if fn-continue (setq has-more (funcall fn-continue)))
(while has-more
(setq current-line
(buffer-substring (line-beginning-position)
(line-end-position)))
(unless (string= current-line "")
(funcall fn-handle-row (read current-line)))
(if fn-continue (setq has-more (funcall fn-continue)))
(setq linum1 (line-number-at-pos (point)))
(forward-line)
(setq linum2 (line-number-at-pos (point)))
(if (= linum1 linum2) (setq has-more nil))
)
)
)
)
(defun dbe-insert (row)
(interactive "xPlease enter the row data in plist format: ")
(save-window-excursion
(switch-to-buffer "**content**")
(end-of-buffer)
(let (row-data)
(setq row-data (append (list 'id (dbe-next-id)) (ensure-list row)))
(insert (format "%s\n" row-data))
(message ">> Row added: %s" row-data) ) ) )
 
(defun dbe-find-by-id (row-id)
(interactive "nPlease enter row id: ")
(let (row-found)
(dbe-rows (lambda (row)
(when (equal (plist-get row 'id) row-id)
(setq row-found row)) )
:continue (lambda () (null row-found)))
(message ">> Row found: %s" row-found)
)
)
</syntaxhighlight>
 
{{out}}
 
<pre>
M-x dbe-insert
Please enter the row data in plist format: (name "book1" author "author1")
>> Row added: (id 1 name book1 author author1)
 
M-x dbe-insert
Please enter the row data in plist format: (name "book2" author "author2")
>> Row added: (id 2 name book2 author author2)
 
M-x dbe-find-by-id
Please enter row id: 2
>> Row found: (id 2 name book2 author author2)
</pre>
 
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
<lang Erlang>
#! /usr/bin/env escript
 
Line 1,267 ⟶ 1,730:
io:fwrite( "Data stored in ~p~n", [file()] ),
init:stop().
</syntaxhighlight>
</lang>
Command line session started with these file contents as database:
<pre>
Line 1,288 ⟶ 1,751:
2013-9-16 comic gustaf
</pre>
 
 
=={{header|Forth}}==
Line 1,367 ⟶ 1,829:
 
Code:
<langsyntaxhighlight lang="forth">\ sdb.fs Simple database. Gforth 0.7.0 specific
' noop is bootmessage
 
Line 1,495 ⟶ 1,957:
cr cr ;
current !
SEAL godb</langsyntaxhighlight>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,837 ⟶ 2,299:
fmt.Println(err)
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
 
Line 1,844 ⟶ 2,307:
Item {description = "La traviata", category = ["Classical"], date = Date 2012 10 19, optional = ["Giuseppe Verdi","1853"]}
 
<langsyntaxhighlight Haskelllang="haskell">import Control.Monad.State
import Data.List (sortBy, nub)
import System.Environment (getArgs, getProgName)
Line 1,972 ⟶ 2,435:
mapM_ (hPutStrLn hw . show) v
hClose hw
</syntaxhighlight>
</lang>
 
=={{header|J}}==
Line 1,978 ⟶ 2,441:
J comes with a sql database, jdb. Jdb's columns are memory mapped files with header information. These won't meet the human readable data file requirement. Hence, this program:
 
<langsyntaxhighlight lang="j">HELP=: 0 :0
Commands:
 
Line 2,086 ⟶ 2,549:
 
exit 0
</syntaxhighlight>
</lang>
Assume the j code is stored in file s . These bash commands, stored in file input , create a database using add .
<langsyntaxhighlight lang="sh">D='jconsole s dataflow'
$D add name expression algebraic rank valence example explanation
Line 2,101 ⟶ 2,564:
$D add atop 'x f@g y' 'f(g(x,y))' 'rank of g' dyad '>@{.' '(lisp) open the car'
$D add 'many more!'
</syntaxhighlight>
</lang>
Now we look up data from the bash command line.
<syntaxhighlight lang="sh">
<lang sh>
$ . input # source the input
$ echo $D
Line 2,179 ⟶ 2,642:
'2012-02-08:23:45:06.515';'atop';'x f@g y';'f(g(x,y))';'rank of g';'dyad';'>@{.';'(lisp) open the car'
'2012-02-08:23:45:06.539';'many more!'
$ </langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|D}}
{{works with|Java|7}}
<langsyntaxhighlight lang="java">import java.io.*;
import java.text.*;
import java.util.*;
Line 2,308 ⟶ 2,771:
+ "\"some category name\"");
}
}</langsyntaxhighlight>
 
Output:
Line 2,344 ⟶ 2,807:
item5,2014-06-03 19:30:23,cat3</pre>
 
=={{header|PhixJulia}}==
Command line CSV based simple database. The file used contained:<pre>
<lang Phix>--
Name,Birthdate,State,Relation,Email
-- demo\rosetta\Simple_db.exw
Sally Whittaker,1988-12-05,Illinois,friend,sally@mail.com
-- ==========================
Belinda Jameson,1994-02-17,California,family,beljames@example.com
--
Jeff Bragg,2018-10-10,Texas,family,jb@texas.edu
include timedate.e
Sandy Allen,2002-03-09,Colorado,friend,sandya@mail.com
Fred Kobo,1967-10-10,Colorado,friend,fkobo@example.net</pre>
<syntaxhighlight lang="julia">using CSV, DataFrames, ArgParse, Dates
 
setting = ArgParseSettings()
constant filename = getenv(iff(platform()=WINDOWS?"APPDATA":"HOME"))&"/simple_db.csv"
@add_arg_table setting begin
"--add"
help = "add an entry, within double quotes, comma separated as \"name,birthdate,state,relation,email\" with birthdate as yyyy-mm-dd"
"--latest"
action = :store_true
nargs = 0
help = "print latest (last) entry"
"--latestfriend"
action = :store_true
nargs = 0
help = "print last friend listed"
"--latestfamily"
action = :store_true
nargs = 0
help = "print last family member listed"
"--listbyage"
action = :store_true
nargs = 0
help = "print all ages and entries in birth order"
end
 
const filename = "example.csv"
procedure add(sequence cmd)
const df = CSV.File(filename, dateformat="yyyy-mm-dd") |> DataFrame
if length(cmd)=0
const commands = parse_args(setting)
or length(cmd)>2 then
if length(ARGS) == 0
printf(1,"usage: add name [cat]\n")
ArgParse.show_help(setting)
else
end
string name = cmd[1]
const changeflag = [false]
string cat = iff(length(cmd)=2?cmd[2]:"none")
string datestr = format_timedate(date(),"YYYY/MM/DD h:mmpm")
integer fn = open(filename,"a")
printf(fn,"%s,%s,%s\n",{name,cat,datestr})
close(fn)
end if
end procedure
 
for (k, v) in commands
procedure last(sequence cmd)
if k == "add" && v != nothing
integer fn = open(filename,"r")
newrow = Vector{Any}(split(v, r","))
if fn=-1 then
if length(newrow) == 5 && tryparse(DateTime, newrow[2]) != nothing
puts(1,"file not found\n")
newrow[2] = DateTime(newrow[2])
push!(df, newrow)
changeflag[1] = true
println("Added entry $newrow.")
end
elseif k == "latest" && v
println("The latest entry is $(df[end, :])")
elseif k == "latestfriend" && v
println(df[df.Relation .== "friend", :][end, :])
elseif k == "latestfamily" && v
println(df[df.Relation .== "family", :][end, :])
elseif k == "listbyage" && v
dobcol = df[:Birthdate]
age = map(x -> round((now() - DateTime(x)).value /(1000*3600*24*365.25), digits=1), dobcol)
df2 = deepcopy(df)
df2 = insert!(df, 1, age, :Age)
println(sort(df2, (:Age)))
end
end
 
if changeflag[1]
CSV.write(filename, df)
println("Changes written to file $filename.")
end
</syntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|Java}}
... though not quite the same.
<syntaxhighlight lang="scala">// version 1.2.31
 
import java.text.SimpleDateFormat
import java.util.Date
import java.io.File
import java.io.IOException
 
val file = File("simdb.csv")
 
class Item(
val name: String,
val date: String,
val category: String
) : Comparable<Item> {
 
override fun compareTo(other: Item) = date.compareTo(other.date)
 
override fun toString() = "$name, $date, $category"
}
 
fun addItem(input: Array<String>) {
if (input.size < 2) {
printUsage()
return
end if}
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
integer lc = length(cmd)
val date = sdf.format(Date())
string last = iff(lc?"<no entries for that category>\n":"<empty>\n")
val cat = if (input.size == 3) input[2] else "none"
while 1 do
store(Item(input[1], date, cat))
object line = gets(fn)
}
if atom(line) then exit end if
if lc=0 or split(line,',')[2]=cmd[1] then
last = line
end if
end while
puts(1,last)
close(fn)
end procedure
 
fun printLatest(a: Array<String>) {
sequence dates
val db = load()
if (db.isEmpty()) {
println("No entries in database.")
return
}
// no need to sort db as items are added chronologically
if (a.size == 2) {
var found = false
for (item in db.reversed()) {
if (item.category == a[1]) {
println(item)
found = true
break
}
}
if (!found) println("There are no items for category '${a[1]}'")
}
else println(db[db.lastIndex])
}
 
fun printAll() {
function by_date(integer d1, integer d2)
val db = load()
return compare(dates[d1],dates[d2])
if (db.isEmpty()) {
end function
println("No entries in database.")
constant r_by_date = routine_id("by_date")
return
}
// no need to sort db as items are added chronologically
for (item in db) println(item)
}
 
fun load(): MutableList<Item> {
procedure sort_by_date()
val db = mutableListOf<Item>()
-- (simple_db.csv should be edited manually to prove the date sort works)
try {
integer fn = open(filename,"r")
file.forEachLine { line ->
if fn=-1 then
puts val item = line.split(1,"file not, found\n")
db.add(Item(item[0], item[1], item[2]))
}
}
catch (e: IOException) {
println(e)
System.exit(1)
}
return db
}
 
fun store(item: Item) {
try {
file.appendText("$item\n")
}
catch (e: IOException) {
println(e)
}
}
 
fun printUsage() {
println("""
|Usage:
| simdb cmd [categoryName]
| add add item, followed by optional category
| latest print last added item(s), followed by optional category
| all print all
| For instance: add "some item name" "some category name"
""".trimMargin())
}
 
fun main(args: Array<String>) {
if (args.size !in 1..3) {
printUsage()
return
end if}
file.createNewFile() // create file if it doesn't already exist
sequence lines = {}
when (args[0].toLowerCase()) {
dates = {}
"add" -> addItem(args)
while 1 do
object"latest" line-> = getsprintLatest(fnargs)
if"all" atom(line) then exit end-> ifprintAll()
lineselse = append -> printUsage(lines,line)
}
dates = append(dates,split(line,',')[3])
}</syntaxhighlight>
end while
close(fn)
sequence tags = custom_sort(r_by_date,tagset(length(lines)))
for i=1 to length(tags) do
puts(1,lines[tags[i]])
end for
end procedure
 
{{out}}
procedure process(sequence cmd)
Sample session.
switch cmd[1] do
<pre>
case "add": add(cmd[2..$])
$ java -jar SimpleDatabase.jar add item1
case "last": last(cmd[2..$])
$ java -jar SimpleDatabase.jar add item2
case "sort": sort_by_date()
$ java -jar SimpleDatabase.jar add item3 cat3
default: printf(1,"unknown command: %s\n",{cmd[1]})
$ java -jar SimpleDatabase.jar add item4 cat3
end switch
$ java -jar SimpleDatabase.jar add item5 cat3
end procedure
$ java -jar SimpleDatabase.jar latest
item5, 2018-03-23 16:49:46, cat3
$ java -jar SimpleDatabase.jar latest none
item2, 2018-03-23 16:49:28, none
$ java -jar SimpleDatabase.jar latest cat4
There are no items for category 'cat4'
$ java -jar SimpleDatabase.jar all
item1, 2018-03-23 16:49:25, none
item2, 2018-03-23 16:49:28, none
item3, 2018-03-23 16:49:34, cat3
item4, 2018-03-23 16:49:40, cat3
item5, 2018-03-23 16:49:46, cat3
</pre>
 
=={{header|M2000 Interpreter}}==
constant helptext = """
Write the code on a UTF-8 text file as tool.gsb
p demo\rosetta\Simple_db -- interactive mode, commands as below
 
p demo\rosetta\Simple_db add name [cat] -- add entry
Assign gsb files to open with M2000.exe (the M2000 environment)
p demo\rosetta\Simple_db last [cat] -- show last entry [in specified category]
 
p demo\rosetta\Simple_db sort -- show full list sorted by date
Open the folder where exist tool.gsb in a cmd window
"""
 
sequence cl = command_line()
then follow the > lines in the out session
if length(cl)<3 then
 
-- interactive mode
The format of file is xml, Utf8 with a BOM.
puts(1,helptext)
 
while 1 do
The M2000 environment not used here, all the output redirect to console. (Although the environment is a Window program, we can attach the console).
puts(1,">")
 
object line = trim(gets(0))
 
if atom(line) or length(line)=0 then exit end if
<syntaxhighlight lang="m2000 interpreter">
puts(1,"\n")
MODULE GLOBAL interpret {
process(split(line))
global filename$="base1.xml"
end while
module latest {
else
PrintConsoleLn("The latest entry is:")
process(cl[3..$])
if exist(filename$) else exit
end if</lang>
declare xml xmlData
with xml, "xml" as doc$, "beautify" as beautify
doc$=string$(eval$(buffer(filename$)) as UTF8dec)
with xml, "lastchild" set child
with child,"attr" as attr$()
PrintConsoleLn(attr$("name")+","+@tag$()+","+attr$("date"))
declare xml nothing
}
module latestForEachTag {
PrintConsoleLn("latest entry for each tag:")
if exist(filename$) else exit
declare xml xmlData
with xml, "xml" as doc$, "beautify" as beautify
doc$=string$(eval$(buffer("base1.xml")) as UTF8dec)
with xml, "firstchild" as firstchild
child=firstchild
with child,"attr" as attr$()
inventory alfa
do
if not exist(alfa, @tag$()) then
append alfa, @tag$():=child
else
return alfa, @tag$():=child
end if
Method xml, "EndOffChilds", &child as ok
when ok
sort alfa
k=each(alfa)
while k
child=eval(k)
PrintConsoleLn(attr$("name")+","+@tag$()+","+attr$("date"))
end while
declare xml nothing
}
module All {
PrintConsoleLn("All entries sorted by date:")
if exist(filename$) else exit
declare xml xmlData
with xml, "xml" as doc$, "beautify" as beautify
doc$=string$(eval$(buffer("base1.xml")) as UTF8dec)
with xml, "firstchild" as firstchild
child=firstchild
with child,"attr" as attr$()
inventory alfa
i=0
do
// prevent same keys using a unique patch key
append alfa, attr$("date")+str$(i,"000000"):=child
i++
Method xml, "EndOffChilds", &child as ok
when ok
sort alfa
k=each(alfa)
while k
child=eval(k)
PrintConsoleLn(attr$("name")+","+@tag$()+","+attr$("date"))
end while
declare xml nothing
}
module add (line$) {
line$=trim$(line$)
if line$="" then exit
declare xml xmlData
with xml, "xml" as doc$, "beautify" as beautify
bom$=str$(format$("\uef\ubb\ubf"))
// len(bom$)=1.5 (1.5*2=3 bytes)
k=0
if exist(filename$) then try {k=filelen(filename$)}
if k<10 then
method xml, "PrepareNodeSimple", "xml" as ProcessInstructions
method xml, "PlaceAttributeToNode", ProcessInstructions, "version", "1.0"
method xml, "PlaceAttributeToNode", ProcessInstructions, "encoding", "utf-8-sig"
method xml, "PlaceProcessingInstructions", ProcessInstructions
method xml, "PrepareNode", "MyFile" as Node
method xml, "InsertNode", Node
else
doc$=string$(eval$(buffer(filename$)) as UTF8dec)
end if
a$=""""+line$
def name$, tag$,date$
do
a$=rightpart$(a$, """") : what$=lcase$(trim$(leftpart$(a$, """")))
if what$="" then exit
a$=rightpart$(a$, """") :par$=leftpart$(a$, """")
select case what$
case "name"
name$=par$
case "tag"
tag$=par$
case "date"
date$=par$
end select
always
if name$<>"" and date$<>"" then
method xml, "PrepareNode", "Row", "" as Node1
method xml, "PlaceAttributeToNode", Node1, "name", name$
if tag$<>"" then method xml, "PlaceAttributeToNode", Node1, "tag", tag$
method xml, "PlaceAttributeToNode", Node1, "date", date$
method xml, "AppendChild", Node1
open filename$ for wide output as #f
print #f, bom$;string$(doc$ as UTF8enc);
close #f
beautify=-4
PrintConsoleLn(doc$)
end if
declare xml nothing
}
declare FreeConsole lib "Kernel32.FreeConsole"
declare GetStdHandle lib "Kernel32.GetStdHandle" {long a}
declare AttachConsole lib "Kernel32.AttachConsole" {long a}
declare CloseHandle lib "Kernel32.CloseHandle" {long a}
declare global WriteCons Lib "Kernel32.WriteConsoleW" {long cons, a$, long n, Long p, long u}
long STD_OUTPUT_HANDLE=-11
global retvalue
buffer clear retvalue as long
ret=AttachConsole(-1)
global m=GetStdHandle(STD_OUTPUT_HANDLE)
if ret=0 then beep: exit
if not islet then
try {
open "tool.bat" for output as #f
print #f, {@}+appdir$+{m2000.exe data {%*}: dir %cd%:load tool
}
close #f
}
PrintConsoleLn("")
dos "tool.bat"
else
read cmd$
cmd$=trim$(cmd$)+" "
select case lcase$(leftpart$(cmd$, " "))
case "add"
add rightpart$(cmd$," ")
case "latest"
latest
case "latest-per-tag"
latestForEachTag
case "all-entries"
all
case else
help()
end select
end if
call void closehandle(m)
call void freeconsole()
 
Sub PrintConsole(a$)
Call Void WriteCons(m, a$, Len(a$), retvalue(0), 0)
End Sub
Sub PrintConsoleLn(a$)
a$+={
}
Call Void WriteCons(m, a$, Len(a$), retvalue(0), 0)
End Sub
// function is static here but can be called from child modules, because there are in the same block of code
// although attr$() must defined in each module. (scope constrain to module block, for local identifiers).
function tag$()
try { // if no tag exist error raised
=attr$("tag")
}
end function
Sub Help()
h$={Commands:
tool add name "anyname" tag "tagtext" date "YYYY.MM.DD.HH:MM"
tool latest
tool latest-per-tag
tool all-entries
}
PrintConsole(h$)
End Sub
}
module interpret1 {
try {interpret}
}
interpret1: end
</syntaxhighlight>
{{out}}
<pre>
first time the program make a tool.bat
>tool.gsb
 
So now we can call the tool bat.
>tool
Commands:
tool add name "anyname" tag "tagtext" date "YYYY.MM.DD.HH:MM"
tool latest
tool latest-per-tag
tool all-entries
 
>tool add name "BOB" tag "EAT A LOT" date "2022.10.21.04:00"
>tool add name "JOHN" tag "DRINK WATER" "date 2022.10.15.12:00"
>tool add name "PAUL" tag "EAT A LOT" date "2022.10.13.22:00"
>tool add name "SUZAN" tag "DRINK WATER" date "2022.10.13.12:00"
>tool add name "PHILIP" tag "DRINK WATER" date "2022.10.13.10:00"
>tool add name "MONDY" tag "EAT A LOT" date "2022.10.10.12:00"
>tool add name "MARY" tag "PIZZA FRIENDLY" date "2022.10.10.12:00"
>tool add name "DONALD" tag "PIZZA FRIENDLY" date "2022.10.10.02:00"
>tool add name "GEORGE" date "2022.11.29.16:55"
 
This is the last print from last tool add:
<?xml version="1.0" encoding="utf-8-sig"?>
<MyFile>
<Row name="BOB" tag="EAT A LOT" date="2022.10.21.04:00"></Row>
<Row name="PAUL" tag="EAT A LOT" date="2022.10.13.22:00"></Row>
<Row name="SUZAN" tag="DRINK WATER" date="2022.10.13.12:00"></Row>
<Row name="PHILIP" tag="DRINK WATER" date="2022.10.13.10:00"></Row>
<Row name="MONDY" tag="EAT A LOT" date="2022.10.10.12:00"></Row>
<Row name="MARY" tag="PIZZA FRIENDLY" date="2022.10.10.12:00"></Row>
<Row name="DONALD" tag="PIZZA FRIENDLY" date="2022.10.10.02:00"></Row>
<Row name="GEORGE" date="2022.11.29.16:55"></Row>
</MyFile>
 
 
>tool latest
The latest entry is:
GEORGE,,2022.11.29.16:55
 
>tool latest-per-tag
latest entry for each tag:
GEORGE,,2022.11.29.16:55
PHILIP,DRINK WATER,2022.10.13.10:00
MONDY,EAT A LOT,2022.10.10.12:00
DONALD,PIZZA FRIENDLY,2022.10.10.02:00
 
>tool all-entries
All entries sorted by date:
DONALD,PIZZA FRIENDLY,2022.10.10.02:00
MONDY,EAT A LOT,2022.10.10.12:00
MARY,PIZZA FRIENDLY,2022.10.10.12:00
PHILIP,DRINK WATER,2022.10.13.10:00
SUZAN,DRINK WATER,2022.10.13.12:00
PAUL,EAT A LOT,2022.10.13.22:00
BOB,EAT A LOT,2022.10.21.04:00
GEORGE,,2022.11.29.16:55
</pre>
 
=={{header|Nim}}==
{{trans|D}}
{{trans|Kotlin}}
There are some important differences with D version and Kotlin versions. Firstly, the way to manage the command arguments is somewhat different. And secondly, the database is stored in JSON format rather than in CSV format. Indeed, if Nim provides a parser of CSV files, it provides better support for JSON with procedures for serialization of Nim objects to JSON and deserialization from JSON to Nim objects. This can be seen in the following program.
 
<syntaxhighlight lang="nim">import algorithm, json, os, strformat, strutils, times
 
const FileName = "simdb.json"
 
type
 
Item = object
name: string
date: string
category: string
 
Database = seq[Item]
 
DbError = object of CatchableError
 
 
proc load(): Database =
if fileExists(FileName):
let node = try: FileName.parseFile()
except JsonParsingError:
raise newException(DbError, getCurrentExceptionMsg())
result = node.to(DataBase)
 
 
proc store(db: Database) =
try:
FileName.writeFile $(%* db)
except IOError:
quit "Unable to save database.", QuitFailure
 
 
proc addItem(args: seq[string]) =
var db = try: load()
except DbError: quit getCurrentExceptionMsg(), QuitFailure
 
let date = now().format("yyyy-MM-dd HH:mm:ss")
let cat = if args.len == 2: args[1] else: "none"
db.add Item(name: args[0], date: date, category: cat)
db.store()
 
 
proc printLatest(args: seq[string]) =
let db = try: load()
except DbError: quit getCurrentExceptionMsg(), QuitFailure
if db.len == 0:
echo "No entries in database."
return
 
# No need to sort db as items are added chronologically.
if args.len == 1:
var found = false
for item in reversed(db):
if item.category == args[0]:
echo item
found = true
break
if not found:
echo &"There are no items for category '{args[0]}'"
else:
echo db[^1]
 
 
proc printAll() =
let db = try: load()
except DbError: quit getCurrentExceptionMsg(), QuitFailure
if db.len == 0:
echo "No entries in database."
return
for item in db:
echo item
 
 
proc printUsage() =
echo &"""
Usage:
{getAppFilename().splitPath().tail} cmd [categoryName]
 
add add item, followed by optional category
latest print last added item(s), followed by optional category
all print all
 
For instance: add "some item name" "some category name"
"""
quit QuitFailure
 
 
if paramCount() notin 1..3: printUsage()
 
var params = commandLineParams()
let command = params[0].toLowerAscii
params.delete(0)
case command
of "add":
if params.len == 0: printUsage()
addItem(params)
of "latest":
if params.len > 1: printUsage()
printLatest(params)
of "all":
if params.len != 0: printUsage()
printAll()</syntaxhighlight>
 
{{out}}
Sample session (same as that of Kotlin).
<pre>$ ./simple_database add item1
$ ./simple_database add item2
$ ./simple_database add item3 cat3
$ ./simple_database add item4 cat3
$ ./simple_database add item5 cat3
$ ./simple_database latest
(name: "item5", date: "2021-04-09 00:31:34", category: "cat3")
$ ./simple_database latest none
(name: "item2", date: "2021-04-09 00:31:08", category: "none")
$ ./simple_database latest cat4
There are no items for category 'cat4'
$ ./simple_database all
(name: "item1", date: "2021-04-09 00:31:03", category: "none")
(name: "item2", date: "2021-04-09 00:31:08", category: "none")
(name: "item3", date: "2021-04-09 00:31:19", category: "cat3")
(name: "item4", date: "2021-04-09 00:31:25", category: "cat3")
(name: "item5", date: "2021-04-09 00:31:34", category: "cat3")</pre>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
 
use JSON::PP;
use Time::Piece;
 
use constant {
NAME => 0,
CATEGORY => 1,
DATE => 2,
DB => 'simple-db',
};
 
my $operation = shift // "";
 
my %dispatch = (
n => \&add_new,
l => \&print_latest,
L => \&print_latest_for_categories,
a => \&print_all,
);
 
if ($dispatch{$operation}) {
$dispatch{$operation}->(@ARGV);
} else {
die "Invalid option. Use one of n, l, L, a.\n"
}
 
sub add_new {
my ($name, $category, $date) = @_;
my $db = eval { load() } || {};
if (defined $date) {
eval { 'Time::Piece'->strptime($date, '%Y-%m-%d'); 1 }
or die "Invalid date format: YYYY-MM-DD.\n";
 
} else {
$date //= localtime->ymd;
}
 
my @ids = keys %{ $db->{by_id} };
my $max_id = max(num => @ids) || 0;
$db->{by_id}{ ++$max_id } = [ $name, $category, $date ];
save($db);
}
 
sub print_latest {
build_indexes( my $db = load(), 0, 1 );
_print_latest($db);
}
 
sub _print_latest {
my ($db, $category) = @_;
my @dates = keys %{ $db->{by_date} };
@dates = grep {
grep $db->{by_id}{$_}[CATEGORY] eq $category,
@{ $db->{by_date}{$_} };
} @dates if defined $category;
 
my $last_date = max(str => @dates);
say for map $db->{by_id}{$_}[NAME],
grep ! defined $category
|| $db->{by_id}{$_}[CATEGORY] eq $category,
@{ $db->{by_date}{$last_date} };
}
 
sub max {
my $type = shift;
my $max = $_[0];
{ num => sub { $_ > $max },
str => sub { $_ gt $max},
}->{$type}->() and $max = $_
for @_[ 1 .. $#_ ];
return $max
}
 
sub print_latest_for_categories {
build_indexes( my $db = load(), 1, 1 );
 
for my $category (sort keys %{ $db->{by_category} }){
say "* $category";
_print_latest($db, $category);
}
}
 
sub print_all {
build_indexes( my $db = load(), 0, 1 );
 
for my $date (sort keys %{ $db->{by_date} }) {
for my $id (@{ $db->{by_date}{$date} }) {
say $db->{by_id}{$id}[NAME];
}
}
}
 
sub load {
open my $in, '<', DB or die "Can't open database: $!\n";
local $/;
return { by_id => decode_json(<$in>) };
}
 
sub save {
my ($db) = @_;
open my $out, '>', DB or die "Can't save database: $!\n";
print {$out} encode_json($db->{by_id});
close $out;
}
 
sub build_indexes {
my ($db, $by_category, $by_date) = @_;
for my $id (keys %{ $db->{by_id} }) {
push @{ $db->{by_category}{ $db->{by_id}{$id}[CATEGORY] } }, $id
if $by_category;
push @{ $db->{by_date}{ $db->{by_id}{$id}[DATE] } }, $id
if $by_date;
}
}</syntaxhighlight>
Sample session<pre> ~ $ db.pl n 'Donald Trump' Republican 2017-01-20
~ $ db.pl n 'Barack Obama' Democratic 2009-01-20
~ $ db.pl n 'Bill Clinton' Democratic 1993-01-20
~ $ db.pl n 'George W. Bush' Republican 2001-01-20
~ $ db.pl a
Bill Clinton
George W. Bush
Barack Obama
Donald Trump
~ $ db.pl l
Donald Trump
~ $ db.pl L
* Democratic
Barack Obama
* Republican
Donald Trump</pre>
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Simple_db.exw
-- ==========================
--</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (file i/o, gets(0), getenv)</span>
<span style="color: #008080;">include</span> <span style="color: #004080;">timedate</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">filename</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">getenv</span><span style="color: #0000FF;">(</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">WINDOWS</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"APPDATA"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"HOME"</span><span style="color: #0000FF;">))&</span><span style="color: #008000;">"/simple_db.csv"</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span>
<span style="color: #008080;">or</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)></span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"usage: add name [cat]\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">name</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">cat</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">2</span><span style="color: #0000FF;">?</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]:</span><span style="color: #008000;">"none"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">datestr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">format_timedate</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">date</span><span style="color: #0000FF;">(),</span><span style="color: #008000;">"YYYY/MM/DD h:mmpm"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"a"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s,%s,%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cat</span><span style="color: #0000FF;">,</span><span style="color: #000000;">datestr</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"r"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">fn</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"file not found\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">lc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">last</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lc</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"&lt;no entries for that category&gt;\n"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"&lt;empty&gt;\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">gets</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">lc</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">,</span><span style="color: #008000;">','</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">last</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">line</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">last</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">dates</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">by_date</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">d1</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">d2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dates</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">dates</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d2</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">sort_by_date</span><span style="color: #0000FF;">()</span>
<span style="color: #000080;font-style:italic;">-- (simple_db.csv should be edited manually to prove the date sort works)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filename</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"r"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">fn</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"file not found\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #000000;">dates</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">gets</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">,</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">dates</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dates</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">,</span><span style="color: #008000;">','</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">3</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">tags</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">custom_sort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">by_date</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">tagset</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)))</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tags</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">tags</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">process</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">switch</span> <span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"add"</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"last"</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">last</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">case</span> <span style="color: #008000;">"sort"</span><span style="color: #0000FF;">:</span> <span style="color: #000000;">sort_by_date</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">default</span><span style="color: #0000FF;">:</span> <span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"unknown command: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">cmd</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">switch</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">helptext</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
p demo\rosetta\Simple_db -- interactive mode, commands as below
p demo\rosetta\Simple_db add name [cat] -- add entry
p demo\rosetta\Simple_db last [cat] -- show last entry [in specified category]
p demo\rosetta\Simple_db sort -- show full list sorted by date
"""</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">cl</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">command_line</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cl</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">3</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- interactive mode</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">helptext</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"&gt;"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">line</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">gets</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">process</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">line</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">process</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cl</span><span style="color: #0000FF;">[</span><span style="color: #000000;">3</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--</syntaxhighlight>-->
Sample session
<pre>
Line 2,474 ⟶ 3,665:
=={{header|PicoLisp}}==
The '[http://software-lab.de/doc/refR.html#rc rc]' resource file handling function is used typically for such tasks. It also takes care of proper locking and protection.
<langsyntaxhighlight PicoLisplang="picolisp">#!/usr/bin/pil
 
(de usage ()
Line 2,509 ⟶ 3,700:
(T (usage)) ) )
 
(bye)</langsyntaxhighlight>
Test:
<pre>$ sdb CDs add "Title 1" "Category 1" 2011-11-13
Line 2,534 ⟶ 3,725:
=={{header|Pike}}==
{{trans|Common Lisp}} (simplified)
<langsyntaxhighlight Pikelang="pike">mapping db = ([]);
 
mapping make_episode(string series, string title, string episode, array date)
Line 2,687 ⟶ 3,878:
else
watch_list(db);
}</langsyntaxhighlight>
 
=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
function db
{
[CmdletBinding(DefaultParameterSetName="None")]
[OutputType([PSCustomObject])]
Param
(
[Parameter(Mandatory=$false,
Position=0,
ParameterSetName="Add a new entry")]
[string]
$Path = ".\SimpleDatabase.csv",
 
[Parameter(Mandatory=$true,
ParameterSetName="Add a new entry")]
[string]
$Name,
 
[Parameter(Mandatory=$true,
ParameterSetName="Add a new entry")]
[string]
$Category,
 
[Parameter(Mandatory=$true,
ParameterSetName="Add a new entry")]
[datetime]
$Birthday,
 
[Parameter(ParameterSetName="Print the latest entry")]
[switch]
$Latest,
 
[Parameter(ParameterSetName="Print the latest entry for each category")]
[switch]
$LatestByCategory,
 
[Parameter(ParameterSetName="Print all entries sorted by a date")]
[switch]
$SortedByDate
)
 
if (-not (Test-Path -Path $Path))
{
'"Name","Category","Birthday"' | Out-File -FilePath $Path
}
 
$db = Import-Csv -Path $Path | Foreach-Object {
$_.Birthday = $_.Birthday -as [datetime]
$_
}
 
switch ($PSCmdlet.ParameterSetName)
{
"Add a new entry"
{
[PSCustomObject]@{Name=$Name; Category=$Category; Birthday=$Birthday} | Export-Csv -Path $Path -Append
}
"Print the latest entry"
{
$db[-1]
}
"Print the latest entry for each category"
{
($db | Group-Object -Property Category).Name | ForEach-Object {($db | Where-Object -Property Category -Contains $_)[-1]}
}
"Print all entries sorted by a date"
{
$db | Sort-Object -Property Birthday
}
Default
{
$db
}
}
}
 
db -Name Bev -Category friend -Birthday 3/3/1983
db -Name Bob -Category family -Birthday 7/19/1987
db -Name Gill -Category friend -Birthday 12/9/1986
db -Name Gail -Category family -Birthday 2/11/1986
db -Name Vince -Category family -Birthday 3/10/1960
db -Name Wayne -Category coworker -Birthday 5/29/1962
</syntaxhighlight>
Here is the data from the CSV file as a PowerShell Object:
<syntaxhighlight lang="powershell">
db
</syntaxhighlight>
{{Out}}
<pre>
Name Category Birthday
---- -------- --------
Bev friend 3/3/1983 12:00:00 AM
Bob family 7/19/1987 12:00:00 AM
Gill friend 12/9/1986 12:00:00 AM
Gail family 2/11/1986 12:00:00 AM
Vince family 3/10/1960 12:00:00 AM
Wayne coworker 5/29/1962 12:00:00 AM
</pre>
The latest entry:
<syntaxhighlight lang="powershell">
db -Latest
</syntaxhighlight>
{{Out}}
<pre>
Name Category Birthday
---- -------- --------
Wayne coworker 5/29/1962 12:00:00 AM
</pre>
The latest entries by category:
<syntaxhighlight lang="powershell">
db -LatestByCategory
</syntaxhighlight>
{{Out}}
<pre>
Name Category Birthday
---- -------- --------
Gill friend 12/9/1986 12:00:00 AM
Vince family 3/10/1960 12:00:00 AM
Wayne coworker 5/29/1962 12:00:00 AM
</pre>
The database sorted on the Birthday property:
<syntaxhighlight lang="powershell">
db -SortedByDate
</syntaxhighlight>
{{Out}}
<pre>
Name Category Birthday
---- -------- --------
Vince family 3/10/1960 12:00:00 AM
Wayne coworker 5/29/1962 12:00:00 AM
Bev friend 3/3/1983 12:00:00 AM
Gail family 2/11/1986 12:00:00 AM
Gill friend 12/9/1986 12:00:00 AM
Bob family 7/19/1987 12:00:00 AM
</pre>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">#!/usr/bin/python3
 
'''\
Line 2,797 ⟶ 4,125:
now = datetime.datetime.utcnow()
args._date = now.isoformat()
do_command[args.command](args, dbname)</langsyntaxhighlight>
 
;Sample session (Unix):
Line 2,845 ⟶ 4,173:
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">
#!/usr/bin/env racket
#lang racket
Line 2,872 ⟶ 4,200:
(for-each (compose1 show last/cat) (remove-duplicates (map cadr data)))]
[else (error 'sdb "bad printout mode")])])
</syntaxhighlight>
</lang>
 
Sample run:
Line 2,907 ⟶ 4,235:
[cds] Some-CD; 2013-01-03
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
A generic client/server JSON database.<br>
<b>server.raku:</b>
<syntaxhighlight lang="raku" line>#!/usr/bin/env raku
use JSON::Fast ;
sub MAIN( :$server='0.0.0.0', :$port=3333, :$dbfile='db' ) {
my %db;
my %index;
my $dbdata = slurp "$dbfile.json" ;
my $indexdata = slurp "{$dbfile}_index.json" ;
%db = from-json($dbdata) if $dbdata ;
%index = from-json($indexdata) if $indexdata ;
react {
whenever IO::Socket::Async.listen( $server , $port ) -> $conn {
whenever $conn.Supply.lines -> $line {
my %response = 'status' => '' ;
my $msg = from-json $line ;
say $msg.perl ;
given $msg<function> {
when 'set' {
%db{ $msg<topic> } = $msg<message> ;
%response<status> = 'ok' ;
%index<last_> = $msg<topic> ;
for %index<keys_>.keys -> $key {
if $msg<message>{$key} {
%index<lastkey_>{ $key }{ $msg<message>{$key} } = $msg<topic> ;
%index<idx_>{ $key }{ $msg<message>{$key} }{ $msg<topic> } = 1 ;
}
}
spurt "$dbfile.json", to-json(%db);
spurt "{$dbfile}_index.json", to-json(%index);
}
when 'get' {
%response<topic> = $msg<topic> ;
%response<message> = %db{ $msg<topic> } ;
%response<status> = 'ok' ;
}
when 'dump' {
%response{'data'} = %db ;
%response<status> = 'ok' ;
}
when 'dumpindex' {
%response{'data'} = %index ;
%response<status> = 'ok' ;
}
when 'delete' {
%db{ $msg<topic> }:delete;
%response<status> = 'ok' ;
spurt "$dbfile.json", to-json(%db);
reindex();
}
when 'addindex' {
%response<status> = 'ok' ;
%index<keys_>{ $msg<key>} =1 ;
reindex();
}
when 'reportlast' {
%response{'data'} = %db{%index<last_>} ;
%response<status> = 'ok' ;
}
when 'reportlastindex' {
%response<key> = $msg<key> ;
for %index<lastkey_>{$msg<key>}.keys -> $value {
#%response{'data'}.push: %db{ %index<lastkey_>{ $msg<key> }{ $value } } ;
%response{'data'}{$value} = %db{ %index<lastkey_>{ $msg<key> }{ $value } } ;
}
%response<status> = 'ok' ;
}
when 'reportindex' {
%response<status> = 'ok' ;
for %index<idx_>{$msg<key>}.keys.sort -> $value {
for %index<idx_>{ $msg<key> }{ $value }.keys.sort -> $topic {
%response<data>.push: %db{ $topic } ;
#%response<data>{$value} = %db{ $topic } ;
}
}
}
when 'commit' {
spurt "$dbfile.json", to-json(%db);
spurt "{$dbfile}_index.json", to-json(%index);
%response<status> = 'ok' ;
}
default {
%response<status> = 'error';
%response<error> = 'no function or not supported';
}
}
$conn.print( to-json(%response, :!pretty) ~ "\n" ) ;
LAST { $conn.close ; }
QUIT { default { $conn.close ; say "oh no, $_";}}
CATCH { default { say .^name, ': ', .Str , " handled in $?LINE";}}
}
}
}
sub reindex {
%index<idx_>:delete;
for %db.keys -> $topic {
my $msg = %db{$topic} ;
for %index<keys_>.keys -> $key {
if $msg{$key} {
%index<idx_>{ $key }{ $msg{$key} }{ $topic } = 1 ;
}
}
}
spurt "{$dbfile}_index.json", to-json(%index) ;
}
}</syntaxhighlight>
<b>client.raku:</b>
<syntaxhighlight lang="raku" line>#!/usr/bin/env raku
use JSON::Fast ;
multi MAIN('set', $topic, $message='', :$server='localhost', :$port='3333', :$json='') {
my %msg = function => 'set' , topic=> $topic , message=> $message ;
%msg{"message"} = from-json( $json ) if $json ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('add', $topic, $json, :$server='localhost', :$port='3333' ) {
my %msg = function => 'set' , topic=> $topic;
%msg{"message"} = from-json( $json ) if $json ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('get', $topic, :$server='localhost', :$port='3333') {
my %msg = function => 'get' , topic=> $topic ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('delete', $topic, :$server='localhost', :$port='3333') {
my %msg = function => 'delete' , topic=> $topic ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('dump', :$server='localhost', :$port='3333') {
my %msg = function => 'dump' ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('addindex', $key, :$server='localhost', :$port='3333') {
my %msg = function => 'addindex', key => $key ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('reportindex', $key, :$server='localhost', :$port='3333') {
my %msg = function => 'reportindex', key => $key ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('reportlastindex', $key, :$server='localhost', :$port='3333') {
my %msg = function => 'reportlastindex', key => $key ;
sendmsg( %msg , $server, $port) ;
}
multi MAIN('reportlast', :$server='localhost', :$port='3333') {
my %msg = function => 'reportlast' ;
sendmsg( %msg , $server, $port) ;
}
sub sendmsg( %msg , $server, $port){
my $conn = await IO::Socket::Async.connect( $server , $port );
$conn.print: to-json( %msg,:!pretty)~"\n";
react {
whenever $conn.Supply -> $data {
print $data;
$conn.close;
}
}
}</syntaxhighlight>
Example:
<pre>./client.raku addindex constructor
./client.raku addindex date
 
./client.raku add 2007 '{"date":"2007-11-04","constructor":"Ducati","name":"Casey Stoner"}'
./client.raku add 2008 '{"date":"2008-10-26","constructor":"Yamaha","name":"Valentino Rossi"}'
./client.raku add 2009 '{"date":"2009-11-08","constructor":"Yamaha","name":"Valentino Rossi"}'
./client.raku add 2010 '{"date":"2010-11-17","constructor":"Yamaha","name":"Jorge Lorenzo"}'
./client.raku add 2011 '{"date":"2011-11-06","constructor":"Honda","name":"Casey Stoner"}'
./client.raku add 2012 '{"date":"2012-11-11","constructor":"Yamaha","name":"Jorge Lorenzo"}'
./client.raku add 2013 '{"date":"2013-11-10","constructor":"Honda","name":"Marc Márquez"}'
./client.raku add 2014 '{"date":"2014-11-09","constructor":"Honda","name":"Marc Márquez"}'
./client.raku add 2015 '{"date":"2015-11-08","constructor":"Yamaha","name":"Jorge Lorenzo"}'
./client.raku add 2016 '{"date":"2016-11-13","constructor":"Honda","name":"Marc Márquez"}'
./client.raku add 2017 '{"date":"2017-11-12","constructor":"Honda","name":"Marc Márquez"}'
 
./client.raku reportlast
./client.raku reportlastindex constructor
./client.raku reportindex date</pre>
 
=={{header|REBOL}}==
<langsyntaxhighlight lang="rebol">rebol [author: "Nick Antonaccio"]
write/append %rdb "" db: load %rdb
switch system/options/args/1 [
Line 2,923 ⟶ 4,430:
"sort" [probe sort/skip db 4]
]
halt</langsyntaxhighlight>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/* REXX ---------------------------------------------------------------
* 05.10.2014
*--------------------------------------------------------------------*/
Line 3,001 ⟶ 4,509:
Say 'end to end this program'
Say 'Use category - to list items without category'
Return</langsyntaxhighlight>
{{out}}
<pre> Enter your commands, ?, or end
Line 3,038 ⟶ 4,546:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">require 'date'
require 'json'
require 'securerandom'
Line 3,224 ⟶ 4,732:
end
 
process_command_line *ARGV</langsyntaxhighlight>
 
Sample session
Line 3,302 ⟶ 4,810:
</pre>
 
=={{header|Run BASIC}}==
<lang runbasic>sqliteconnect #sql, "f:\client.db" ' Connect to the DB
 
' -------------------------------
' show user options
' -------------------------------
[sho]
cls ' clear screen
button #acd, "Add a new entry", [add]
button #acd, "Print the latest entry", [last]
button #acd, "Print the latest entry for each category", [lastCat]
button #acd, "Print all entries sorted by a date", [date]
button #ex, "Exit", [exit]
wait
 
' ------------------------------------
' add a new entry (user input screen)
' ------------------------------------
[add]
cls ' clear the screen
html "<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 bgcolor=wheat>"
html "<TR align=center BGCOLOR=tan><TD colspan=2>Client Maintenance</TD></TR><TR>"
html "<TD bgcolor=tan align=right>Client Num</TD><TD>"
textbox #clientNum,clientNum$,5
 
html "</TD></TR><TR><TD bgcolor=tan align=right>Name</TD><TD>"
textbox #name,name$,30
 
html "</TD></TR><TR><TD bgcolor=tan align=right>Client Date</TD><TD>"
textbox #clientDate,clientDate$,19
 
html "</TD></TR><TR><TD bgcolor=tan align=right>Category</TD><TD>"
textbox #category,category$,10
 
html "</TD></TR><TR><TR bgcolor=tan><TD colspan=2 ALIGN=CENTER>"
button #acd, "Add", [addIt]
button #ex, "Exit", [sho]
html "</TD></TR></TABLE>"
wait
 
' ---------------------------------------------
' Get data from the screen
' ---------------------------------------------
[addIt]
clientNum = #clientNum contents$()
name$ = trim$(#name contents$())
clientDate$ = trim$(#clientDate contents$())
category$ = trim$(#category contents$())
dbVals$ = clientNum;",'";name$;"','";clientDate$;"','";category$;"'"
sql$ = "INSERT into client VALUES ("; dbVals$ ; ")"
#sql execute(sql$)
goto [sho]
 
' ------------------------------------
' Select last entry
' ------------------------------------
[last]
sql$ = "SELECT *,client.rowid as rowid FROM client ORDER BY rowid desc LIMIT 1"
what$ = "---- Last Entry ----"
goto [shoQuery]
 
' ------------------------------------
' Select by category (Last date only)
' ------------------------------------
[lastCat]
sql$ = "SELECT * FROM client
WHERE client.clientDate = (SELECT max(c.clientDate)
FROM client as c WHERE c.category = client.category)
ORDER BY category"
what$ = "---- Last Category Sequence ----"
goto [shoQuery]
 
' ------------------------------------
' Select by date
' ------------------------------------
[date]
sql$ = "SELECT * FROM client ORDER BY clientDate"
what$ = "---- By Date ----"
 
[shoQuery]
cls
print what$
html "<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>"
html "<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>" ' heading
#sql execute(sql$)
WHILE #sql hasanswer()
#row = #sql #nextrow()
clientNum = #row clientNum()
name$ = #row name$()
clientDate$ = #row clientDate$()
category$ = #row category$()
 
html "<TR><TD align=right>";clientNum;"</TD><TD>";name$;"</TD><TD>";clientDate$;"</TD><TD>";category$;"</TD></TR>"
WEND
html "</TABLE>"
button #c, "Continue", [sho]
wait
 
' ------ the end -------
[exit]
end</lang>
Output:
 
---- User Input ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 bgcolor=wheat>
<TR align=center BGCOLOR=tan><TD colspan=2>Client Maintenance</TD></TR>
<TR><TD bgcolor=tan align=right>Client Num</TD><TD>5</TD></TR>
<TR><TD bgcolor=tan align=right>Name</TD><TD>Dawnridge Winery</TD></TR>
<TR><TD bgcolor=tan align=right>Client Date</TD><TD>2008-06-18 22:16</TD></TR>
<TR><TD bgcolor=tan align=right>Category</TD><TD>wine</TD></TR>
<TR><TR bgcolor=tan><TD colspan=2 ALIGN=CENTER>[Add] [Exit]</TD></TR></TABLE>
 
---- Last Entry ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>
<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>
<TR><TD align=right>5</TD><TD>Dawnridge Winery</TD><TD>2008-06-18 22:16</TD><TD>wine</TD></TR></TABLE>
 
---- Last category Sequence ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>
<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>
<TR><TD align=right>1</TD><TD>Home Sales</TD><TD>2012-01-01 10;20</TD><TD>broker</TD></TR>
<TR><TD align=right>4</TD><TD>Back 40 Equipment</TD><TD>2009-09-18 20:18</TD><TD>farm</TD></TR>
<TR><TD align=right>3</TD><TD>Floral Designs</TD><TD>2010-10-14 09:16</TD><TD>flowers</TD></TR>
<TR><TD align=right>2</TD><TD>Best Foods</TD><TD>2011-02-02 12:33</TD><TD>food</TD></TR>
<TR><TD align=right>5</TD><TD>Dawnridge Winery</TD><TD>2008-06-18 22:16</TD><TD>wine</TD></TR></TABLE>
 
---- Date Sequence ----<br />
<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>
<TR align=center bgcolor=wheat><TD>Client<br>Num</TD><TD>Name</TD><TD>Client<br>Date</TD><TD>Category</TD></TR>
<TR><TD align=right>5</TD><TD>Dawnridge Winery</TD><TD>2008-06-18 22;16</TD><TD>wine</TD></TR>
<TR><TD align=right>4</TD><TD>Back 40 Equipment</TD><TD>2009-09-18 20:18</TD><TD>farm</TD></TR>
<TR><TD align=right>3</TD><TD>Floral Designs</TD><TD>2010-10-14 09:16</TD><TD>flowers</TD></TR>
<TR><TD align=right>2</TD><TD>Best Foods</TD><TD>2011-02-02 12:33</TD><TD>food</TD></TR>
<TR><TD align=right>1</TD><TD>Home Sales</TD><TD>2012-01-01 10:20</TD><TD>broker</TD></TR></TABLE>
=={{header|Scala}}==
<langsyntaxhighlight Scalalang="scala">object SimpleDatabase extends App {
type Entry = Array[String]
def asTSV(e: Entry) = e mkString "\t"
Line 3,474 ⟶ 4,848:
case _ => println("Usage: SimpleDatabase filename.tsv [all [latest]| latest [CATEGORY] | add [DESCRIPTION [CATEGORY [OPTIONAL]...]]]")
}
}</langsyntaxhighlight>
{{out}}
<pre>> SimpleDatabase
Line 3,512 ⟶ 4,886:
=={{header|Tcl}}==
The format used is that of a Tcl dictionary, where each entry uses the title as a key and the remaining information (category, date and miscellaneous metadata) is the value associated with it. The only variation from the standard internal format is that entries are separated by newlines instead of spaces; this is still a legal value, but is a non-canonical.
<langsyntaxhighlight lang="tcl">#!/usr/bin/env tclsh8.6
package require Tcl 8.6
namespace eval udb {
Line 3,612 ⟶ 4,986:
}
 
udb::Store [lindex $argv 0]</langsyntaxhighlight>
Sample session:
<langsyntaxhighlight lang="bash">bash$ udb.tcl db
wrong # args: should be "udb.tcl dbfile subcommand ?args...?"
bash$ udb.tcl db ?
Line 3,704 ⟶ 5,078:
Title: Title 3
Category: bar
Date: Tue Nov 15 18:12:07 GMT 2011</langsyntaxhighlight>
 
=={{header|ToffeeScript}}==
<langsyntaxhighlight lang="coffeescript">#!/usr/local/bin/toffee
 
prog = require 'commander'
Line 3,791 ⟶ 5,165:
printFormatted entry
 
prog.parse process.argv</langsyntaxhighlight>
 
=={{header|UNIX Shell}}==
This format is guaranteed to be human readable: if you can type it, you can read it.
<langsyntaxhighlight lang="bash">#!/bin/sh
 
db_create() {
Line 3,890 ⟶ 5,264:
show_help
;;
esac</langsyntaxhighlight>
Sample usage (assuming script is named "sdb"):<syntaxhighlight lang="text">$ sdb create CDs
Create DB `CDs'
$ sdb add CDs Bookends
Line 3,927 ⟶ 5,301:
$ sdb drop CDs
Delete DB `CDs'
$</langsyntaxhighlight>
 
=={{header|Wren}}==
{{trans|Kotlin}}
===Version 1===
{{libheader|Wren-ioutil}}
{{libheader|Wren-trait}}
{{libheader|Wren-iterate}}
{{libheader|Wren-date}}
{{libheader|Wren-sort}}
{{libheader|Wren-str}}
Note that since Wren CLI currently has no way of determining the current date/time, a date needs to be input for each item to be added.
<syntaxhighlight lang="wren">/* Simple_database.wren */
 
import "os" for Process
import "./ioutil" for File, FileFlags, FileUtil
import "./trait" for Comparable
import "./iterate" for Reversed
import "./date" for Date
import "./sort" for Sort
import "./str" for Str
 
var fileName = "Simple_database.csv"
 
Date.default = Date.isoDate
 
class Item is Comparable {
construct new(name, date, category) {
_name = name
_date = date
_category = category
}
 
name { _name }
date { _date }
category { _category }
 
compare(other) { _date.compare(other.date) }
 
toString { "%(name), %(date.toString), %(category)" }
}
 
var printUsage = Fn.new {
System.print("""
Usage:
wren Simple_database.wren cmd [categoryName]
add add item name and date, followed by optional category
latest print item with latest date, followed by optional category
all print all
For instance: add "some item name", "some item date", "some category name"
Dates should be in format: yyyy-mm-dd
""")
}
 
var load = Fn.new {
var db = []
var lines = FileUtil.readLines(fileName)
for (line in lines) {
if (line == "") break // end of file
var item = line.split(", ")
db.add(Item.new(item[0], Date.parse(item[1]), item[2]))
}
return db
}
 
var store = Fn.new { |item|
File.openWithFlags(fileName, FileFlags.writeOnly) { |f|
f.writeBytes("%(item)\n")
}
}
 
var addItem = Fn.new { |input|
if (input.count < 2) {
printUsage.call()
return
}
var date = Date.parse(input[1])
var cat = (input.count == 3) ? input[2] : "none"
store.call(Item.new(input[0], date, cat))
}
 
var printLatest = Fn.new { |a|
var db = load.call()
if (db.isEmpty) {
System.print("No entries in database.")
return
}
Sort.quick(db) // sort by ascending date
if (a.count == 1) {
var found = false
for (item in Reversed.new(db)) {
if (item.category == a[0]) {
System.print(item)
found = true
break
}
}
if (!found) System.print("There are no items for category '%(a[0])'.")
} else System.print(db[-1])
}
 
var printAll = Fn.new {
var db = load.call()
if (db.isEmpty) {
System.print("No entries in database.")
return
}
Sort.quick(db) // sort by ascending date
for (item in db) System.print(item)
}
 
var args = Process.arguments
if (!(1..4).contains(args.count)) {
printUsage.call()
return
}
// create file if it doesn't already exist
if (!File.exists(fileName)) {
var f = File.create(fileName)
f.close()
}
 
var cmd = Str.lower(args[0])
if (cmd == "add") {
addItem.call(args[1..-1])
} else if (cmd == "latest") {
printLatest.call(args[1..-1])
} else if (cmd == "all") {
printAll.call()
} else {
printUsage.call()
}</syntaxhighlight>
 
{{out}}
Sample session:
<pre>
$ wren Simple_database.wren add item1 2021-03-01
$ wren Simple_database.wren add item2 2021-04-01
$ wren Simple_database.wren add item3 2021-05-01 cat3
$ wren Simple_database.wren add item4 2021-06-01 cat3
$ wren Simple_database.wren add item5 2021-07-01 cat3
$ wren Simple_database.wren latest
item5, 2021-07-01, cat3
$ wren Simple_database.wren latest none
item2, 2021-04-01, none
$ wren Simple_database.wren latest cat4
There are no items for category 'cat4'.
$ wren Simple_database.wren all
item1, 2021-03-01, none
item2, 2021-04-01, none
item3, 2021-05-01, cat3
item4, 2021-06-01, cat3
item5, 2021-07-01, cat3
</pre>
<br>
===Version 2===
{{libheader|Wren-table}}
The above module provides a more generic way to create simple databases and was not available when the first version was written.
<syntaxhighlight lang="wren">import "os" for Process
import "./table" for Table, FieldInfo, File
import "./str" for Str
 
var printUsage = Fn.new {
System.print("""
Usage:
wren Simple_database.wren cmd [categoryName]
add add item name and date, followed by optional category
latest print item with latest date, followed by optional category
all print all
For instance: add "some item name", "some item date", "some category name"
Dates should be in format: yyyy-mm-dd
""")
}
 
var printLatest = Fn.new { |table, a|
if (table.isEmpty) {
System.print("No entries in table.")
return
}
var records = table.records
records.sort { |s, t| Str.lt(s[1], t[1]) } // sort by ascending date
if (a.count == 1) {
var found = false
for (record in records[-1..0]) {
if (record[2] == a[0]) {
System.print(record)
found = true
break
}
}
if (!found) System.print("There are no records for category '%(a[0])'.")
} else System.print(records[-1])
}
 
var args = Process.arguments
if (!(1..4).contains(args.count)) {
printUsage.call()
return
}
 
// create a new Table object
var tableName = "Simple_database"
var table
if (Table.fileExists(tableName)) {
table = Table.load(tableName)
} else {
var fis = [
FieldInfo.new("name", String),
FieldInfo.new("date", String),
FieldInfo.new("category", String)
]
table = Table.new(tableName, fis)
}
 
var cmd = Str.lower(args[0])
if (cmd == "add") {
if (args.count < 4) args.add("none")
table.add(args[1..-1])
table.save()
} else if (cmd == "latest") {
printLatest.call(table, args[1..-1])
} else if (cmd == "all") {
table.list()
} else {
printUsage.call()
}</syntaxhighlight>
 
{{out}}
<pre>
$ wren Simple_database.wren add item1 2021-03-01
$ wren Simple_database.wren add item2 2021-04-01
$ wren Simple_database.wren add item3 2021-05-01 cat3
$ wren Simple_database.wren add item4 2021-06-01 cat3
$ wren Simple_database.wren add item5 2021-07-01 cat3
$ wren Simple_database.wren latest
[item5, 2021-07-01, cat3]
$ wren Simple_database.wren latest none
[item2, 2021-04-01, none]
$ wren Simple_database.wren latest cat4
There are no records for category 'cat4'.
$ wren Simple_database.wren all
Records in 'Simple_database' table:
 
name date category
----- ---------- --------
item1 2021-03-01 none
item2 2021-04-01 none
item3 2021-05-01 cat3
item4 2021-06-01 cat3
item5 2021-07-01 cat3
</pre>
413

edits