mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-23 09:02:41 +00:00
Clarify various SQL queries
This commit is contained in:
parent
6000d80b7b
commit
e2cba68c1b
2 changed files with 139 additions and 104 deletions
180
lib/Database.php
180
lib/Database.php
|
@ -428,14 +428,18 @@ class Database {
|
||||||
$parent = $this->folderValidateId($user, $parent)['id'];
|
$parent = $this->folderValidateId($user, $parent)['id'];
|
||||||
$q = new Query(
|
$q = new Query(
|
||||||
"SELECT
|
"SELECT
|
||||||
id,name,parent,
|
id,
|
||||||
(select count(*) from arsse_folders as parents where coalesce(parents.parent,0) = coalesce(arsse_folders.id,0)) as children,
|
name,
|
||||||
(select count(*) from arsse_subscriptions where coalesce(folder,0) = coalesce(arsse_folders.id,0)) as feeds
|
arsse_folders.parent as parent,
|
||||||
FROM arsse_folders"
|
coalesce(children,0) as children,
|
||||||
|
coalesce(feeds,0) as feeds
|
||||||
|
FROM arsse_folders
|
||||||
|
left join (SELECT parent,count(id) as children from arsse_folders group by parent) as child_stats on child_stats.parent = arsse_folders.id
|
||||||
|
left join (SELECT folder,count(id) as feeds from arsse_subscriptions group by folder) as sub_stats on sub_stats.folder = arsse_folders.id"
|
||||||
);
|
);
|
||||||
if (!$recursive) {
|
if (!$recursive) {
|
||||||
$q->setWhere("owner = ?", "str", $user);
|
$q->setWhere("owner = ?", "str", $user);
|
||||||
$q->setWhere("coalesce(parent,0) = ?", "strict int", $parent);
|
$q->setWhere("coalesce(arsse_folders.parent,0) = ?", "strict int", $parent);
|
||||||
} else {
|
} else {
|
||||||
$q->setCTE("folders", "SELECT id from arsse_folders where owner = ? and coalesce(parent,0) = ? union select arsse_folders.id from arsse_folders join folders on arsse_folders.parent=folders.id", ["str", "strict int"], [$user, $parent]);
|
$q->setCTE("folders", "SELECT id from arsse_folders where owner = ? and coalesce(parent,0) = ? union select arsse_folders.id from arsse_folders join folders on arsse_folders.parent=folders.id", ["str", "strict int"], [$user, $parent]);
|
||||||
$q->setWhere("id in (SELECT id from folders)");
|
$q->setWhere("id in (SELECT id from folders)");
|
||||||
|
@ -687,22 +691,23 @@ class Database {
|
||||||
$q = new Query(
|
$q = new Query(
|
||||||
"SELECT
|
"SELECT
|
||||||
arsse_subscriptions.id as id,
|
arsse_subscriptions.id as id,
|
||||||
feed,url,favicon,source,folder,pinned,err_count,err_msg,order_type,added,
|
arsse_subscriptions.feed,
|
||||||
|
url,favicon,source,folder,pinned,err_count,err_msg,order_type,added,
|
||||||
arsse_feeds.updated as updated,
|
arsse_feeds.updated as updated,
|
||||||
topmost.top as top_folder,
|
topmost.top as top_folder,
|
||||||
coalesce(arsse_subscriptions.title, arsse_feeds.title) as title,
|
coalesce(arsse_subscriptions.title, arsse_feeds.title) as title,
|
||||||
(SELECT count(*) from arsse_articles where feed = arsse_subscriptions.feed) - (SELECT count(*) from arsse_marks where subscription = arsse_subscriptions.id and \"read\" = 1) as unread
|
(articles - marked) as unread
|
||||||
from arsse_subscriptions
|
FROM arsse_subscriptions
|
||||||
join userdata on userid = owner
|
left join topmost on topmost.f_id = arsse_subscriptions.folder
|
||||||
join arsse_feeds on feed = arsse_feeds.id
|
join arsse_feeds on arsse_feeds.id = arsse_subscriptions.feed
|
||||||
left join topmost on folder=f_id"
|
left join (select feed, count(*) as articles from arsse_articles group by feed) as article_stats on article_stats.feed = arsse_subscriptions.feed
|
||||||
|
left join (select subscription, sum(\"read\") as marked from arsse_marks group by subscription) as mark_stats on mark_stats.subscription = arsse_subscriptions.id"
|
||||||
);
|
);
|
||||||
|
$q->setWhere("arsse_subscriptions.owner = ?", ["str"], [$user]);
|
||||||
$nocase = $this->db->sqlToken("nocase");
|
$nocase = $this->db->sqlToken("nocase");
|
||||||
$q->setOrder("pinned desc, coalesce(arsse_subscriptions.title, arsse_feeds.title) collate $nocase");
|
$q->setOrder("pinned desc, coalesce(arsse_subscriptions.title, arsse_feeds.title) collate $nocase");
|
||||||
// define common table expressions
|
|
||||||
$q->setCTE("userdata(userid)", "SELECT ?", "str", $user); // the subject user; this way we only have to pass it to prepare() once
|
|
||||||
// topmost folders belonging to the user
|
// topmost folders belonging to the user
|
||||||
$q->setCTE("topmost(f_id,top)", "SELECT id,id from arsse_folders join userdata on owner = userid where parent is null union select id,top from arsse_folders join topmost on parent=f_id");
|
$q->setCTE("topmost(f_id,top)", "SELECT id,id from arsse_folders where owner = ? and parent is null union select id,top from arsse_folders join topmost on parent=f_id", ["str"], [$user]);
|
||||||
if ($id) {
|
if ($id) {
|
||||||
// this condition facilitates the implementation of subscriptionPropertiesGet, which would otherwise have to duplicate the complex query; it takes precedence over a specified folder
|
// this condition facilitates the implementation of subscriptionPropertiesGet, which would otherwise have to duplicate the complex query; it takes precedence over a specified folder
|
||||||
// if an ID is specified, add a suitable WHERE condition and bindings
|
// if an ID is specified, add a suitable WHERE condition and bindings
|
||||||
|
@ -801,7 +806,7 @@ class Database {
|
||||||
* - "order_type": Whether articles should be sorted in reverse cronological order (2), chronological order (1), or the default (0)
|
* - "order_type": Whether articles should be sorted in reverse cronological order (2), chronological order (1), or the default (0)
|
||||||
*
|
*
|
||||||
* @param string $user The user whose subscription is to be modified
|
* @param string $user The user whose subscription is to be modified
|
||||||
* @param integer|null $id the numeric identifier of the subscription to modfify
|
* @param integer $id the numeric identifier of the subscription to modfify
|
||||||
* @param array $data An associative array of properties to modify; any keys not specified will be left unchanged
|
* @param array $data An associative array of properties to modify; any keys not specified will be left unchanged
|
||||||
*/
|
*/
|
||||||
public function subscriptionPropertiesSet(string $user, $id, array $data): bool {
|
public function subscriptionPropertiesSet(string $user, $id, array $data): bool {
|
||||||
|
@ -873,7 +878,7 @@ class Database {
|
||||||
* Returns an associative array containing the id of the subscription and the id of the underlying newsfeed
|
* Returns an associative array containing the id of the subscription and the id of the underlying newsfeed
|
||||||
*
|
*
|
||||||
* @param string $user The user who owns the subscription to be validated
|
* @param string $user The user who owns the subscription to be validated
|
||||||
* @param integer|null $id The identifier of the subscription to validate
|
* @param integer $id The identifier of the subscription to validate
|
||||||
* @param boolean $subject Whether the subscription is the subject (true) rather than the object (false) of the operation being performed; this only affects the semantics of the error message if validation fails
|
* @param boolean $subject Whether the subscription is the subject (true) rather than the object (false) of the operation being performed; this only affects the semantics of the error message if validation fails
|
||||||
*/
|
*/
|
||||||
protected function subscriptionValidateId(string $user, $id, bool $subject = false): array {
|
protected function subscriptionValidateId(string $user, $id, bool $subject = false): array {
|
||||||
|
@ -1056,9 +1061,9 @@ class Database {
|
||||||
public function feedCleanup(): bool {
|
public function feedCleanup(): bool {
|
||||||
$tr = $this->begin();
|
$tr = $this->begin();
|
||||||
// first unmark any feeds which are no longer orphaned
|
// first unmark any feeds which are no longer orphaned
|
||||||
$this->db->query("UPDATE arsse_feeds set orphaned = null where exists(SELECT id from arsse_subscriptions where feed = arsse_feeds.id)");
|
$this->db->query("WITH active_feeds as (select id from arsse_feeds left join (select feed, count(id) as count from arsse_subscriptions group by feed) as sub_stats on sub_stats.feed = arsse_feeds.id where orphaned is not null and count is not null) UPDATE arsse_feeds set orphaned = null where id in (select id from active_feeds)");
|
||||||
// next mark any newly orphaned feeds with the current date and time
|
// next mark any newly orphaned feeds with the current date and time
|
||||||
$this->db->query("UPDATE arsse_feeds set orphaned = CURRENT_TIMESTAMP where orphaned is null and not exists(SELECT id from arsse_subscriptions where feed = arsse_feeds.id)");
|
$this->db->query("WITH orphaned_feeds as (select id from arsse_feeds left join (select feed, count(id) as count from arsse_subscriptions group by feed) as sub_stats on sub_stats.feed = arsse_feeds.id where orphaned is null and count is null) UPDATE arsse_feeds set orphaned = CURRENT_TIMESTAMP where id in (select id from orphaned_feeds)");
|
||||||
// finally delete feeds that have been orphaned longer than the retention period, if a a purge threshold has been specified
|
// finally delete feeds that have been orphaned longer than the retention period, if a a purge threshold has been specified
|
||||||
if (Arsse::$conf->purgeFeeds) {
|
if (Arsse::$conf->purgeFeeds) {
|
||||||
$limit = Date::sub(Arsse::$conf->purgeFeeds);
|
$limit = Date::sub(Arsse::$conf->purgeFeeds);
|
||||||
|
@ -1500,7 +1505,7 @@ class Database {
|
||||||
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
||||||
}
|
}
|
||||||
$id = $this->articleValidateId($user, $id)['article'];
|
$id = $this->articleValidateId($user, $id)['article'];
|
||||||
$out = $this->db->prepare("SELECT id,name from arsse_labels where owner = ? and exists(select id from arsse_label_members where article = ? and label = arsse_labels.id and assigned = 1)", "str", "int")->run($user, $id)->getAll();
|
$out = $this->db->prepare("SELECT id, name from arsse_labels join arsse_label_members on arsse_label_members.label = arsse_labels.id where owner = ? and article = ? and assigned = 1", "str", "int")->run($user, $id)->getAll();
|
||||||
// flatten the result to return just the label ID or name, sorted
|
// flatten the result to return just the label ID or name, sorted
|
||||||
$out = $out ? array_column($out, !$byName ? "id" : "name") : [];
|
$out = $out ? array_column($out, !$byName ? "id" : "name") : [];
|
||||||
sort($out);
|
sort($out);
|
||||||
|
@ -1525,30 +1530,16 @@ class Database {
|
||||||
/** Deletes from the database articles which are beyond the configured clean-up threshold */
|
/** Deletes from the database articles which are beyond the configured clean-up threshold */
|
||||||
public function articleCleanup(): bool {
|
public function articleCleanup(): bool {
|
||||||
$query = $this->db->prepare(
|
$query = $this->db->prepare(
|
||||||
"WITH target_feed(id,subs) as (".
|
"WITH RECURSIVE
|
||||||
"SELECT
|
exempt_articles as (SELECT id from arsse_articles join (SELECT article, max(id) as edition from arsse_editions group by article) as latest_editions on arsse_articles.id = latest_editions.article where feed = ? order by edition desc limit ?),
|
||||||
id, (select count(*) from arsse_subscriptions where feed = arsse_feeds.id) as subs
|
target_articles as (
|
||||||
from arsse_feeds where id = ?".
|
select id from arsse_articles
|
||||||
"), latest_editions(article,edition) as (".
|
left join (select article, sum(starred) as starred, sum(\"read\") as \"read\", max(arsse_marks.modified) as marked_date from arsse_marks join arsse_subscriptions on arsse_subscriptions.id = arsse_marks.subscription group by article) as mark_stats on mark_stats.article = arsse_articles.id
|
||||||
"SELECT article,max(id) from arsse_editions group by article".
|
left join (select feed, count(*) as subs from arsse_subscriptions group by feed) as feed_stats on feed_stats.feed = arsse_articles.feed
|
||||||
"), excepted_articles(id,edition) as (".
|
where arsse_articles.feed = ? and coalesce(starred,0) = 0 and (coalesce(marked_date,modified) <= ? or (coalesce(\"read\",0) = coalesce(subs,0) and coalesce(marked_date,modified) <= ?))
|
||||||
"SELECT
|
|
||||||
arsse_articles.id as id,
|
|
||||||
latest_editions.edition as edition
|
|
||||||
from arsse_articles
|
|
||||||
join target_feed on arsse_articles.feed = target_feed.id
|
|
||||||
join latest_editions on arsse_articles.id = latest_editions.article
|
|
||||||
order by edition desc limit ?".
|
|
||||||
") ".
|
|
||||||
"DELETE from arsse_articles where
|
|
||||||
feed = (select max(id) from target_feed)
|
|
||||||
and id not in (select id from excepted_articles)
|
|
||||||
and (select count(*) from arsse_marks where article = arsse_articles.id and starred = 1) = 0
|
|
||||||
and (
|
|
||||||
coalesce((select max(modified) from arsse_marks where article = arsse_articles.id),modified) <= ?
|
|
||||||
or ((select max(subs) from target_feed) = (select count(*) from arsse_marks where article = arsse_articles.id and \"read\" = 1) and coalesce((select max(modified) from arsse_marks where article = arsse_articles.id),modified) <= ?)
|
|
||||||
)
|
)
|
||||||
",
|
DELETE FROM arsse_articles WHERE id not in (select id from exempt_articles) and id in (select id from target_articles)",
|
||||||
|
"int",
|
||||||
"int",
|
"int",
|
||||||
"int",
|
"int",
|
||||||
"datetime",
|
"datetime",
|
||||||
|
@ -1564,7 +1555,7 @@ class Database {
|
||||||
}
|
}
|
||||||
$feeds = $this->db->query("SELECT id, size from arsse_feeds")->getAll();
|
$feeds = $this->db->query("SELECT id, size from arsse_feeds")->getAll();
|
||||||
foreach ($feeds as $feed) {
|
foreach ($feeds as $feed) {
|
||||||
$query->run($feed['id'], $feed['size'], $limitUnread, $limitRead);
|
$query->run($feed['id'], $feed['size'], $feed['id'], $limitUnread, $limitRead);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1574,21 +1565,19 @@ class Database {
|
||||||
* Returns an associative array containing the id and latest edition of the article if it exists
|
* Returns an associative array containing the id and latest edition of the article if it exists
|
||||||
*
|
*
|
||||||
* @param string $user The user who owns the article to be validated
|
* @param string $user The user who owns the article to be validated
|
||||||
* @param integer|null $id The identifier of the article to validate
|
* @param integer $id The identifier of the article to validate
|
||||||
*/
|
*/
|
||||||
protected function articleValidateId(string $user, $id): array {
|
protected function articleValidateId(string $user, $id): array {
|
||||||
if (!ValueInfo::id($id)) {
|
if (!ValueInfo::id($id)) {
|
||||||
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "article", 'type' => "int > 0"]); // @codeCoverageIgnore
|
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "article", 'type' => "int > 0"]); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
$out = $this->db->prepare(
|
$out = $this->db->prepare(
|
||||||
"SELECT
|
"SELECT articles.article as article, max(arsse_editions.id) as edition from (
|
||||||
arsse_articles.id as article,
|
select arsse_articles.id as article
|
||||||
(select max(id) from arsse_editions where article = arsse_articles.id) as edition
|
FROM arsse_articles
|
||||||
FROM arsse_articles
|
join arsse_subscriptions on arsse_subscriptions.feed = arsse_articles.feed
|
||||||
join arsse_feeds on arsse_feeds.id = arsse_articles.feed
|
WHERE arsse_articles.id = ? and arsse_subscriptions.owner = ?
|
||||||
join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id
|
) as articles join arsse_editions on arsse_editions.article = articles.article group by articles.article",
|
||||||
WHERE
|
|
||||||
arsse_articles.id = ? and arsse_subscriptions.owner = ?",
|
|
||||||
"int",
|
"int",
|
||||||
"str"
|
"str"
|
||||||
)->run($id, $user)->getRow();
|
)->run($id, $user)->getRow();
|
||||||
|
@ -1603,7 +1592,7 @@ class Database {
|
||||||
* Returns an associative array containing the edition id, article id, and latest edition of the edition if it exists
|
* Returns an associative array containing the edition id, article id, and latest edition of the edition if it exists
|
||||||
*
|
*
|
||||||
* @param string $user The user who owns the edition to be validated
|
* @param string $user The user who owns the edition to be validated
|
||||||
* @param integer|null $id The identifier of the edition to validate
|
* @param integer $id The identifier of the edition to validate
|
||||||
*/
|
*/
|
||||||
protected function articleValidateEdition(string $user, int $id): array {
|
protected function articleValidateEdition(string $user, int $id): array {
|
||||||
if (!ValueInfo::id($id)) {
|
if (!ValueInfo::id($id)) {
|
||||||
|
@ -1611,15 +1600,12 @@ class Database {
|
||||||
}
|
}
|
||||||
$out = $this->db->prepare(
|
$out = $this->db->prepare(
|
||||||
"SELECT
|
"SELECT
|
||||||
arsse_editions.id as edition,
|
arsse_editions.id, arsse_editions.article, edition_stats.edition as current
|
||||||
arsse_editions.article as article,
|
from arsse_editions
|
||||||
(arsse_editions.id = (select max(id) from arsse_editions where article = arsse_editions.article)) as current
|
join arsse_articles on arsse_articles.id = arsse_editions.article
|
||||||
FROM arsse_editions
|
join arsse_subscriptions on arsse_subscriptions.feed = arsse_articles.feed
|
||||||
join arsse_articles on arsse_editions.article = arsse_articles.id
|
join (select article, max(id) as edition from arsse_editions group by article) as edition_stats on edition_stats.article = arsse_editions.article
|
||||||
join arsse_feeds on arsse_feeds.id = arsse_articles.feed
|
where arsse_editions.id = ? and arsse_subscriptions.owner = ?",
|
||||||
join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id
|
|
||||||
WHERE
|
|
||||||
arsse_editions.id = ? and arsse_subscriptions.owner = ?",
|
|
||||||
"int",
|
"int",
|
||||||
"str"
|
"str"
|
||||||
)->run($id, $user)->getRow();
|
)->run($id, $user)->getRow();
|
||||||
|
@ -1693,18 +1679,28 @@ class Database {
|
||||||
return $this->db->prepare(
|
return $this->db->prepare(
|
||||||
"SELECT * FROM (
|
"SELECT * FROM (
|
||||||
SELECT
|
SELECT
|
||||||
id,name,
|
id,name,coalesce(articles,0) as articles,coalesce(marked,0) as \"read\"
|
||||||
(select count(*) from arsse_label_members where label = id and assigned = 1) as articles,
|
from arsse_labels
|
||||||
(select count(*) from arsse_label_members
|
left join (
|
||||||
join arsse_marks on arsse_label_members.article = arsse_marks.article and arsse_label_members.subscription = arsse_marks.subscription
|
SELECT label, sum(assigned) as articles from arsse_label_members group by label
|
||||||
where label = id and assigned = 1 and \"read\" = 1
|
) as label_stats on label_stats.label = arsse_labels.id
|
||||||
) as \"read\"
|
left join (
|
||||||
FROM arsse_labels where owner = ?) as label_data
|
SELECT
|
||||||
|
label, sum(\"read\") as marked
|
||||||
|
from arsse_marks
|
||||||
|
join arsse_subscriptions on arsse_subscriptions.id = arsse_marks.subscription
|
||||||
|
join arsse_label_members on arsse_label_members.article = arsse_marks.article
|
||||||
|
where arsse_subscriptions.owner = ?
|
||||||
|
group by label
|
||||||
|
) as mark_stats on mark_stats.label = arsse_labels.id
|
||||||
|
WHERE owner = ?
|
||||||
|
) as label_data
|
||||||
where articles >= ? order by name
|
where articles >= ? order by name
|
||||||
",
|
",
|
||||||
"str",
|
"str",
|
||||||
|
"str",
|
||||||
"int"
|
"int"
|
||||||
)->run($user, !$includeEmpty);
|
)->run($user, $user, !$includeEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Deletes a label from the database
|
/** Deletes a label from the database
|
||||||
|
@ -1751,17 +1747,26 @@ class Database {
|
||||||
$type = $byName ? "str" : "int";
|
$type = $byName ? "str" : "int";
|
||||||
$out = $this->db->prepare(
|
$out = $this->db->prepare(
|
||||||
"SELECT
|
"SELECT
|
||||||
id,name,
|
id,name,coalesce(articles,0) as articles,coalesce(marked,0) as \"read\"
|
||||||
(select count(*) from arsse_label_members where label = id and assigned = 1) as articles,
|
FROM arsse_labels
|
||||||
(select count(*) from arsse_label_members
|
left join (
|
||||||
join arsse_marks on arsse_label_members.article = arsse_marks.article and arsse_label_members.subscription = arsse_marks.subscription
|
SELECT label, sum(assigned) as articles from arsse_label_members group by label
|
||||||
where label = id and assigned = 1 and \"read\" = 1
|
) as label_stats on label_stats.label = arsse_labels.id
|
||||||
) as \"read\"
|
left join (
|
||||||
FROM arsse_labels where $field = ? and owner = ?
|
SELECT
|
||||||
|
label, sum(\"read\") as marked
|
||||||
|
from arsse_marks
|
||||||
|
join arsse_subscriptions on arsse_subscriptions.id = arsse_marks.subscription
|
||||||
|
join arsse_label_members on arsse_label_members.article = arsse_marks.article
|
||||||
|
where arsse_subscriptions.owner = ?
|
||||||
|
group by label
|
||||||
|
) as mark_stats on mark_stats.label = arsse_labels.id
|
||||||
|
WHERE $field = ? and owner = ?
|
||||||
",
|
",
|
||||||
|
"str",
|
||||||
$type,
|
$type,
|
||||||
"str"
|
"str"
|
||||||
)->run($id, $user)->getRow();
|
)->run($user, $id, $user)->getRow();
|
||||||
if (!$out) {
|
if (!$out) {
|
||||||
throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "label", 'id' => $id]);
|
throw new Db\ExceptionInput("subjectMissing", ["action" => __FUNCTION__, "field" => "label", 'id' => $id]);
|
||||||
}
|
}
|
||||||
|
@ -1846,27 +1851,14 @@ class Database {
|
||||||
$tr = $this->begin();
|
$tr = $this->begin();
|
||||||
// first update any existing entries with the removal or re-addition of their association
|
// first update any existing entries with the removal or re-addition of their association
|
||||||
$q = $this->articleQuery($user, $context);
|
$q = $this->articleQuery($user, $context);
|
||||||
$q->setWhere("exists(select article from arsse_label_members where label = ? and article = arsse_articles.id)", "int", $id);
|
|
||||||
$q->pushCTE("target_articles");
|
$q->pushCTE("target_articles");
|
||||||
$q->setBody(
|
$q->setBody("UPDATE arsse_label_members set assigned = ?, modified = CURRENT_TIMESTAMP where label = ? and assigned <> ? and article in (select id from target_articles)", ["bool","int","bool"], [!$remove, $id, !$remove]);
|
||||||
"UPDATE arsse_label_members set assigned = ?, modified = CURRENT_TIMESTAMP where label = ? and assigned <> ? and article in (select id from target_articles)",
|
|
||||||
["bool","int","bool"],
|
|
||||||
[!$remove, $id, !$remove]
|
|
||||||
);
|
|
||||||
$out += $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->changes();
|
$out += $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->changes();
|
||||||
// next, if we're not removing, add any new entries that need to be added
|
// next, if we're not removing, add any new entries that need to be added
|
||||||
if (!$remove) {
|
if (!$remove) {
|
||||||
$q = $this->articleQuery($user, $context, ["id", "feed"]);
|
$q = $this->articleQuery($user, $context, ["id", "subscription"]);
|
||||||
$q->setWhere("not exists(select article from arsse_label_members where label = ? and article = arsse_articles.id)", "int", $id);
|
|
||||||
$q->pushCTE("target_articles");
|
$q->pushCTE("target_articles");
|
||||||
$q->setBody(
|
$q->setBody("SELECT ?,id,subscription from target_articles where id not in (select article from arsse_label_members where label = ?)", ["int", "int"], [$id, $id]);
|
||||||
"SELECT
|
|
||||||
?,id,
|
|
||||||
(select id from arsse_subscriptions where owner = ? and arsse_subscriptions.feed = target_articles.feed)
|
|
||||||
FROM target_articles",
|
|
||||||
["int", "str"],
|
|
||||||
[$id, $user]
|
|
||||||
);
|
|
||||||
$out += $this->db->prepare("INSERT INTO arsse_label_members(label,article,subscription) ".$q->getQuery(), $q->getTypes())->run($q->getValues())->changes();
|
$out += $this->db->prepare("INSERT INTO arsse_label_members(label,article,subscription) ".$q->getQuery(), $q->getTypes())->run($q->getValues())->changes();
|
||||||
}
|
}
|
||||||
// commit the transaction
|
// commit the transaction
|
||||||
|
|
|
@ -49,6 +49,49 @@ trait SeriesFolder {
|
||||||
[6, "john.doe@example.com", 2, "Politics"],
|
[6, "john.doe@example.com", 2, "Politics"],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
'arsse_feeds' => [
|
||||||
|
'columns' => [
|
||||||
|
'id' => "int",
|
||||||
|
'url' => "str",
|
||||||
|
'title' => "str",
|
||||||
|
],
|
||||||
|
'rows' => [
|
||||||
|
[1,"http://example.com/1", "Feed 1"],
|
||||||
|
[2,"http://example.com/2", "Feed 2"],
|
||||||
|
[3,"http://example.com/3", "Feed 3"],
|
||||||
|
[4,"http://example.com/4", "Feed 4"],
|
||||||
|
[5,"http://example.com/5", "Feed 5"],
|
||||||
|
[6,"http://example.com/6", "Feed 6"],
|
||||||
|
[7,"http://example.com/7", "Feed 7"],
|
||||||
|
[8,"http://example.com/8", "Feed 8"],
|
||||||
|
[9,"http://example.com/9", "Feed 9"],
|
||||||
|
[10,"http://example.com/10", "Feed 10"],
|
||||||
|
[11,"http://example.com/11", "Feed 11"],
|
||||||
|
[12,"http://example.com/12", "Feed 12"],
|
||||||
|
[13,"http://example.com/13", "Feed 13"],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'arsse_subscriptions' => [
|
||||||
|
'columns' => [
|
||||||
|
'id' => "int",
|
||||||
|
'owner' => "str",
|
||||||
|
'feed' => "int",
|
||||||
|
'folder' => "int",
|
||||||
|
],
|
||||||
|
'rows' => [
|
||||||
|
[1, "john.doe@example.com",1, null],
|
||||||
|
[2, "john.doe@example.com",2, null],
|
||||||
|
[3, "john.doe@example.com",3, 1],
|
||||||
|
[4, "john.doe@example.com",4, 6],
|
||||||
|
[5, "john.doe@example.com",5, 5],
|
||||||
|
[6, "john.doe@example.com",10, 5],
|
||||||
|
[7, "jane.doe@example.com",1, null],
|
||||||
|
[8, "jane.doe@example.com",10,null],
|
||||||
|
[9, "jane.doe@example.com",2, 4],
|
||||||
|
[10,"jane.doe@example.com",3, 4],
|
||||||
|
[11,"jane.doe@example.com",4, 4],
|
||||||
|
]
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +162,8 @@ trait SeriesFolder {
|
||||||
|
|
||||||
public function testListRootFolders() {
|
public function testListRootFolders() {
|
||||||
$exp = [
|
$exp = [
|
||||||
['id' => 5, 'name' => "Politics", 'parent' => null, 'children' => 0],
|
['id' => 5, 'name' => "Politics", 'parent' => null, 'children' => 0, 'feeds' => 2],
|
||||||
['id' => 1, 'name' => "Technology", 'parent' => null, 'children' => 2],
|
['id' => 1, 'name' => "Technology", 'parent' => null, 'children' => 2, 'feeds' => 1],
|
||||||
];
|
];
|
||||||
$this->assertResult($exp, Arsse::$db->folderList("john.doe@example.com", null, false));
|
$this->assertResult($exp, Arsse::$db->folderList("john.doe@example.com", null, false));
|
||||||
$exp = [
|
$exp = [
|
||||||
|
@ -136,17 +179,17 @@ trait SeriesFolder {
|
||||||
|
|
||||||
public function testListFoldersRecursively() {
|
public function testListFoldersRecursively() {
|
||||||
$exp = [
|
$exp = [
|
||||||
['id' => 5, 'name' => "Politics", 'parent' => null, 'children' => 0],
|
['id' => 5, 'name' => "Politics", 'parent' => null, 'children' => 0, 'feeds' => 2],
|
||||||
['id' => 6, 'name' => "Politics", 'parent' => 2, 'children' => 0],
|
['id' => 6, 'name' => "Politics", 'parent' => 2, 'children' => 0, 'feeds' => 1],
|
||||||
['id' => 3, 'name' => "Rocketry", 'parent' => 1, 'children' => 0],
|
['id' => 3, 'name' => "Rocketry", 'parent' => 1, 'children' => 0, 'feeds' => 0],
|
||||||
['id' => 2, 'name' => "Software", 'parent' => 1, 'children' => 1],
|
['id' => 2, 'name' => "Software", 'parent' => 1, 'children' => 1, 'feeds' => 0],
|
||||||
['id' => 1, 'name' => "Technology", 'parent' => null, 'children' => 2],
|
['id' => 1, 'name' => "Technology", 'parent' => null, 'children' => 2, 'feeds' => 1],
|
||||||
];
|
];
|
||||||
$this->assertResult($exp, Arsse::$db->folderList("john.doe@example.com", null, true));
|
$this->assertResult($exp, Arsse::$db->folderList("john.doe@example.com", null, true));
|
||||||
$exp = [
|
$exp = [
|
||||||
['id' => 6, 'name' => "Politics", 'parent' => 2, 'children' => 0],
|
['id' => 6, 'name' => "Politics", 'parent' => 2, 'children' => 0, 'feeds' => 1],
|
||||||
['id' => 3, 'name' => "Rocketry", 'parent' => 1, 'children' => 0],
|
['id' => 3, 'name' => "Rocketry", 'parent' => 1, 'children' => 0, 'feeds' => 0],
|
||||||
['id' => 2, 'name' => "Software", 'parent' => 1, 'children' => 1],
|
['id' => 2, 'name' => "Software", 'parent' => 1, 'children' => 1, 'feeds' => 0],
|
||||||
];
|
];
|
||||||
$this->assertResult($exp, Arsse::$db->folderList("john.doe@example.com", 1, true));
|
$this->assertResult($exp, Arsse::$db->folderList("john.doe@example.com", 1, true));
|
||||||
$exp = [];
|
$exp = [];
|
||||||
|
|
Loading…
Reference in a new issue