Simple database: Difference between revisions
m
→{{header|11l}}
(→{{header|Java}}: reverse sort order) |
Alextretyak (talk | contribs) m (→{{header|11l}}) |
||
(55 intermediate revisions by 23 users not shown) | |||
Line 1:
{{task|Data Structures}}
;Task:
Write a simple tool to track a small set of data.
The tool should have a command-line interface to enter at least two different values.
The entered data should be stored in a structured format and saved to disk.
It does not matter what kind of data is being tracked. It could be
You should track the following details:
Line 13 ⟶ 17:
* Other optional fields
<br>
The command should support the following [[Command-line arguments]] to run:
* Add a new entry
Line 19 ⟶ 24:
* Print all entries sorted by a date
<br>
The category may be realized as a tag or as structure (by making all entries in that category subitems)
The file format on disk should be human readable, but it need not be standardized. A natively available format that doesn't need an external library is preferred. Avoid developing your own format
:::* [[JSON]]
:::* [[S-Expressions]]
:::* [[YAML]]
:::* [[wp:Comparison_of_data_serialization_formats|others]]
;Related task:
* [[Take notes on the command line]]
<br><br>
=={{header|11l}}==
{{trans|Kotlin}}
<syntaxhighlight lang="11l">T Item((String name, String date, String 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':
<syntaxhighlight lang="bracmat"> whl
' ( arg$:?command
& ( get'db
| (db=1)&lst$(db,db,NEW)
)
& !command
: ( add
& :?name:?tag:?date
& whl
' ( arg$:?argmnt
& arg$:?value
& (!argmnt.!value)
: ( (title|name.?name)
| (category|tag.?tag)
| (date.?date)
)
)
& ( !name:~
& !tag:~
& !date:~
& ( !db:?*!tag^(?+(!date.!name)+?)*?
& out$"This record already exists"
| !tag^(!date.!name)*!db:?db
& lst$(db,db,NEW)
)
| out$"invalid data"
)
| latest
& :?date
& nothing found:?latest
& ( !db
: ?
* ?tag
^ ( ?
+ ( (>!date:?date.?name)
& (!name,!tag,!date):?latest
& ~
)
+ ?
)
* ?
| out$!latest
)
| latest/category
& :?date:?latests:?latest
& ( !db
: ?
* ( ?tag
& !latests !latest:?latests
& :?latest:?date
)
^ ( ?
+ ( (>!date:?date.?name)
& (!name,!tag,!date):?latest
& ~
)
+ ?
)
* ?
| !latests !latest:?latests&out$!latests
)
| sorted
& 0:?sorted
& ( !db
: ?
* ?tag
^ ( ?
+ ( (?date.?name)
& (!date.!name,!tag,!date)+!sorted:?sorted
& ~
)
+ ?
)
* ?
| whl
' (!sorted:(?.?row)+?sorted&out$!row)
)
)
);
</syntaxhighlight>
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"
bracmat "get$sdb" add name "FPMC 21" tag "CHEMICAL TANKER" date "2014.10.15.12:00"
bracmat "get$sdb" add name "CHINA PROGRESS" tag "BULK CARRIER" date "2014.10.13.22:00"
bracmat "get$sdb" add name "FAIRCHEM YUKA" tag "CHEMICAL TANKER" date "2014.10.13.12:00"
bracmat "get$sdb" add name "NAVE COSMOS" tag "CHEMICAL TANKER" date "2014.10.13.10:00"
bracmat "get$sdb" add name "GOLDEN ICE" tag "BULK CARRIER" date "2014.10.10.12:00"
bracmat "get$sdb" add name "GHAZAL" tag "CRUDE OIL" date "2014.10.10.12:00"
bracmat "get$sdb" add name "HS MEDEA" tag "CRUDE OIL" date "2014.10.10.02:00"</pre>
Instead of 'name' you can use 'title' and instead of 'tag' you can use 'category'. The date has to be year first and day last, followed by time information if you like. No attempt is made to validate the date/time. Now the queries:
<pre>prompt> bracmat "get$sdb" latest
CORONA BULKER,BULK CARRIER,2014.10.21.04:00
prompt> bracmat "get$sdb" latest/category
(CORONA BULKER,BULK CARRIER,2014.10.21.04:00)
(FPMC 21,CHEMICAL TANKER,2014.10.15.12:00)
(GHAZAL,CRUDE OIL,2014.10.10.12:00)
prompt> bracmat "get$sdb" sorted
HS MEDEA,CRUDE OIL,2014.10.10.02:00
GHAZAL,CRUDE OIL,2014.10.10.12:00
GOLDEN ICE,BULK CARRIER,2014.10.10.12:00
NAVE COSMOS,CHEMICAL TANKER,2014.10.13.10:00
FAIRCHEM YUKA,CHEMICAL TANKER,2014.10.13.12:00
CHINA PROGRESS,BULK CARRIER,2014.10.13.22:00
FPMC 21,CHEMICAL TANKER,2014.10.15.12:00
CORONA BULKER,BULK CARRIER,2014.10.21.04:00</pre>
The database file 'db' looks like this:
<pre>db= "BULK CARRIER"
^ ( ("2014.10.10.12:00"."GOLDEN ICE")
+ ("2014.10.13.22:00"."CHINA PROGRESS")
+ ("2014.10.21.04:00"."CORONA BULKER")
)
* "CHEMICAL TANKER"
^ ( ("2014.10.13.10:00"."NAVE COSMOS")
+ ("2014.10.13.12:00"."FAIRCHEM YUKA")
+ ("2014.10.15.12:00"."FPMC 21")
)
* "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 34 ⟶ 437:
"Treasure Beach","Argus","Jemky","09-22-1999","Lancast"
<
#include <stdlib.h> /* malloc */
#include <string.h> /* strlen */
Line 226 ⟶ 629:
}
else return ((*p1)->date > (*p2)->date);
}</
=={{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}}
<
PROGRAM-ID. simple-database.
Line 492 ⟶ 1,255:
"The title should be specified as shown for -c."
DISPLAY " -t - Show all the entries sorted by tag."
.</
Sample session:
Line 528 ⟶ 1,291:
=={{header|Common Lisp}}==
Tested with [[Common Lisp]]. ''(Save the code below as db.lisp)''
<syntaxhighlight lang="lisp">(defvar *db* nil)
(defvar *db-cat* (make-hash-table :test 'equal))
(defvar *db-file* "db.txt")
(defstruct item
"this is the unit of data stored/displayed in *db*"
(title " ")
(category "default")
(date (progn (get-universal-time))))
(defun
(setf (gethash (item-category new-item) *db-cat*) 't))
(defun
(
(find category *db* :key #'item-category :test #'string=)))
(defun
"scan categories from an existing database -- after reading it from disk"
(dolist (itm *db*) (set-category itm)))
(defun pr-univ-time (utime)
(multiple-value-bind
(format nil "~4,'0d-~2,'0d-~2,'0d ~2,'0d:~2,'0d:~2,'0d" year month date hour minute second)))
(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
"print the latest item from each category"
(loop for k being the hash-keys in *db-cat*
do (pr (find-item-in-db k))))
(defun
"print all the items, *db* is sorted by time."
(defun
(loop for k being the hash-keys in *db-cat*
do (format stream "(~a) " k)))
(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
(with-open-file (in file :if-does-not-exist nil)
(when in
(with-standard-io-syntax (setf *db* (read in)))
(defun
(with-open-file (out file :direction :output :if-exists :supersede)
(with-standard-io-syntax
(print *db* out))))
(defun
(setf *db* nil)
(save-db-to-file))
(defun
(
(setf *db* (remove itm *db* :key #'item-title :test #'string=))
(save-db-to-file))
(defun
(
(insert-item (make-item :title (first args) :category (second args)))
(save-db-to-file))
(defun
(format t "clisp db.lisp ~{~15T~a~^~% ~}"
'("delete <item-name> ------------------- delete an item"
"delete-all --------------------------- delete the database"
"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
(
(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 db-argv ()
(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>
Help menu:
$ clisp db.lisp
clisp db.lisp delete <item-name> ------------------- delete an item
delete-all --------------------------- delete the database
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
Here are a few steps to add a few titles, and their categories:
$ clisp db.lisp insert "title-vinyl-1" "vinyl"
$ 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:
$ clisp db.lisp show
title-tape-2: (tape) (2017-04-04 20:19:06)
Here is a (sorted time wise) list of all the entries:
$ clisp db.lisp show-all
title-tape-2: (tape) (2017-04-04 20:19:06)
title-tape-1: (tape) (2017-04-04 20:19:00)
title-dvd-1: (dvd) (2017-04-04 20:18:55)
title-cd-1: (cd) (2017-04-04 20:18:48)
title-vinyl-1: (vinyl) (2017-04-04 20:18:41)
Here is the latest entry for each category:
$ clisp db.lisp show-per-category
title-vinyl-1: (vinyl) (2017-04-04 20:18:41)
title-cd-1: (cd) (2017-04-04 20:18:48)
title-dvd-1: (dvd) (2017-04-04 20:18:55)
title-tape-2: (tape) (2017-04-04 20:19:06)
Here is the list of all categories:
$ clisp db.lisp show-categories
(vinyl) (cd) (dvd) (tape)
To delete an entry:
$ clisp db.lisp delete "title-tape-2"
To delete all entries:
$ clisp db.lisp delete-all
=={{header|D}}==
<
std.file, std.csv, std.datetime;
Line 1,022 ⟶ 1,547:
default: printUsage(); break;
}
}</
{{out}}
<pre>C:\>simdb add item1 cat1
Line 1,071 ⟶ 1,596:
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">
#! /usr/bin/env escript
Line 1,128 ⟶ 1,723:
io:fwrite( "Data stored in ~p~n", [file()] ),
init:stop().
</syntaxhighlight>
Command line session started with these file contents as database:
<pre>
Line 1,149 ⟶ 1,744:
2013-9-16 comic gustaf
</pre>
=={{header|Forth}}==
Line 1,228 ⟶ 1,822:
Code:
<
' noop is bootmessage
Line 1,356 ⟶ 1,950:
cr cr ;
current !
SEAL godb</
=={{header|Go}}==
<
import (
Line 1,698 ⟶ 2,292:
fmt.Println(err)
}
}</
=={{header|Haskell}}==
Line 1,705 ⟶ 2,300:
Item {description = "La traviata", category = ["Classical"], date = Date 2012 10 19, optional = ["Giuseppe Verdi","1853"]}
<
import Data.List (sortBy, nub)
import System.Environment (getArgs, getProgName)
Line 1,833 ⟶ 2,428:
mapM_ (hPutStrLn hw . show) v
hClose hw
</syntaxhighlight>
=={{header|J}}==
Line 1,839 ⟶ 2,434:
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:
<
Commands:
Line 1,947 ⟶ 2,542:
exit 0
</syntaxhighlight>
Assume the j code is stored in file s . These bash commands, stored in file input , create a database using add .
<
$D add name expression algebraic rank valence example explanation
Line 1,962 ⟶ 2,557:
$D add atop 'x f@g y' 'f(g(x,y))' 'rank of g' dyad '>@{.' '(lisp) open the car'
$D add 'many more!'
</syntaxhighlight>
Now we look up data from the bash command line.
<syntaxhighlight lang="sh">
$ . input # source the input
$ echo $D
Line 2,040 ⟶ 2,635:
'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!'
$ </
=={{header|Java}}==
{{trans|D}}
{{works with|Java|7}}
<
import java.text.*;
import java.util.*;
Line 2,139 ⟶ 2,734:
private static List<Item> load() {
List<Item> db = new ArrayList<>();
try (
db.add(new Item(item[0], item[1], item[2]));
}
Line 2,170 ⟶ 2,764:
+ "\"some category name\"");
}
}</
Output:
Line 2,205 ⟶ 2,799:
item5,2014-06-03 19:30:23,cat3</pre>
=={{header|Julia}}==
Command line CSV based simple database. The file used contained:<pre>
Name,Birthdate,State,Relation,Email
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
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()
@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"
const df = CSV.File(filename, dateformat="yyyy-mm-dd") |> DataFrame
const commands = parse_args(setting)
if length(ARGS) == 0
ArgParse.show_help(setting)
end
const changeflag = [false]
for (k, v) in commands
if k == "add" && v != nothing
newrow = Vector{Any}(split(v, r","))
if length(newrow) == 5 && tryparse(DateTime, newrow[2]) != nothing
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
}
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val date = sdf.format(Date())
val cat = if (input.size == 3) input[2] else "none"
store(Item(input[1], date, cat))
}
fun printLatest(a: Array<String>) {
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() {
val db = load()
if (db.isEmpty()) {
println("No entries in database.")
return
}
// no need to sort db as items are added chronologically
for (item in db) println(item)
}
fun load(): MutableList<Item> {
val db = mutableListOf<Item>()
try {
file.forEachLine { line ->
val item = line.split(", ")
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
}
file.createNewFile() // create file if it doesn't already exist
when (args[0].toLowerCase()) {
"add" -> addItem(args)
"latest" -> printLatest(args)
"all" -> printAll()
else -> printUsage()
}
}</syntaxhighlight>
{{out}}
Sample session.
<pre>
$ java -jar SimpleDatabase.jar add item1
$ java -jar SimpleDatabase.jar add item2
$ java -jar SimpleDatabase.jar add item3 cat3
$ java -jar SimpleDatabase.jar add item4 cat3
$ java -jar SimpleDatabase.jar add item5 cat3
$ 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}}==
Write the code on a UTF-8 text file as tool.gsb
Assign gsb files to open with M2000.exe (the M2000 environment)
Open the folder where exist tool.gsb in a cmd window
then follow the > lines in the out session
The format of file is xml, Utf8 with a BOM.
The M2000 environment not used here, all the output redirect to console. (Although the environment is a Window program, we can attach the console).
<syntaxhighlight lang="m2000 interpreter">
MODULE GLOBAL interpret {
global filename$="base1.xml"
module latest {
PrintConsoleLn("The latest entry is:")
if exist(filename$) else exit
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;">"<no entries for that category>\n"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"<empty>\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;">">"</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>
C:\Program Files (x86)\Phix>p demo\rosetta\simple_db
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
>sort
fred,none,2016/07/25 12:30pm
cliff,none,2016/07/25 12:31pm
barney,none,2016/07/25 12:32pm
one,two,2016/07/25 12:33pm
>add three four
>sort
fred,none,2016/07/25 12:30pm
cliff,none,2016/07/25 12:31pm
barney,none,2016/07/25 12:32pm
one,two,2016/07/25 12:33pm
three,four,2016/07/25 12:39pm
>last
three,four,2016/07/25 12:39pm
>last one
<no entries for that category>
>last two
one,two,2016/07/25 12:33pm
>
</pre>
=={{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.
<
(de usage ()
Line 2,243 ⟶ 3,693:
(T (usage)) ) )
(bye)</
Test:
<pre>$ sdb CDs add "Title 1" "Category 1" 2011-11-13
Line 2,268 ⟶ 3,718:
=={{header|Pike}}==
{{trans|Common Lisp}} (simplified)
<
mapping make_episode(string series, string title, string episode, array date)
Line 2,421 ⟶ 3,871:
else
watch_list(db);
}</
=={{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}}==
<
'''\
Line 2,531 ⟶ 4,118:
now = datetime.datetime.utcnow()
args._date = now.isoformat()
do_command[args.command](args, dbname)</
;Sample session (Unix):
Line 2,579 ⟶ 4,166:
=={{header|Racket}}==
<
#!/usr/bin/env racket
#lang racket
Line 2,606 ⟶ 4,193:
(for-each (compose1 show last/cat) (remove-duplicates (map cadr data)))]
[else (error 'sdb "bad printout mode")])])
</syntaxhighlight>
Sample run:
Line 2,641 ⟶ 4,228:
[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}}==
<
write/append %rdb "" db: load %rdb
switch system/options/args/1 [
Line 2,657 ⟶ 4,423:
"sort" [probe sort/skip db 4]
]
halt</
=={{header|REXX}}==
<syntaxhighlight lang="rexx">/* REXX ---------------------------------------------------------------
* 05.10.2014
*--------------------------------------------------------------------*/
x05='05'x
mydb='sidb.txt'
Say 'Enter your commands, ?, or end'
Do Forever
Parse Pull l
Parse Var l command text
Select
When command='?' Then
Call help
When command='add' Then Do
Parse Var text item ',' category ',' date
If date='' Then
date=date('S') /*yyyymmdd*/
Say 'adding item' item'/'category 'dated' date
Call lineout mydb,date item x05 category
End
When command='latest' Then Do
Call lineout mydb
Parse Var text category
hidt='00000000'
ol=''
Do While lines(mydb)>0
l=linein(mydb)
Parse Var l dt a (x05) b
If category=''|,
category='-' & b='' |,
b=category Then Do
If dt>>hidt Then Do
ol=l
hidt=dt
End
End
End
If ol>'' Then
Call o ol
Else
Say 'no matching item found'
End
When command='all' Then Do
Call lineout mydb
Parse Var text category
Do While lines(mydb)>0
l=linein(mydb)
Parse Var l a (x05) b
If category=''|,
category='-' & b=''|,
b=category Then
Call o l
End
End
When command='end' Then
Leave
Otherwise Do
Say 'invalid command ('command')'
Call help
End
End
End
Say 'Bye'
Exit
o: Parse Value arg(1) With dt text
Say left(dt,8) text
Return
help:
Say 'add item[,[category][,date]] to add an item'
Say 'latest category to list the latest item of a category'
Say 'latest to list the latest item'
Say 'all category to list all items of a category'
Say 'all to list all items'
Say 'end to end this program'
Say 'Use category - to list items without category'
Return</syntaxhighlight>
{{out}}
<pre> Enter your commands, ?, or end
?
add item[,[category][,date]] to add an item
latest category to list the latest item of a category
latest to list the latest item
all category to list all items of a category
all to list all items
end to end this program
Use category - to list items without category
add item1
adding item item1/ dated 20141006
add item2
adding item item2/ dated 20141006
add item3,cat3
adding item item3/cat3 dated 20141006
add item4,cat3,20201910
adding item item4/cat3 dated 20201910
add item5,cat3,190201910
adding item item5/cat3 dated 190201910
all
20141006 item1 �
20141006 item2 �
20141006 item3 � cat3
20201910 item4 � cat3
190201910 item5 � cat3
latest
20201910 item4 � cat3
latest cat1
no matching item found
latest cat3
20201910 item4 � cat3
end
Bye</pre>
=={{header|Ruby}}==
<
require 'json'
require 'securerandom'
Line 2,846 ⟶ 4,725:
end
process_command_line *ARGV</
Sample session
Line 2,924 ⟶ 4,803:
</pre>
=={{header|
<syntaxhighlight lang="scala">object SimpleDatabase extends App {
type Entry = Array[String]
def asTSV(e: Entry) = e mkString "\t"
def fromTSV(s: String) = s split "\t"
val header = asTSV(Array("TIMESTAMP", "DESCRIPTION", "CATEGORY", "OTHER"))
def read(filename: String) = try {
scala.io.Source.fromFile(filename).getLines.drop(1).map(fromTSV)
} catch {
case e: java.io.FileNotFoundException => Nil
}
def write(filename: String, all: Seq[Entry]) = {
import java.nio.file.{Files,Paths}
import scala.collection.JavaConversions.asJavaIterable
Files.write(Paths.get(filename), asJavaIterable(header +: all.map(asTSV)))
all.size
}
def add(filename: String, description: String, category: String = "none", optional: Seq[String] = Nil) {
val format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val e = Array(format.format(new java.util.Date), description, category) ++ optional
println(write(filename, read(filename).toBuffer :+ e) + " entries")
}
def print(filename: String, filter: Seq[Entry] => TraversableOnce[Entry]) =
filter(read(filename).toList.sortBy(_.headOption)) map(_ mkString ",") foreach println
args match {
case Array(f, "latest") => print(f, _ takeRight 1)
case Array(f, "latest", cat) => print(f, _ filter(_.lift(2) == Some(cat)) takeRight 1)
case Array(f, "all") => print(f, _.toSeq)
case Array(f, "all", "latest") => print(f, _ groupBy (_ lift 2 getOrElse "") map{case (_, cat) => cat.last})
case Array(f, "add", desc) => add(f, desc, category = "")
case Array(f, "add", desc, cat, opt @ _*) => add(f, desc, cat, opt)
case _ => println("Usage: SimpleDatabase filename.tsv [all [latest]| latest [CATEGORY] | add [DESCRIPTION [CATEGORY [OPTIONAL]...]]]")
}
}</syntaxhighlight>
{{out}}
<pre>> SimpleDatabase
Usage: SimpleDatabase filename.tsv [all [latest]| latest [CATEGORY] | add [DESCRIPTION [CATEGORY [OPTIONAL]...]]]
> SimpleDatabase database.tsv all
> SimpleDatabase database.tsv add one
1 entries
> SimpleDatabase database.tsv add two test
2 entries
> SimpleDatabase database.tsv add three test optional
3 entries
> SimpleDatabase database.tsv add four final
4 entries
> SimpleDatabase database.tsv all
2014-10-03 12:00:01,one
2014-10-03 12:00:02,two,test
2014-10-03 12:00:03,three,test,optional
2014-10-03 12:00:04,four,final
> SimpleDatabase database.tsv all latest
2014-10-03 12:00:04,four,final
2014-10-03 12:00:03,three,test,optional
2014-10-03 12:00:01,one
> SimpleDatabase database.tsv latest
2014-10-03 12:00:04,four,final
> SimpleDatabase database.tsv latest test
2014-10-03 12:00:03,three,test,optional</pre>
=={{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.
<
package require Tcl 8.6
namespace eval udb {
Line 3,161 ⟶ 4,979:
}
udb::Store [lindex $argv 0]</
Sample session:
<
wrong # args: should be "udb.tcl dbfile subcommand ?args...?"
bash$ udb.tcl db ?
Line 3,253 ⟶ 5,071:
Title: Title 3
Category: bar
Date: Tue Nov 15 18:12:07 GMT 2011</
=={{header|ToffeeScript}}==
<
prog = require 'commander'
Line 3,340 ⟶ 5,158:
printFormatted entry
prog.parse process.argv</
=={{header|UNIX Shell}}==
This format is guaranteed to be human readable: if you can type it, you can read it.
<
db_create() {
Line 3,439 ⟶ 5,257:
show_help
;;
esac</
Sample usage (assuming script is named "sdb"):<syntaxhighlight lang="text">$ sdb create CDs
Create DB `CDs'
$ sdb add CDs Bookends
Line 3,476 ⟶ 5,294:
$ sdb drop CDs
Delete DB `CDs'
$</
=={{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>
|