website/lib/DB.rakumod

98 lines
2.7 KiB
Raku

use v6.e.PREVIEW;
#| Post database
unit module DB;
use Pandoc;
use JSON::Class:auth<zef:vrurg>;
use DB::Post;
use DB::BlogMeta;
use DB::MarkdownPost;
use DB::IdrisPost;
use DB::PlaceholderPost;
subset PostTypes where MarkdownPost:D | IdrisPost:D | PlaceholderPost:D;
#| The top level posts database
class PostDB {
#| The metadata for the blog
has BlogMeta:D $.meta is required;
#| A mapping from post ids to posts
# has %.posts is Posts;
has %.posts{Int} of PostTypes = %();
#| The post id to use for placeholder posts
has Int $.placeholder-id = 0;
#| Get the next unused post ID
method next-post-id(--> Int) {
if %!posts.elems > 0 {
%!posts.keys.max + 1
} else {
0
}
}
#| Insert a new post to the DB, returning its id
method insert-post(PostTypes $post --> Int) {
my $id = self.next-post-id;
%!posts{$id} = $post;
$id
}
#| Initialize a new database
method init(BlogMeta:D $meta --> PostDB:D) {
my %posts{Int} of PostTypes = %();
%posts{0} = PlaceholderPost.empty;
PostDB.new(
meta => $meta,
posts => %posts,
)
}
#| Write a database to a directory
method write(IO::Path:D $dir) {
my $posts-dir = $dir.add('posts/');
# Make sure directory structrue exists
mkdir $dir unless $dir.e;
mkdir $posts-dir unless $posts-dir.e;
# Write out metadata
# TODO: Track changes and only write changed files
$dir.add('meta.json').spurt: $!meta.to-json;
# Write out posts (ids are the filename)
for %!posts.kv -> $key, $value {
$posts-dir.add("$key.json").spurt: $value.to-json;
}
}
}
sub read-db(IO::Path:D $dir --> PostDB:D) is export {
my $posts-dir = $dir.add('posts/');
die "DB directory does not exist" unless $dir.e;
die "posts directory does not exist" unless $posts-dir.e;
# Read metadata
my $meta = BlogMeta.from-json: $dir.add('meta.json').slurp;
# Read posts
my %posts{Int} of PostTypes = %();
for dir $posts-dir -> $post {
my $id = $post.extension("").basename.Int;
# TODO: Dejankify this, maybe see if we can work with parsed, but
# unmarshalled json
given $post.slurp {
when /'"placeholder": true'/ {
%posts{$id} = PlaceholderPost.from-json: $_;
}
when /'"markdown": true'/ {
%posts{$id} = MarkdownPost.from-json: $_;
}
when /'"idris": true'/ {
%posts{$id} = IdrisPost.from-json: $_;
}
default {
die "Unsupported post type: $post";
}
}
}
# Build db structure
PostDB.new: meta => $meta, posts => %posts
}