mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2025-01-11 10:22:40 +00:00
Implement most multiple-item context options
Selecting multiple folder trees will require further effort
This commit is contained in:
parent
ba32ad2f17
commit
ef1b761f95
2 changed files with 78 additions and 30 deletions
102
lib/Database.php
102
lib/Database.php
|
@ -1323,7 +1323,9 @@ class Database {
|
||||||
"markedSince" => ["marked_date", ">=", "datetime", "notMarkedSince"],
|
"markedSince" => ["marked_date", ">=", "datetime", "notMarkedSince"],
|
||||||
"notMarkedSince" => ["marked_date", "<=", "datetime", "markedSince"],
|
"notMarkedSince" => ["marked_date", "<=", "datetime", "markedSince"],
|
||||||
"folderShallow" => ["folder", "=", "int", ""],
|
"folderShallow" => ["folder", "=", "int", ""],
|
||||||
|
"foldersShallow" => ["folder", "in", "int", ""],
|
||||||
"subscription" => ["subscription", "=", "int", ""],
|
"subscription" => ["subscription", "=", "int", ""],
|
||||||
|
"subscriptions" => ["subscription", "in", "int", ""],
|
||||||
"unread" => ["unread", "=", "bool", ""],
|
"unread" => ["unread", "=", "bool", ""],
|
||||||
"starred" => ["starred", "=", "bool", ""],
|
"starred" => ["starred", "=", "bool", ""],
|
||||||
];
|
];
|
||||||
|
@ -1374,6 +1376,76 @@ class Database {
|
||||||
$q->setWhereNot("{$colDefs[$col]} $op ?", $type, $context->not->$m);
|
$q->setWhereNot("{$colDefs[$col]} $op ?", $type, $context->not->$m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// handle labels and tags
|
||||||
|
$options = [
|
||||||
|
'label' => [
|
||||||
|
'match_col' => "arsse_articles.id",
|
||||||
|
'cte_name' => "labelled",
|
||||||
|
'cte_cols' => ["article", "label_id", "label_name"],
|
||||||
|
'cte_body' => "SELECT m.article, l.id, l.name from arsse_label_members as m join arsse_labels as l on l.id = m.label where l.owner = ? and m.assigned = 1",
|
||||||
|
'cte_types' => ["str"],
|
||||||
|
'cte_values' => [$user],
|
||||||
|
'options' => [
|
||||||
|
'label' => ['use_name' => false, 'multi' => false],
|
||||||
|
'labels' => ['use_name' => false, 'multi' => true],
|
||||||
|
'labelName' => ['use_name' => true, 'multi' => false],
|
||||||
|
'labelNames' => ['use_name' => true, 'multi' => true],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'tag' => [
|
||||||
|
'match_col' => "arsse_subscriptions.id",
|
||||||
|
'cte_name' => "tagged",
|
||||||
|
'cte_cols' => ["subscription", "tag_id", "tag_name"],
|
||||||
|
'cte_body' => "SELECT m.subscription, t.id, t.name from arsse_tag_members as m join arsse_tags as t on t.id = m.tag where t.owner = ? and m.assigned = 1",
|
||||||
|
'cte_types' => ["str"],
|
||||||
|
'cte_values' => [$user],
|
||||||
|
'options' => [
|
||||||
|
'tag' => ['use_name' => false, 'multi' => false],
|
||||||
|
'tags' => ['use_name' => false, 'multi' => true],
|
||||||
|
'tagName' => ['use_name' => true, 'multi' => false],
|
||||||
|
'tagNames' => ['use_name' => true, 'multi' => true],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
foreach ($options as $opt) {
|
||||||
|
$seen = false;
|
||||||
|
$match = $opt['match_col'];
|
||||||
|
$table = $opt['cte_name'];
|
||||||
|
foreach ($opt['options'] as $m => $props) {
|
||||||
|
$named = $props['use_name'];
|
||||||
|
$multi = $props['multi'];
|
||||||
|
$selection = $opt['cte_cols'][0];
|
||||||
|
$col = $opt['cte_cols'][$named ? 2 : 1];
|
||||||
|
if ($context->$m()) {
|
||||||
|
$seen = true;
|
||||||
|
if ($multi) {
|
||||||
|
list($test, $types, $values) = $this->generateIn($context->$m, $named ? "str" : "int");
|
||||||
|
$test = "in ($test)";
|
||||||
|
} else {
|
||||||
|
$test = "= ?";
|
||||||
|
$types = $named ? "str" : "int";
|
||||||
|
$values = $context->$m;
|
||||||
|
}
|
||||||
|
$q->setWhere("$match in (select $selection from $table where $col $test)", $types, $values);
|
||||||
|
}
|
||||||
|
if ($context->not->$m()) {
|
||||||
|
$seen = true;
|
||||||
|
if ($multi) {
|
||||||
|
list($test, $types, $values) = $this->generateIn($context->not->$m, $named ? "str" : "int");
|
||||||
|
$test = "in ($test)";
|
||||||
|
} else {
|
||||||
|
$test = "= ?";
|
||||||
|
$types = $named ? "str" : "int";
|
||||||
|
$values = $context->not->$m;
|
||||||
|
}
|
||||||
|
$q->setWhereNot("$match in (select $selection from $table where $col $test)", $types, $values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($seen) {
|
||||||
|
$spec = $opt['cte_name']."(".implode(",",$opt['cte_cols']).")";
|
||||||
|
$q->setCTE($spec, $opt['cte_body'], $opt['cte_types'], $opt['cte_values']);
|
||||||
|
}
|
||||||
|
}
|
||||||
// handle complex context options
|
// handle complex context options
|
||||||
if ($context->annotated()) {
|
if ($context->annotated()) {
|
||||||
$comp = ($context->annotated) ? "<>" : "=";
|
$comp = ($context->annotated) ? "<>" : "=";
|
||||||
|
@ -1384,36 +1456,6 @@ class Database {
|
||||||
$op = $context->labelled ? ">" : "=";
|
$op = $context->labelled ? ">" : "=";
|
||||||
$q->setWhere("coalesce(label_stats.assigned,0) $op 0");
|
$q->setWhere("coalesce(label_stats.assigned,0) $op 0");
|
||||||
}
|
}
|
||||||
if ($context->label() || $context->not->label() || $context->labelName() || $context->not->labelName()) {
|
|
||||||
$q->setCTE("labelled(article,label_id,label_name)","SELECT m.article, l.id, l.name from arsse_label_members as m join arsse_labels as l on l.id = m.label where l.owner = ? and m.assigned = 1", "str", $user);
|
|
||||||
if ($context->label()) {
|
|
||||||
$q->setWhere("arsse_articles.id in (select article from labelled where label_id = ?)", "int", $context->label);
|
|
||||||
}
|
|
||||||
if ($context->not->label()) {
|
|
||||||
$q->setWhereNot("arsse_articles.id in (select article from labelled where label_id = ?)", "int", $context->not->label);
|
|
||||||
}
|
|
||||||
if ($context->labelName()) {
|
|
||||||
$q->setWhere("arsse_articles.id in (select article from labelled where label_name = ?)", "str", $context->labelName);
|
|
||||||
}
|
|
||||||
if ($context->not->labelName()) {
|
|
||||||
$q->setWhereNot("arsse_articles.id in (select article from labelled where label_name = ?)", "str", $context->not->labelName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($context->tag() || $context->not->tag() || $context->tagName() || $context->not->tagName()) {
|
|
||||||
$q->setCTE("tagged(id,name,subscription)","SELECT arsse_tags.id, arsse_tags.name, arsse_tag_members.subscription FROM arsse_tag_members join arsse_tags on arsse_tags.id = arsse_tag_members.tag WHERE arsse_tags.owner = ? and assigned = 1", "str", $user);
|
|
||||||
if ($context->tag()) {
|
|
||||||
$q->setWhere("arsse_subscriptions.id in (select subscription from tagged where id = ?)", "int", $context->tag);
|
|
||||||
}
|
|
||||||
if ($context->not->tag()) {
|
|
||||||
$q->setWhereNot("arsse_subscriptions.id in (select subscription from tagged where id = ?)", "int", $context->not->tag);
|
|
||||||
}
|
|
||||||
if ($context->tagName()) {
|
|
||||||
$q->setWhere("arsse_subscriptions.id in (select subscription from tagged where name = ?)", "str", $context->tagName);
|
|
||||||
}
|
|
||||||
if ($context->not->tagName()) {
|
|
||||||
$q->setWhereNot("arsse_subscriptions.id in (select subscription from tagged where name = ?)", "str", $context->not->tagName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($context->folder()) {
|
if ($context->folder()) {
|
||||||
// add a common table expression to list the folder and its children so that we select from the entire subtree
|
// add a common table expression to list the folder and its children so that we select from the entire subtree
|
||||||
$q->setCTE("folders(folder)", "SELECT ? union select id from arsse_folders join folders on parent = folder", "int", $context->folder);
|
$q->setCTE("folders(folder)", "SELECT ? union select id from arsse_folders join folders on parent = folder", "int", $context->folder);
|
||||||
|
|
|
@ -427,7 +427,9 @@ trait SeriesArticle {
|
||||||
'Leaf folder' => [(new Context)->folder(6), [7,8]],
|
'Leaf folder' => [(new Context)->folder(6), [7,8]],
|
||||||
'Root folder only' => [(new Context)->folderShallow(0), [1,2,3,4]],
|
'Root folder only' => [(new Context)->folderShallow(0), [1,2,3,4]],
|
||||||
'Shallow folder' => [(new Context)->folderShallow(1), [5,6]],
|
'Shallow folder' => [(new Context)->folderShallow(1), [5,6]],
|
||||||
|
'Multiple shallow folders' => [(new Context)->foldersShallow([1,6]), [5,6,7,8]],
|
||||||
'Subscription' => [(new Context)->subscription(5), [19,20]],
|
'Subscription' => [(new Context)->subscription(5), [19,20]],
|
||||||
|
'Multiple subscriptions' => [(new Context)->subscriptions([4,5]), [7,8,19,20]],
|
||||||
'Unread' => [(new Context)->subscription(5)->unread(true), [20]],
|
'Unread' => [(new Context)->subscription(5)->unread(true), [20]],
|
||||||
'Read' => [(new Context)->subscription(5)->unread(false), [19]],
|
'Read' => [(new Context)->subscription(5)->unread(false), [19]],
|
||||||
'Starred' => [(new Context)->starred(true), [1,20]],
|
'Starred' => [(new Context)->starred(true), [1,20]],
|
||||||
|
@ -458,8 +460,10 @@ trait SeriesArticle {
|
||||||
'Reversed paged results' => [(new Context)->limit(2)->latestEdition(7)->reverse(true), [7,6]],
|
'Reversed paged results' => [(new Context)->limit(2)->latestEdition(7)->reverse(true), [7,6]],
|
||||||
'With label ID 1' => [(new Context)->label(1), [1,19]],
|
'With label ID 1' => [(new Context)->label(1), [1,19]],
|
||||||
'With label ID 2' => [(new Context)->label(2), [1,5,20]],
|
'With label ID 2' => [(new Context)->label(2), [1,5,20]],
|
||||||
|
'With label ID 1 or 2' => [(new Context)->labels([1,2]), [1,5,19,20]],
|
||||||
'With label "Interesting"' => [(new Context)->labelName("Interesting"), [1,19]],
|
'With label "Interesting"' => [(new Context)->labelName("Interesting"), [1,19]],
|
||||||
'With label "Fascinating"' => [(new Context)->labelName("Fascinating"), [1,5,20]],
|
'With label "Fascinating"' => [(new Context)->labelName("Fascinating"), [1,5,20]],
|
||||||
|
'With label "Interesting" or "Fascinating"' => [(new Context)->labelNames(["Interesting","Fascinating"]), [1,5,19,20]],
|
||||||
'Article ID 20' => [(new Context)->article(20), [20]],
|
'Article ID 20' => [(new Context)->article(20), [20]],
|
||||||
'Edition ID 1001' => [(new Context)->edition(1001), [20]],
|
'Edition ID 1001' => [(new Context)->edition(1001), [20]],
|
||||||
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
||||||
|
@ -494,8 +498,10 @@ trait SeriesArticle {
|
||||||
'Search 501 terms' => [(new Context)->searchTerms(array_merge(range(1,500),[str_repeat("a", 1000)])), []],
|
'Search 501 terms' => [(new Context)->searchTerms(array_merge(range(1,500),[str_repeat("a", 1000)])), []],
|
||||||
'With tag ID 1' => [(new Context)->tag(1), [5,6,7,8]],
|
'With tag ID 1' => [(new Context)->tag(1), [5,6,7,8]],
|
||||||
'With tag ID 5' => [(new Context)->tag(5), [7,8,19,20]],
|
'With tag ID 5' => [(new Context)->tag(5), [7,8,19,20]],
|
||||||
|
'With tag ID 1 or 5' => [(new Context)->tags([1,5]), [5,6,7,8,19,20]],
|
||||||
'With tag "Technology"' => [(new Context)->tagName("Technology"), [5,6,7,8]],
|
'With tag "Technology"' => [(new Context)->tagName("Technology"), [5,6,7,8]],
|
||||||
'With tag "Politics"' => [(new Context)->tagName("Politics"), [7,8,19,20]],
|
'With tag "Politics"' => [(new Context)->tagName("Politics"), [7,8,19,20]],
|
||||||
|
'With tag "Technology" or "Politics"' => [(new Context)->tagNames(["Technology","Politics"]), [5,6,7,8,19,20]],
|
||||||
'Excluding tag ID 1' => [(new Context)->not->tag(1), [1,2,3,4,19,20]],
|
'Excluding tag ID 1' => [(new Context)->not->tag(1), [1,2,3,4,19,20]],
|
||||||
'Excluding tag ID 5' => [(new Context)->not->tag(5), [1,2,3,4,5,6]],
|
'Excluding tag ID 5' => [(new Context)->not->tag(5), [1,2,3,4,5,6]],
|
||||||
'Excluding tag "Technology"' => [(new Context)->not->tagName("Technology"), [1,2,3,4,19,20]],
|
'Excluding tag "Technology"' => [(new Context)->not->tagName("Technology"), [1,2,3,4,19,20]],
|
||||||
|
|
Loading…
Reference in a new issue