use v6.d;
use DB::SQLite;
class App::MediaControl::DB {
has DB::SQLite $.pool is required;
method !db(Callable:D $code) {
my $conn = self.pool.db;
LEAVE { .finish with $conn };
$conn.begin;
$conn.execute('PRAGMA foreign_keys=true');
KEEP { .commit with $conn };
return $code($conn) with $conn;
}
method ensure-schema() {
return if self!db: { .query(
'SELECT 1 FROM sqlite_schema WHERE type=? AND tbl_name=?',
'table', 'files',
).value.defined };
self!db: {
.query(q:to/END/);
CREATE TABLE files (
id INTEGER PRIMARY KEY,
parent_id INTEGER NULL REFERENCES files(id)
ON DELETE CASCADE,
matpath TEXT NOT NULL,
name TEXT NOT NULL,
is_dir BOOLEAN NOT NULL,
watched_time INTEGER NULL,
seen BOOLEAN NOT NULL DEFAULT false,
UNIQUE (matpath, name)
)
END
}
}
method clear-seen() {
self!db: {
.query(q:to/END/)
UPDATE files SET seen=false
END
}
}
method remove-unseen() {
self!db: {
.query(q:to/END/)
DELETE FROM files
WHERE seen=false
END
}
}
method add-entry(Str:D() :$path! is copy, Str:D() :$name!, Bool:D() :$is-dir!) {
$path ~~ s{<!after '/'>$} = '/';
$path ~~ s{<!before '/'>^} = '/';
note "add-entry($path,$name)";
self!db: {
.query(q:to/END/, :$path, :$name, :is_dir($is-dir));
WITH parent(id,path) AS (
SELECT id, matpath || name || '/' FROM files
),
newrow(path,name,is_dir) AS (
VALUES($path, $name, $is_dir)
)
INSERT INTO files(parent_id,matpath,name,is_dir,seen)
SELECT id, newrow.path, name, is_dir, true
FROM newrow
LEFT JOIN parent ON parent.path=newrow.path
WHERE true
ON CONFLICT (matpath,name) DO UPDATE SET seen=true
END
}
}
method remove-entry(Str:D() :$path! is copy, Str:D() :$name!) {
$path ~~ s{<!after '/'>$} = '/';
$path ~~ s{<!before '/'>^} = '/';
note "remove-entry($path,$name)";
self!db: {
.query(q:to/END/, :$path, :$name);
DELETE FROM files
WHERE name=$name
AND matpath=$path
END
}
}
multi method get-children-of(Any:U $id) {
self!get-children('IS NULL');
}
multi method get-children-of(Int:D() $id) {
self!get-children('=$id',$id);
}
method !get-children(Str $clause, *@binds) {
self!db: {
.query(qq:to/END/,|@binds).hashes;
SELECT id, name, is_dir
FROM files
WHERE parent_id $clause
END
}
}
method get-entry(Int:D() $id) {
self!db: {
.query(q:to/END/,$id).hash;
SELECT id, matpath, name, is_dir
FROM files
WHERE id=$id
END
}
}
}