119 lines
2.7 KiB
Perl
119 lines
2.7 KiB
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;
|
|
}
|
|
}
|