diff --git a/lib/Database.php b/lib/Database.php index c5ff7709..e23cfe6c 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -1524,7 +1524,7 @@ class Database { * If an empty column list is supplied, a count of articles matching the context is queried instead * * @param string $user The user whose articles are to be queried - * @param RootContext $context The search context + * @param Context|UnionContext $context The search context * @param array $cols The columns to request in the result set */ protected function articleQuery(string $user, RootContext $context, array $cols = ["id"]): Query { @@ -1643,7 +1643,8 @@ class Database { return $q; } - protected function articleFilter(Context $context, QueryFilter $q = null) { + /** Transforms a selection context for articles into a set of terms for an SQL "where" clause */ + protected function articleFilter(Context $context, QueryFilter $q = null): QueryFilter { $q = $q ?? new QueryFilter; $colDefs = $this->articleColumns(); // handle the simple context options @@ -1919,11 +1920,10 @@ class Database { * * @param string $user The user who owns the articles to be modified * @param array $data An associative array of properties to modify. Anything not specified will remain unchanged - * @param RootContext $context The query context to match articles against + * @param Context|UnionContext $context The query context to match articles against * @param bool $updateTimestamp Whether to also update the timestamp. This should only be false if a mark is changed as a result of an automated action not taken by the user */ public function articleMark(string $user, array $data, RootContext $context = null, bool $updateTimestamp = true): int { - // normalize requested marks $data = [ 'read' => $data['read'] ?? null, 'starred' => $data['starred'] ?? null, @@ -1931,94 +1931,102 @@ class Database { 'note' => $data['note'] ?? null, ]; if (!isset($data['read']) && !isset($data['starred']) && !isset($data['hidden']) && !isset($data['note'])) { - // no changes were requested return 0; } - // begin a transaction - $tr = $this->begin(); $context = $context ?? new Context; - if ($context instanceof UnionContext) { - $out = 0; - // if we were provided a union context, mark each context in series; - // this is atomic (due to the transaction already begun), but may - // result in multiple timestamps as well as an inaccurate output - // integer as articles may be in multiple contexts - // TODO: The above quirks could be fixed by resolving the union - // context to a single list of article IDs noting which are - // valid read marks (if editions were selected in any of the child - // contexts); this functionality is not needed yet, however - foreach ($context as $c) { - $out += $this->articleMark($user, $data, $c, $updateTimestamp); - } - $tr->commit(); - return $out; - } - // prepare the subquery which selects the articles to act on - $subq = $this->articleQuery($user, $context); - $subq->setWhere("(arsse_articles.note <> coalesce(?,arsse_articles.note) or arsse_articles.starred <> coalesce(?,arsse_articles.starred) or arsse_articles.read <> coalesce(?,arsse_articles.read) or arsse_articles.hidden <> coalesce(?,arsse_articles.hidden))", ["str", "bool", "bool", "bool"], [$data['note'], $data['starred'], $data['read'], $data['hidden']]); - // if we're marking as read/unread by edition, we have to use a different query so that we only mark read/unread if the edition is the latest for the article - if (isset($data['read']) && ($context->edition() || $context->editions())) { - // set up the "SET" clause for the update - $setData = array_filter($data, function($v, $k) { - // filter out anyhing with a value of null (no change), as well as the "rea" key as it required special handling - return isset($v) && $k !== "read"; - }, \ARRAY_FILTER_USE_BOTH); - [$set, $setTypes, $setValues] = $this->generateSet($setData, ['read' => "bool", 'starred' => "bool", 'hidden' => "bool", 'note' => "str"]); - $set = $set ? "$set, " : ""; - $set .= "read = case when id in (select article from valid_read) then ? else \"read\" end"; - $setTypes[] = "bool"; - $setValues[] = $data['read']; - if ($updateTimestamp) { - $set .= ", marked = CURRENT_TIMESTAMP"; - } - // prepare the rest of the query - [$inClause, $inTypes, $inValues] = $this->generateIn($context->editions ?: (array) $context->edition, "int"); - $out = $this->db->prepare( + $tr = $this->begin(); + $out = 0; + if (isset($data['read']) && (isset($data['starred']) || isset($data['hidden']) || isset($data['note'])) && ($context->edition() || $context->editions())) { + // if marking by edition both read and something else, do separate marks for starred, hidden, and note than for read + // marking as read is ignored if the edition is not the latest, but the same is not true of the other two marks + $subq = $this->articleQuery($user, $context); + $subq->setWhere("arsse_articles.read <> coalesce(?,arsse_articles.read)", "bool", $data['read']); + $q = new Query( "WITH RECURSIVE - target_articles as ( + target_articles(article) as ( {$subq->getQuery()} - ), - valid_read as ( - select selected_editions.article from ( - select max(id) as edition, article from arsse_editions where id in ($inClause) group by article - ) as selected_editions join ( - SELECT max(id) as edition, article from arsse_editions group by article - ) as latest_editions on selected_editions.edition = latest_editions.edition ) update arsse_articles set - $set + \"read\" = ?, + touched = 1 where - id in (select id from target_articles)", - $subq->getTypes(), $inTypes, $setTypes - )->run( - $subq->getValues(), $inValues, $setValues - )->changes(); + id in (select article from target_articles)", + [$subq->getTypes(), "bool"], + [$subq->getValues(), $data['read']] + ); + $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues()); + // get the articles associated with the requested editions + if ($context->edition()) { + $context->article($this->articleValidateEdition($user, $context->edition)['article'])->edition(null); + } else { + $context->articles($this->editionArticle(...$context->editions))->editions(null); + } + // set starred, hidden, and/or note marks (unless all requested editions actually do not exist) + if ($context->article || $context->articles) { + $setData = array_filter($data, function($v) { + return isset($v); + }); + [$set, $setTypes, $setValues] = $this->generateSet($setData, ['starred' => "bool", 'hidden' => "bool", 'note' => "str"]); + $subq = $this->articleQuery($user, $context); + $subq->setWhere("(arsse_articles.note <> coalesce(?,arsse_articles.note) or arsse_articles.starred <> coalesce(?,arsse_articles.starred) or arsse_articles.hidden <> coalesce(?,arsse_articles.hidden))", ["str", "bool", "bool"], [$data['note'], $data['starred'], $data['hidden']]); + $q = new Query( + "WITH RECURSIVE + target_articles(article) as ( + {$subq->getQuery()} + ) + update arsse_articles + set + touched = 1, + $set + where + id in (select article from target_articles)", + [$subq->getTypes(), $setTypes], + [$subq->getValues(), $setValues] + ); + $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues()); + } + // finally set the modification date for all touched marks and return the number of affected marks + if ($updateTimestamp) { + $out = $this->db->query("UPDATE arsse_articles set marked = CURRENT_TIMESTAMP, touched = 0 where touched = 1")->changes(); + } else { + $out = $this->db->query("UPDATE arsse_articles set touched = 0 where touched = 1")->changes(); + } } else { - // set up the "SET" clause for the update + if (!isset($data['read']) && ($context->edition() || $context->editions())) { + // get the articles associated with the requested editions + if ($context->edition()) { + $context->article($this->articleValidateEdition($user, $context->edition)['article'])->edition(null); + } else { + $context->articles($this->editionArticle(...$context->editions))->editions(null); + } + if (!$context->article && !$context->articles) { + return 0; + } + } $setData = array_filter($data, function($v) { - // filter out anyhing with a value of null (no change) return isset($v); }); [$set, $setTypes, $setValues] = $this->generateSet($setData, ['read' => "bool", 'starred' => "bool", 'hidden' => "bool", 'note' => "str"]); if ($updateTimestamp) { $set .= ", marked = CURRENT_TIMESTAMP"; } - // prepare the rest of the query - $out = $this->db->prepare( + $subq = $this->articleQuery($user, $context); + $subq->setWhere("(arsse_articles.note <> coalesce(?,arsse_articles.note) or arsse_articles.starred <> coalesce(?,arsse_articles.starred) or arsse_articles.read <> coalesce(?,arsse_articles.read) or arsse_articles.hidden <> coalesce(?,arsse_articles.hidden))", ["str", "bool", "bool", "bool"], [$data['note'], $data['starred'], $data['read'], $data['hidden']]); + $q = new Query( "WITH RECURSIVE - target_articles as ( + target_articles(article) as ( {$subq->getQuery()} ) update arsse_articles - set - $set - where - id in (select id from target_articles)", - $subq->getTypes(), $setTypes - )->run( - $subq->getValues(), $setValues - )->changes(); + set + $set + where + id in (select article from target_articles)", + [$subq->getTypes(), $setTypes], + [$subq->getValues(), $setValues] + ); + $out = $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->changes(); } $tr->commit(); return $out; diff --git a/sql/MySQL/7.sql b/sql/MySQL/7.sql index 442b43c7..c422b12e 100644 --- a/sql/MySQL/7.sql +++ b/sql/MySQL/7.sql @@ -38,6 +38,7 @@ alter table arsse_articles add column subscription bigint unsigned; alter table arsse_articles add column "read" smallint not null default 0; alter table arsse_articles add column starred smallint not null default 0; alter table arsse_articles add column hidden smallint not null default 0; +alter table arsse_articles add column touched smallint not null default 0; alter table arsse_articles add column marked datetime(0); alter table arsse_articles add column note longtext; diff --git a/sql/PostgreSQL/7.sql b/sql/PostgreSQL/7.sql index 67cc2f57..a83d4b63 100644 --- a/sql/PostgreSQL/7.sql +++ b/sql/PostgreSQL/7.sql @@ -35,6 +35,7 @@ alter table arsse_articles add column subscription bigint references arsse_subsc alter table arsse_articles add column read smallint not null default 0; alter table arsse_articles add column starred smallint not null default 0; alter table arsse_articles add column hidden smallint not null default 0; +alter table arsse_articles add column touched smallint not null default 0; alter table arsse_articles add column marked timestamp(0) without time zone; alter table arsse_articles add column note text collate "und-x-icu" not null default ''; diff --git a/sql/SQLite3/7.sql b/sql/SQLite3/7.sql index 4e3e2573..acb1b948 100644 --- a/sql/SQLite3/7.sql +++ b/sql/SQLite3/7.sql @@ -48,6 +48,7 @@ create table arsse_articles_new( url_title_hash text not null, -- hash of URL + title; used when checking for updates and for identification if there is no guid url_content_hash text not null, -- hash of URL + content + enclosure URL + enclosure content type; used when checking for updates and for identification if there is no guid title_content_hash text not null, -- hash of title + content + enclosure URL + enclosure content type; used when checking for updates and for identification if there is no guid + touched int not null default 0, -- field used internally while marking; should normally be left as 0 note text not null default '' -- Tiny Tiny RSS freeform user note ); insert into arsse_articles_new @@ -68,6 +69,7 @@ insert into arsse_articles_new a.url_title_hash, a.url_content_hash, a.title_content_hash, + 0, coalesce(m.note,'') from arsse_articles_map as i left join arsse_articles as a on a.id = i.article diff --git a/tests/cases/Database/SeriesArticle.php b/tests/cases/Database/SeriesArticle.php index c45d5349..cd7aeefd 100644 --- a/tests/cases/Database/SeriesArticle.php +++ b/tests/cases/Database/SeriesArticle.php @@ -515,11 +515,20 @@ trait SeriesArticle { 103 => 103, 104 => 104, 105 => 105, + 119 => 119, + 120 => 120, 202 => 102, 203 => 103, 204 => 104, 205 => 105, 305 => 105, + 501 => 501, + 502 => 502, + 519 => 519, + 520 => 520, + 801 => 801, + 802 => 802, + 902 => 802, 1001 => 20, ]; $act = Arsse::$db->editionArticle(...range(1, 1001)); @@ -580,9 +589,9 @@ trait SeriesArticle { $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); $state['arsse_articles']['rows'][20][1] = 0; - $state['arsse_articles']['rows'][9][4] = $now; + $state['arsse_articles']['rows'][20][4] = $now; $state['arsse_articles']['rows'][22][1] = 0; - $state['arsse_articles']['rows'][11][4] = $now; + $state['arsse_articles']['rows'][22][4] = $now; $this->compareExpectations(static::$drv, $state); } @@ -590,14 +599,12 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => true]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][8][2] = 1; - $state['arsse_articles']['rows'][8][4] = $now; - $state['arsse_articles']['rows'][10][2] = 1; - $state['arsse_articles']['rows'][10][4] = $now; - $state['arsse_articles']['rows'][] = [13,5,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,7,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,8,1,0,$now,'',0]; + $state['arsse_articles']['rows'][19] = [119,1,0,0,$now,"ook"]; + $state['arsse_articles']['rows'][21] = [203,1,1,0,$now,"ack"]; + $state['arsse_articles']['rows'][23] = [205,1,0,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,1,0,0,$now,""]; + $state['arsse_articles']['rows'][25] = [207,1,0,0,$now,""]; + $state['arsse_articles']['rows'][26] = [208,1,0,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -605,10 +612,10 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['starred' => false]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][10][3] = 0; - $state['arsse_articles']['rows'][10][4] = $now; - $state['arsse_articles']['rows'][11][3] = 0; - $state['arsse_articles']['rows'][11][4] = $now; + $state['arsse_articles']['rows'][21][2] = 0; + $state['arsse_articles']['rows'][21][4] = $now; + $state['arsse_articles']['rows'][22][2] = 0; + $state['arsse_articles']['rows'][22][4] = $now; $this->compareExpectations(static::$drv, $state); } @@ -616,14 +623,12 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['starred' => true]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][8][3] = 1; - $state['arsse_articles']['rows'][8][4] = $now; - $state['arsse_articles']['rows'][9][3] = 1; - $state['arsse_articles']['rows'][9][4] = $now; - $state['arsse_articles']['rows'][] = [13,5,0,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,0,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,7,0,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,8,0,1,$now,'',0]; + $state['arsse_articles']['rows'][19] = [119,0,1,0,$now,"ook"]; + $state['arsse_articles']['rows'][20] = [120,1,1,0,$now,"eek"]; + $state['arsse_articles']['rows'][23] = [205,0,1,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,0,1,0,$now,""]; + $state['arsse_articles']['rows'][25] = [207,0,1,0,$now,""]; + $state['arsse_articles']['rows'][26] = [208,0,1,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -631,13 +636,9 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => false,'starred' => false]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][9][2] = 0; - $state['arsse_articles']['rows'][9][4] = $now; - $state['arsse_articles']['rows'][10][3] = 0; - $state['arsse_articles']['rows'][10][4] = $now; - $state['arsse_articles']['rows'][11][2] = 0; - $state['arsse_articles']['rows'][11][3] = 0; - $state['arsse_articles']['rows'][11][4] = $now; + $state['arsse_articles']['rows'][20] = [120,0,0,0,$now,"eek"]; + $state['arsse_articles']['rows'][21] = [203,0,0,0,$now,"ack"]; + $state['arsse_articles']['rows'][22] = [204,0,0,0,$now,"ach"]; $this->compareExpectations(static::$drv, $state); } @@ -645,17 +646,13 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => true,'starred' => true]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][8][2] = 1; - $state['arsse_articles']['rows'][8][3] = 1; - $state['arsse_articles']['rows'][8][4] = $now; - $state['arsse_articles']['rows'][9][3] = 1; - $state['arsse_articles']['rows'][9][4] = $now; - $state['arsse_articles']['rows'][10][2] = 1; - $state['arsse_articles']['rows'][10][4] = $now; - $state['arsse_articles']['rows'][] = [13,5,1,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,1,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,7,1,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,8,1,1,$now,'',0]; + $state['arsse_articles']['rows'][19] = [119,1,1,0,$now,"ook"]; + $state['arsse_articles']['rows'][20] = [120,1,1,0,$now,"eek"]; + $state['arsse_articles']['rows'][21] = [203,1,1,0,$now,"ack"]; + $state['arsse_articles']['rows'][23] = [205,1,1,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,1,1,0,$now,""]; + $state['arsse_articles']['rows'][25] = [207,1,1,0,$now,""]; + $state['arsse_articles']['rows'][26] = [208,1,1,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -663,17 +660,13 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][8][3] = 1; - $state['arsse_articles']['rows'][8][4] = $now; - $state['arsse_articles']['rows'][9][2] = 0; - $state['arsse_articles']['rows'][9][3] = 1; - $state['arsse_articles']['rows'][9][4] = $now; - $state['arsse_articles']['rows'][11][2] = 0; - $state['arsse_articles']['rows'][11][4] = $now; - $state['arsse_articles']['rows'][] = [13,5,0,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,0,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,7,0,1,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,8,0,1,$now,'',0]; + $state['arsse_articles']['rows'][19] = [119,0,1,0,$now,"ook"]; + $state['arsse_articles']['rows'][20] = [120,0,1,0,$now,"eek"]; + $state['arsse_articles']['rows'][22] = [204,0,1,0,$now,"ach"]; + $state['arsse_articles']['rows'][23] = [205,0,1,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,0,1,0,$now,""]; + $state['arsse_articles']['rows'][25] = [207,0,1,0,$now,""]; + $state['arsse_articles']['rows'][26] = [208,0,1,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -681,17 +674,13 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => true,'starred' => false]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][8][2] = 1; - $state['arsse_articles']['rows'][8][4] = $now; - $state['arsse_articles']['rows'][10][2] = 1; - $state['arsse_articles']['rows'][10][3] = 0; - $state['arsse_articles']['rows'][10][4] = $now; - $state['arsse_articles']['rows'][11][3] = 0; - $state['arsse_articles']['rows'][11][4] = $now; - $state['arsse_articles']['rows'][] = [13,5,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,7,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,8,1,0,$now,'',0]; + $state['arsse_articles']['rows'][19] = [119,1,0,0,$now,"ook"]; + $state['arsse_articles']['rows'][21] = [203,1,0,0,$now,"ack"]; + $state['arsse_articles']['rows'][22] = [204,1,0,0,$now,"ach"]; + $state['arsse_articles']['rows'][23] = [205,1,0,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,1,0,0,$now,""]; + $state['arsse_articles']['rows'][25] = [207,1,0,0,$now,""]; + $state['arsse_articles']['rows'][26] = [208,1,0,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -699,18 +688,14 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['note' => "New note"]); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][8][5] = "New note"; - $state['arsse_articles']['rows'][8][4] = $now; - $state['arsse_articles']['rows'][9][5] = "New note"; - $state['arsse_articles']['rows'][9][4] = $now; - $state['arsse_articles']['rows'][10][5] = "New note"; - $state['arsse_articles']['rows'][10][4] = $now; - $state['arsse_articles']['rows'][11][5] = "New note"; - $state['arsse_articles']['rows'][11][4] = $now; - $state['arsse_articles']['rows'][] = [13,5,0,0,$now,'New note',0]; - $state['arsse_articles']['rows'][] = [13,6,0,0,$now,'New note',0]; - $state['arsse_articles']['rows'][] = [14,7,0,0,$now,'New note',0]; - $state['arsse_articles']['rows'][] = [14,8,0,0,$now,'New note',0]; + $state['arsse_articles']['rows'][19] = [119,0,0,0,$now,"New note"]; + $state['arsse_articles']['rows'][20] = [120,1,0,0,$now,"New note"]; + $state['arsse_articles']['rows'][21] = [203,0,1,0,$now,"New note"]; + $state['arsse_articles']['rows'][22] = [204,1,1,0,$now,"New note"]; + $state['arsse_articles']['rows'][23] = [205,0,0,0,$now,"New note"]; + $state['arsse_articles']['rows'][24] = [206,0,0,0,$now,"New note"]; + $state['arsse_articles']['rows'][25] = [207,0,0,0,$now,"New note"]; + $state['arsse_articles']['rows'][26] = [208,0,0,0,$now,"New note"]; $this->compareExpectations(static::$drv, $state); } @@ -718,10 +703,10 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->folder(7)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][] = [13,5,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,7,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [14,8,1,0,$now,'',0]; + $state['arsse_articles']['rows'][23] = [205,1,0,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,1,0,0,$now,""]; + $state['arsse_articles']['rows'][25] = [207,1,0,0,$now,""]; + $state['arsse_articles']['rows'][26] = [208,1,0,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -729,8 +714,8 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->folder(8)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][] = [13,5,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,1,0,$now,'',0]; + $state['arsse_articles']['rows'][23] = [205,1,0,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,1,0,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -743,8 +728,8 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->subscription(13)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][] = [13,5,1,0,$now,'',0]; - $state['arsse_articles']['rows'][] = [13,6,1,0,$now,'',0]; + $state['arsse_articles']['rows'][23] = [205,1,0,0,$now,""]; + $state['arsse_articles']['rows'][24] = [206,1,0,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -757,18 +742,17 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->article(120)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][20][3] = 1; + $state['arsse_articles']['rows'][20][2] = 1; $state['arsse_articles']['rows'][20][4] = $now; $this->compareExpectations(static::$drv, $state); } public function testMarkMultipleArticles(): void { - Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->articles([2,4,7,20])); + Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->articles([202,204,207,120])); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][9][3] = 1; - $state['arsse_articles']['rows'][9][4] = $now; - $state['arsse_articles']['rows'][] = [14,7,0,1,$now,'',0]; + $state['arsse_articles']['rows'][20] = [120,1,1,0,$now,"eek"]; + $state['arsse_articles']['rows'][25] = [207,0,1,0,$now,""]; $this->compareExpectations(static::$drv, $state); } @@ -787,7 +771,7 @@ trait SeriesArticle { public function testMarkTooManyMultipleArticles(): void { $setSize = (new \ReflectionClassConstant(Database::class, "LIMIT_SET_SIZE"))->getValue(); - $this->assertSame(7, Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->articles(range(1, $setSize * 3)))); + $this->assertSame(7, Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->articles(range(119, $setSize * 3)))); } public function testMarkAMissingArticle(): void { @@ -799,8 +783,8 @@ trait SeriesArticle { Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->edition(1101)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][9][3] = 1; - $state['arsse_articles']['rows'][9][4] = $now; + $state['arsse_articles']['rows'][20][2] = 1; + $state['arsse_articles']['rows'][20][4] = $now; $this->compareExpectations(static::$drv, $state); } @@ -1097,8 +1081,8 @@ trait SeriesArticle { Arsse::$db->articleMark("jane.doe@example.com", ['hidden' => true], (new Context)->edition(520)); $now = Date::transform(time(), "sql"); $state = $this->primeExpectations($this->data, $this->checkTables); - $state['arsse_articles']['rows'][3][6] = 1; - $state['arsse_articles']['rows'][3][4] = $now; + $state['arsse_articles']['rows'][13][3] = 1; + $state['arsse_articles']['rows'][13][4] = $now; $this->compareExpectations(static::$drv, $state); } diff --git a/tests/cases/Db/BaseUpdate.php b/tests/cases/Db/BaseUpdate.php index 96b6a718..9fbd98c6 100644 --- a/tests/cases/Db/BaseUpdate.php +++ b/tests/cases/Db/BaseUpdate.php @@ -295,14 +295,14 @@ QUERY_TEXT ] ], 'arsse_articles' => [ - 'columns' => ["id", "subscription", "read", "starred", "hidden", "published", "edited", "modified", "marked", "url", "title", "author", "guid", "url_title_hash", "url_content_hash", "title_content_hash", "note"], + 'columns' => ["id", "subscription", "read", "starred", "hidden", "touched", "published", "edited", "modified", "marked", "url", "title", "author", "guid", "url_title_hash", "url_content_hash", "title_content_hash", "note"], 'rows' => [ - [1, 1, 1, 1, 0, "2001-11-08 22:07:55", "2002-11-08 07:51:12", "2001-11-08 23:44:56", "2002-11-08 00:37:22", "https://example.com/1", "Article 1", "John Doe", "GUID1", "UTHASH1", "UCHASH1", "TCHASH1", "Note 1"], - [2, 1, 0, 0, 0, "2001-11-09 22:07:55", "2002-11-09 07:51:12", "2001-11-09 23:44:56", null, "https://example.com/2", "Article 2", "Jane Doe", "GUID2", "UTHASH2", "UCHASH2", "TCHASH2", ""], - [7, 4, 1, 0, 0, "2001-11-12 22:07:55", "2002-11-12 07:51:12", "2001-11-12 23:44:56", "2002-11-12 00:37:22", "https://example.net/1", "Article 5", "Adam Doe", "GUID5", "UTHASH5", "UCHASH5", "TCHASH5", "Note 5"], - [8, 6, 0, 1, 0, "2001-11-12 22:07:55", "2002-11-12 07:51:12", "2001-11-12 23:44:56", "2002-12-12 00:37:22", "https://example.net/1", "Article 5", "Adam Doe", "GUID5", "UTHASH5", "UCHASH5", "TCHASH5", ""], - [9, 4, 0, 0, 0, "2001-11-13 22:07:55", "2002-11-13 07:51:12", "2001-11-13 23:44:56", null, "https://example.net/2", "Article 6", "Evie Doe", "GUID6", "UTHASH6", "UCHASH6", "TCHASH6", ""], - [10, 6, 0, 0, 1, "2001-11-13 22:07:55", "2002-11-13 07:51:12", "2001-11-13 23:44:56", "2002-12-13 00:37:22", "https://example.net/2", "Article 6", "Evie Doe", "GUID6", "UTHASH6", "UCHASH6", "TCHASH6", "Note 6"], + [1, 1, 1, 1, 0, 0, "2001-11-08 22:07:55", "2002-11-08 07:51:12", "2001-11-08 23:44:56", "2002-11-08 00:37:22", "https://example.com/1", "Article 1", "John Doe", "GUID1", "UTHASH1", "UCHASH1", "TCHASH1", "Note 1"], + [2, 1, 0, 0, 0, 0, "2001-11-09 22:07:55", "2002-11-09 07:51:12", "2001-11-09 23:44:56", null, "https://example.com/2", "Article 2", "Jane Doe", "GUID2", "UTHASH2", "UCHASH2", "TCHASH2", ""], + [7, 4, 1, 0, 0, 0, "2001-11-12 22:07:55", "2002-11-12 07:51:12", "2001-11-12 23:44:56", "2002-11-12 00:37:22", "https://example.net/1", "Article 5", "Adam Doe", "GUID5", "UTHASH5", "UCHASH5", "TCHASH5", "Note 5"], + [8, 6, 0, 1, 0, 0, "2001-11-12 22:07:55", "2002-11-12 07:51:12", "2001-11-12 23:44:56", "2002-12-12 00:37:22", "https://example.net/1", "Article 5", "Adam Doe", "GUID5", "UTHASH5", "UCHASH5", "TCHASH5", ""], + [9, 4, 0, 0, 0, 0, "2001-11-13 22:07:55", "2002-11-13 07:51:12", "2001-11-13 23:44:56", null, "https://example.net/2", "Article 6", "Evie Doe", "GUID6", "UTHASH6", "UCHASH6", "TCHASH6", ""], + [10, 6, 0, 0, 1, 0, "2001-11-13 22:07:55", "2002-11-13 07:51:12", "2001-11-13 23:44:56", "2002-12-13 00:37:22", "https://example.net/2", "Article 6", "Evie Doe", "GUID6", "UTHASH6", "UCHASH6", "TCHASH6", "Note 6"], ] ], 'arsse_article_contents' => [