1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-23 05:44:53 +00:00

Prototype arbitrary result ordering

This commit is contained in:
J. King 2019-04-03 15:02:59 -04:00
parent 74fc39fca0
commit 4b133bddd6

View file

@ -1226,7 +1226,7 @@ class Database {
* @param Context $context The search context * @param Context $context The search context
* @param array $cols The columns to request in the result set * @param array $cols The columns to request in the result set
*/ */
protected function articleQuery(string $user, Context $context, array $cols = ["id"]): Query { protected function articleQuery(string $user, Context $context, array $cols = ["id"], array $sort = []): Query {
// validate input // validate input
if ($context->subscription()) { if ($context->subscription()) {
$this->subscriptionValidateId($user, $context->subscription); $this->subscriptionValidateId($user, $context->subscription);
@ -1275,23 +1275,55 @@ class Database {
'media_type' => "arsse_enclosures.type", 'media_type' => "arsse_enclosures.type",
]; ];
if (!$cols) { if (!$cols) {
// if no columns are specified return a count // if no columns are specified return a count; don't borther with sorting
$columns = "count(distinct arsse_articles.id) as count"; $outColumns = "count(distinct arsse_articles.id) as count";
$sortColumns = [];
} else { } else {
$columns = []; // normalize requested output and sorting columns
$norm = function($v) {
return trim(strtolower(ValueInfo::normalize($v, ValueInfo::T_STRING)));
};
$cols = array_map($norm, $cols);
$sort = array_map($norm, $sort);
// make an output column list
$outColumns = [];
foreach ($cols as $col) { foreach ($cols as $col) {
$col = trim(strtolower($col));
if (!isset($colDefs[$col])) { if (!isset($colDefs[$col])) {
continue; continue;
} }
$columns[] = $colDefs[$col]." as ".$col; $outColumns[] = $colDefs[$col]." as ".$col;
}
$outColumns = implode(",", $outColumns);
// make an ORDER BY column list
$sortColumns = [];
foreach ($sort as $spec) {
$col = explode(" ", $spec, 1);
$order = $col[1] ?? "";
$col = $col[0];
if ($order === "desc") {
$order = " desc";
} elseif ($order === "asc" || $order === "") {
$order = "";
} else {
// column direction spec is bogus
continue;
}
if (!isset($colDefs[$col])) {
// column name spec is bogus
continue;
} elseif (in_array($col, $cols)) {
// if the sort column is also an output column, use it as-is
$sortColumns[] = $col.$order;
} else {
// otherwise if the column name is valid, use its expression
$sortColumns[] = $colDefs[$col].$order;
}
} }
$columns = implode(",", $columns);
} }
// define the basic query, to which we add lots of stuff where necessary // define the basic query, to which we add lots of stuff where necessary
$q = new Query( $q = new Query(
"SELECT "SELECT
$columns $outColumns
from arsse_articles from arsse_articles
join arsse_subscriptions on arsse_subscriptions.feed = arsse_articles.feed and arsse_subscriptions.owner = ? join arsse_subscriptions on arsse_subscriptions.feed = arsse_articles.feed and arsse_subscriptions.owner = ?
join arsse_feeds on arsse_subscriptions.feed = arsse_feeds.id join arsse_feeds on arsse_subscriptions.feed = arsse_feeds.id
@ -1307,6 +1339,10 @@ class Database {
[$user, $user] [$user, $user]
); );
$q->setLimit($context->limit, $context->offset); $q->setLimit($context->limit, $context->offset);
// apply the ORDER BY definition computed above
array_walk($sortColumns, function($v, $k, Query $q) {
$q->setOrder($v);
}, $q);
// handle the simple context options // handle the simple context options
$options = [ $options = [
// each context array consists of a column identifier (see $colDefs above), a comparison operator, a data type, and an option to pair with for BETWEEN evaluation // each context array consists of a column identifier (see $colDefs above), a comparison operator, a data type, and an option to pair with for BETWEEN evaluation
@ -1492,20 +1528,20 @@ class Database {
"authorTerms" => ["arsse_articles.author"], "authorTerms" => ["arsse_articles.author"],
"annotationTerms" => ["arsse_marks.note"], "annotationTerms" => ["arsse_marks.note"],
]; ];
foreach ($options as $m => $cols) { foreach ($options as $m => $columns) {
if (!$context->$m()) { if (!$context->$m()) {
continue; continue;
} elseif (!$context->$m) { } elseif (!$context->$m) {
throw new Db\ExceptionInput("tooShort", ['field' => $m, 'action' => $this->caller(), 'min' => 1]); // must have at least one array element throw new Db\ExceptionInput("tooShort", ['field' => $m, 'action' => $this->caller(), 'min' => 1]); // must have at least one array element
} }
$q->setWhere(...$this->generateSearch($context->$m, $cols)); $q->setWhere(...$this->generateSearch($context->$m, $columns));
} }
// further handle exclusionary text-matching context options // further handle exclusionary text-matching context options
foreach ($options as $m => $cols) { foreach ($options as $m => $columns) {
if (!$context->not->$m() || !$context->not->$m) { if (!$context->not->$m() || !$context->not->$m) {
continue; continue;
} }
$q->setWhereNot(...$this->generateSearch($context->not->$m, $cols, true)); $q->setWhereNot(...$this->generateSearch($context->not->$m, $columns, true));
} }
// return the query // return the query
return $q; return $q;