mirror of
https://github.com/maxpozdeev/mytinytodo.git
synced 2026-03-11 08:55:27 +00:00
** remove "tags" and "tags_ids" fields from tasks table (used for better performance)
This commit is contained in:
parent
3a68339cb9
commit
8815569861
5 changed files with 146 additions and 64 deletions
|
|
@ -24,22 +24,14 @@ if (!$listData) {
|
|||
die("No list found.");
|
||||
}
|
||||
|
||||
$sqlSort = "ORDER BY compl ASC, ";
|
||||
if($listData['sorting'] == 1) $sqlSort .= "prio DESC, ddn ASC, duedate ASC, ow ASC";
|
||||
elseif($listData['sorting'] == 2) $sqlSort .= "ddn ASC, duedate ASC, prio DESC, ow ASC";
|
||||
else $sqlSort .= "ow ASC";
|
||||
$data = DBCore::defaultInstance()->getTasksByListId($listId, '', (int)$listData['sorting']);
|
||||
|
||||
$data = array();
|
||||
$q = $db->dq("SELECT *, duedate IS NULL AS ddn FROM {$db->prefix}todolist WHERE list_id=$listId $sqlSort");
|
||||
while($r = $q->fetchAssoc())
|
||||
{
|
||||
$data[] = $r;
|
||||
if (_get('format') == 'ical') {
|
||||
printICal($listData, $data);
|
||||
}
|
||||
else {
|
||||
printCSV($listData, $data);
|
||||
}
|
||||
|
||||
$format = _get('format');
|
||||
|
||||
if($format == 'ical') printICal($listData, $data);
|
||||
else printCSV($listData, $data);
|
||||
|
||||
|
||||
function printCSV(array $listData, array $data)
|
||||
|
|
|
|||
15
src/feed.php
15
src/feed.php
|
|
@ -32,7 +32,7 @@ $feedType = _get('feed');
|
|||
|
||||
if($feedType == 'completed') {
|
||||
$listData['_feed_descr'] = $lang->get('feed_completed_tasks');
|
||||
fillData( $data, $listId, 'd_completed', 'AND compl=1' );
|
||||
fillData( $data, $listId, 'd_completed', 'compl=1' );
|
||||
}
|
||||
elseif($feedType == 'modified') {
|
||||
$listData['_feed_descr'] = $lang->get('feed_modified_tasks');
|
||||
|
|
@ -40,13 +40,13 @@ elseif($feedType == 'modified') {
|
|||
}
|
||||
elseif($feedType == 'current') {
|
||||
$listData['_feed_descr'] = $lang->get('feed_new_tasks');
|
||||
fillData( $data, $listId, 'd_created', 'AND compl=0' );
|
||||
fillData( $data, $listId, 'd_created', 'compl=0' );
|
||||
}
|
||||
elseif($feedType == 'status') {
|
||||
$listData['_feed_descr'] = $lang->get('feed_tasks');
|
||||
fillData( $data, $listId, 'd_created', '' );
|
||||
fillData( $data, $listId, 'd_edited', 'AND compl=0 AND d_edited > d_created' );
|
||||
fillData( $data, $listId, 'd_completed', 'AND compl=1' );
|
||||
fillData( $data, $listId, 'd_edited', 'compl=0 AND d_edited > d_created' );
|
||||
fillData( $data, $listId, 'd_completed', 'compl=1' );
|
||||
}
|
||||
else {
|
||||
$listData['_feed_descr'] = $lang->get('feed_new_tasks');
|
||||
|
|
@ -64,15 +64,14 @@ printRss($data, $listData);
|
|||
|
||||
function fillData(array &$data, int $listId, string $field, string $sqlWhere )
|
||||
{
|
||||
$tasks = DBCore::defaultInstance()->getTasksByListId($listId, $sqlWhere, "$field DESC", 100);
|
||||
$lang = Lang::instance();
|
||||
$db = DBConnection::instance();
|
||||
$q = $db->dq("SELECT * FROM {$db->prefix}todolist WHERE list_id=$listId $sqlWhere ORDER BY $field DESC LIMIT 100");
|
||||
while ($r = $q->fetchAssoc())
|
||||
foreach ($tasks as $r)
|
||||
{
|
||||
if ($r['prio'] > 0) {
|
||||
$r['prio'] = '+'.$r['prio'];
|
||||
}
|
||||
$a = array();
|
||||
$a = array(); //for _descr
|
||||
$a[] = $lang->get('task'). ": ". $r['title'];
|
||||
if ($r['prio']) {
|
||||
$a[] = $lang->get('priority'). ": $r[prio]";
|
||||
|
|
|
|||
|
|
@ -98,10 +98,14 @@ class TasksController extends ApiController {
|
|||
$t['total'] = 0;
|
||||
$t['list'] = array();
|
||||
|
||||
$q = $db->dq("SELECT todo.*, duedate IS NULL AS ddn
|
||||
$q = $db->dq("
|
||||
SELECT todo.*, todo.duedate IS NULL AS ddn, GROUP_CONCAT(tags.id) AS tags_ids, GROUP_CONCAT(tags.name) AS tags
|
||||
FROM {$db->prefix}todolist AS todo
|
||||
LEFT JOIN {$db->prefix}tag2task AS t2t ON todo.id = t2t.task_id
|
||||
LEFT JOIN {$db->prefix}tags AS tags ON t2t.tag_id = tags.id
|
||||
WHERE $sqlWhereListId $sqlWhere
|
||||
GROUP BY todo.id $sqlSort");
|
||||
GROUP BY todo.id $sqlSort
|
||||
");
|
||||
|
||||
while ($r = $q->fetchAssoc())
|
||||
{
|
||||
|
|
@ -187,6 +191,11 @@ class TasksController extends ApiController {
|
|||
checkWriteAccess();
|
||||
$id = (int)$id;
|
||||
|
||||
if (!DBCore::defaultInstance()->taskExists($id)) {
|
||||
$this->response->data = ['total' => 0];
|
||||
return;
|
||||
}
|
||||
|
||||
$action = $this->req->jsonBody['action'] ?? '';
|
||||
switch ($action) {
|
||||
case 'edit': $this->response->data = $this->editTask($id); break;
|
||||
|
|
@ -258,14 +267,12 @@ class TasksController extends ApiController {
|
|||
$aTags = $this->prepareTags($tags);
|
||||
if ($aTags) {
|
||||
$this->addTaskTags($id, $aTags['ids'], $listId);
|
||||
$db->ex("UPDATE {$db->prefix}todolist SET tags=?,tags_ids=? WHERE id=$id", array(implode(',',$aTags['tags']), implode(',',$aTags['ids'])));
|
||||
}
|
||||
}
|
||||
$db->ex("COMMIT");
|
||||
$r = $db->sqa("SELECT * FROM {$db->prefix}todolist WHERE id=$id");
|
||||
$oo = $this->prepareTaskRow($r);
|
||||
MTTNotificationCenter::postNotification(MTTNotification::didCreateTask, $oo);
|
||||
$t['list'][] = $oo;
|
||||
$task = $this->getTaskRowById($id);
|
||||
MTTNotificationCenter::postNotification(MTTNotification::didCreateTask, $task);
|
||||
$t['list'][] = $task;
|
||||
$t['total'] = 1;
|
||||
return $t;
|
||||
}
|
||||
|
|
@ -298,14 +305,12 @@ class TasksController extends ApiController {
|
|||
$aTags = $this->prepareTags($tags);
|
||||
if ($aTags) {
|
||||
$this->addTaskTags($id, $aTags['ids'], $listId);
|
||||
$db->ex("UPDATE {$db->prefix}todolist SET tags=?,tags_ids=? WHERE id=$id", array(implode(',',$aTags['tags']), implode(',',$aTags['ids'])));
|
||||
}
|
||||
}
|
||||
$db->ex("COMMIT");
|
||||
$r = $db->sqa("SELECT * FROM {$db->prefix}todolist WHERE id=$id");
|
||||
$oo = $this->prepareTaskRow($r);
|
||||
MTTNotificationCenter::postNotification(MTTNotification::didCreateTask, $oo);
|
||||
$t['list'][] = $oo;
|
||||
$task = $this->getTaskRowById($id);
|
||||
MTTNotificationCenter::postNotification(MTTNotification::didCreateTask, $task);
|
||||
$t['list'][] = $task;
|
||||
$t['total'] = 1;
|
||||
return $t;
|
||||
}
|
||||
|
|
@ -329,31 +334,26 @@ class TasksController extends ApiController {
|
|||
$db->ex("BEGIN");
|
||||
$db->ex("DELETE FROM {$db->prefix}tag2task WHERE task_id=$id");
|
||||
$aTags = $this->prepareTags($tags);
|
||||
if($aTags) {
|
||||
$tags = implode(',', $aTags['tags']);
|
||||
$tags_ids = implode(',',$aTags['ids']);
|
||||
if ($aTags) {
|
||||
$this->addTaskTags($id, $aTags['ids'], $listId);
|
||||
}
|
||||
$db->dq("UPDATE {$db->prefix}todolist SET title=?,note=?,prio=?,tags=?,tags_ids=?,duedate=?,d_edited=? WHERE id=$id",
|
||||
array($title, $note, $prio, $tags, $tags_ids, $duedate, time()) );
|
||||
$db->dq("UPDATE {$db->prefix}todolist SET title=?,note=?,prio=?,duedate=?,d_edited=? WHERE id=$id",
|
||||
array($title, $note, $prio, $duedate, time()) );
|
||||
$db->ex("COMMIT");
|
||||
$r = $db->sqa("SELECT * FROM {$db->prefix}todolist WHERE id=$id");
|
||||
if ($r) {
|
||||
$t['list'][] = $this->prepareTaskRow($r);
|
||||
$t['total'] = 1;
|
||||
}
|
||||
$task = $this->getTaskRowById($id);
|
||||
$t['list'][] = $task;
|
||||
$t['total'] = 1;
|
||||
return $t;
|
||||
}
|
||||
|
||||
private function moveTask(int $id): ?array
|
||||
{
|
||||
$db = DBConnection::instance();
|
||||
$fromId = (int)($this->req->jsonBody['from'] ?? 0);
|
||||
$toId = (int)($this->req->jsonBody['to'] ?? 0);
|
||||
$result = $this->doMoveTask($id, $toId);
|
||||
$t = array('total' => $result ? 1 : 0);
|
||||
if ($fromId == -1 && $result && $r = $db->sqa("SELECT * FROM {$db->prefix}todolist WHERE id=$id")) {
|
||||
$t['list'][] = $this->prepareTaskRow($r);
|
||||
if ($fromId == -1 && $result) {
|
||||
$t['list'][] = $this->getTaskRowById($id);
|
||||
}
|
||||
return $t;
|
||||
}
|
||||
|
|
@ -392,8 +392,7 @@ class TasksController extends ApiController {
|
|||
array($dateCompleted, $date) );
|
||||
$t = array();
|
||||
$t['total'] = 1;
|
||||
$r = $db->sqa("SELECT * FROM {$db->prefix}todolist WHERE id=$id");
|
||||
$t['list'][] = $this->prepareTaskRow($r);
|
||||
$t['list'][] = $this->getTaskRowById($id);
|
||||
return $t;
|
||||
}
|
||||
|
||||
|
|
@ -460,6 +459,15 @@ class TasksController extends ApiController {
|
|||
return $a;
|
||||
}
|
||||
|
||||
private function getTaskRowById(int $id): ?array
|
||||
{
|
||||
$r = DBCore::defaultInstance()->getTaskById($id);
|
||||
if (!$r) {
|
||||
throw new Exception("Failed to fetch task data");
|
||||
}
|
||||
return $this->prepareTaskRow($r);
|
||||
}
|
||||
|
||||
private function prepareTaskRow(array $r): array
|
||||
{
|
||||
$lang = Lang::instance();
|
||||
|
|
@ -487,7 +495,7 @@ class TasksController extends ApiController {
|
|||
'date' => htmlarray($dCreated),
|
||||
'dateInt' => (int)$r['d_created'],
|
||||
'dateFull' => htmlarray($dCreatedFull),
|
||||
'dateInlineTitle' => htmlarray(sprintf($lang->get('taskdate_inline_created'), $dCreated)),
|
||||
'dateInlineTitle' => htmlarray(sprintf($lang->get('taskdate_inline_created'), $dCreated)), //TODO: move preparing of *inlineTitle to js
|
||||
'dateEdited' => htmlarray($dEdited),
|
||||
'dateEditedInt' => (int)$r['d_edited'],
|
||||
'dateEditedFull' => htmlarray($dEditedFull),
|
||||
|
|
@ -501,8 +509,8 @@ class TasksController extends ApiController {
|
|||
'note' => noteMarkup($r['note']),
|
||||
'noteText' => (string)$r['note'],
|
||||
'ow' => (int)$r['ow'],
|
||||
'tags' => htmlarray($r['tags']),
|
||||
'tags_ids' => htmlarray($r['tags_ids']),
|
||||
'tags' => htmlarray($r['tags'] ?? ''),
|
||||
'tags_ids' => htmlarray($r['tags_ids'] ?? ''),
|
||||
'duedate' => htmlarray($dueA['formatted']),
|
||||
'dueClass' => $dueA['class'],
|
||||
'dueStr' => htmlarray($dueA['str']),
|
||||
|
|
|
|||
|
|
@ -74,5 +74,84 @@ class DBCore
|
|||
return $listId;
|
||||
}
|
||||
|
||||
|
||||
public function taskExists(int $id): bool
|
||||
{
|
||||
$db = $this->db;
|
||||
$count = (int) $db->sq("SELECT COUNT(*) FROM {$db->prefix}todolist WHERE id = $id");
|
||||
return ($count > 0) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
public function getTaskById(int $id): ?array
|
||||
{
|
||||
$db = $this->db;
|
||||
$r = $db->sqa("
|
||||
SELECT todo.*, GROUP_CONCAT(tags.id) AS tags_ids, GROUP_CONCAT(tags.name) AS tags
|
||||
FROM {$db->prefix}todolist AS todo
|
||||
LEFT JOIN {$db->prefix}tag2task AS t2t ON todo.id = t2t.task_id
|
||||
LEFT JOIN {$db->prefix}tags AS tags ON t2t.tag_id = tags.id
|
||||
WHERE todo.id = $id
|
||||
");
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $listId
|
||||
* @param string $sqlWhere
|
||||
* @param int|string $sort
|
||||
* @param null|int $limit
|
||||
* @return array
|
||||
*/
|
||||
public function getTasksByListId(int $listId, string $sqlWhere, /* int|string */ $sort, ?int $limit = null): array
|
||||
{
|
||||
$db = $this->db;
|
||||
|
||||
if ($sqlWhere != '') {
|
||||
$sqlWhere = "AND $sqlWhere";
|
||||
}
|
||||
|
||||
$sqlSort = '';
|
||||
if (is_int($sort)) {
|
||||
$sqlSort = "ORDER BY compl ASC, ";
|
||||
if ($sort == 1) $sqlSort .= "prio DESC, ddn ASC, duedate ASC, ow ASC"; // byPrio
|
||||
elseif ($sort == 101) $sqlSort .= "prio ASC, ddn DESC, duedate DESC, ow DESC"; // byPrio (reverse)
|
||||
elseif ($sort == 2) $sqlSort .= "ddn ASC, duedate ASC, prio DESC, ow ASC"; // byDueDate
|
||||
elseif ($sort == 102) $sqlSort .= "ddn DESC, duedate DESC, prio ASC, ow DESC"; // byDueDate (reverse)
|
||||
elseif ($sort == 3) $sqlSort .= "d_created ASC, prio DESC, ow ASC"; // byDateCreated
|
||||
elseif ($sort == 103) $sqlSort .= "d_created DESC, prio ASC, ow DESC"; // byDateCreated (reverse)
|
||||
elseif ($sort == 4) $sqlSort .= "d_edited ASC, prio DESC, ow ASC"; // byDateModified
|
||||
elseif ($sort == 104) $sqlSort .= "d_edited DESC, prio ASC, ow DESC"; // byDateModified (reverse)
|
||||
elseif ($sort == 5) $sqlSort .= "title ASC, prio DESC, ow ASC"; // byTitle
|
||||
elseif ($sort == 105) $sqlSort .= "title DESC, prio ASC, ow DESC"; // byTitle (reverse)
|
||||
else $sqlSort .= "ow ASC";
|
||||
}
|
||||
else if ($sort != '') {
|
||||
$sqlSort = "ORDER BY $sort";
|
||||
}
|
||||
|
||||
$sqlLimit = '';
|
||||
if (!is_null($limit)) {
|
||||
$sqlLimit = "LIMIT $limit";
|
||||
}
|
||||
|
||||
$q = $db->dq("
|
||||
SELECT todo.*, todo.duedate IS NULL AS ddn, GROUP_CONCAT(tags.id) AS tags_ids, GROUP_CONCAT(tags.name) AS tags
|
||||
FROM {$db->prefix}todolist AS todo
|
||||
LEFT JOIN {$db->prefix}tag2task AS t2t ON todo.id = t2t.task_id
|
||||
LEFT JOIN {$db->prefix}tags AS tags ON t2t.tag_id = tags.id
|
||||
WHERE todo.list_id = $listId $sqlWhere
|
||||
GROUP BY todo.id
|
||||
$sqlSort
|
||||
$sqlLimit
|
||||
");
|
||||
|
||||
$data = array();
|
||||
while ($r = $q->fetchAssoc()) {
|
||||
$data[] = $r;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -278,8 +278,6 @@ function createMysqlTables($db)
|
|||
`note` TEXT,
|
||||
`prio` TINYINT NOT NULL default 0, /* priority -,0,+ */
|
||||
`ow` INT NOT NULL default 0, /* order weight */
|
||||
`tags` VARCHAR(600) NOT NULL default '', /* for fast access to task tags */
|
||||
`tags_ids` VARCHAR(250) NOT NULL default '', /* no more than 22 tags (x11 chars) */
|
||||
`duedate` DATE default NULL,
|
||||
PRIMARY KEY(`id`),
|
||||
KEY(`list_id`),
|
||||
|
|
@ -290,7 +288,7 @@ function createMysqlTables($db)
|
|||
$db->ex(
|
||||
"CREATE TABLE {$db->prefix}tags (
|
||||
`id` INT UNSIGNED NOT NULL auto_increment,
|
||||
`name` VARCHAR(50) NOT NULL,
|
||||
`name` VARCHAR(250) NOT NULL default '',
|
||||
PRIMARY KEY(`id`),
|
||||
UNIQUE KEY `name` (`name`)
|
||||
) CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ");
|
||||
|
|
@ -333,7 +331,7 @@ function createSqliteTables($db)
|
|||
id INTEGER PRIMARY KEY,
|
||||
uuid CHAR(36) NOT NULL,
|
||||
ow INTEGER NOT NULL default 0,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
name VARCHAR(250) NOT NULL,
|
||||
d_created INTEGER UNSIGNED NOT NULL default 0,
|
||||
d_edited INTEGER UNSIGNED NOT NULL default 0,
|
||||
sorting TINYINT UNSIGNED NOT NULL default 0,
|
||||
|
|
@ -357,8 +355,6 @@ function createSqliteTables($db)
|
|||
note TEXT COLLATE UTF8CI default NULL,
|
||||
prio TINYINT NOT NULL default 0,
|
||||
ow INTEGER NOT NULL default 0,
|
||||
tags VARCHAR(600) NOT NULL default '',
|
||||
tags_ids VARCHAR(250) NOT NULL default '',
|
||||
duedate DATE default NULL
|
||||
) ");
|
||||
$db->ex("CREATE INDEX todo_list_id ON {$db->prefix}todolist (list_id)");
|
||||
|
|
@ -422,6 +418,8 @@ function databaseVersion(Database_Abstract $db): string
|
|||
$v = '1.4';
|
||||
if ( !$db->tableExists($db->prefix.'settings') ) return $v;
|
||||
$v = '1.7';
|
||||
if ( $db->tableFieldExists($db->prefix.'todolist', 'tags') ) return $v;
|
||||
$v = '1.8';
|
||||
return $v;
|
||||
}
|
||||
|
||||
|
|
@ -579,7 +577,7 @@ function update_14_17(Database_Abstract $db, $dbtype)
|
|||
$db->ex("ALTER TABLE {$db->prefix}lists ADD `extra` TEXT");
|
||||
|
||||
# increase the length of list and tag name
|
||||
# (not applicable to sqlite because it uses VARCHAR fields of eny length as TEXT)
|
||||
# (not applicable to sqlite because it uses VARCHAR fields of any length as TEXT)
|
||||
$db->ex("ALTER TABLE {$db->prefix}todolist CHANGE `tags` `tags` VARCHAR(2000) NOT NULL default '' ");
|
||||
$db->ex("ALTER TABLE {$db->prefix}tags CHANGE `name` `name` VARCHAR(250) NOT NULL default '' ");
|
||||
$db->ex("ALTER TABLE {$db->prefix}lists CHANGE `name` `name` VARCHAR(250) NOT NULL default '' ");
|
||||
|
|
@ -653,7 +651,7 @@ function update_17_18(Database_Abstract $db, $dbtype)
|
|||
|
||||
if ($dbtype == 'sqlite')
|
||||
{
|
||||
// Use UTF8CI collate. Old sqlite does not support DROP COLUMN
|
||||
// Use UTF8CI collate. Old sqlite does not support DROP COLUMN (before v3.35.0 2021-03-12)
|
||||
$db->ex("DROP INDEX todo_list_id");
|
||||
$db->ex("DROP INDEX todo_uuid");
|
||||
$db->ex("ALTER TABLE {$db->prefix}todolist RENAME TO {$db->prefix}todolist_old");
|
||||
|
|
@ -670,11 +668,9 @@ function update_17_18(Database_Abstract $db, $dbtype)
|
|||
note TEXT COLLATE UTF8CI default NULL,
|
||||
prio TINYINT NOT NULL default 0,
|
||||
ow INTEGER NOT NULL default 0,
|
||||
tags VARCHAR(600) NOT NULL default '',
|
||||
tags_ids VARCHAR(250) NOT NULL default '',
|
||||
duedate DATE default NULL )"
|
||||
);
|
||||
$db->ex("INSERT INTO {$db->prefix}todolist SELECT * FROM {$db->prefix}todolist_old");
|
||||
$db->ex("INSERT INTO {$db->prefix}todolist SELECT id,uuid,list_id,d_created,d_completed,d_edited,compl,title,note,prio,ow,duedate FROM {$db->prefix}todolist_old");
|
||||
$db->ex("CREATE INDEX todo_list_id ON {$db->prefix}todolist (list_id)");
|
||||
$db->ex("CREATE UNIQUE INDEX todo_uuid ON {$db->prefix}todolist (uuid)");
|
||||
$db->ex("DROP TABLE {$db->prefix}todolist_old");
|
||||
|
|
@ -684,12 +680,20 @@ function update_17_18(Database_Abstract $db, $dbtype)
|
|||
$db->ex(
|
||||
"CREATE TABLE {$db->prefix}tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(50) NOT NULL DEFAULT '' COLLATE UTF8CI )"
|
||||
name VARCHAR(250) NOT NULL DEFAULT '' COLLATE UTF8CI )"
|
||||
);
|
||||
$db->ex("INSERT INTO {$db->prefix}tags SELECT * FROM {$db->prefix}tags_old");
|
||||
$db->ex("CREATE INDEX tags_name ON {$db->prefix}tags (name)");
|
||||
$db->ex("DROP TABLE {$db->prefix}tags_old");
|
||||
}
|
||||
else // mysql
|
||||
{
|
||||
$db->ex("ALTER TABLE {$db->prefix}todolist DROP COLUMN tags");
|
||||
$db->ex("ALTER TABLE {$db->prefix}todolist DROP COLUMN tags_ids");
|
||||
|
||||
// if mysql db was created in v1.7.x then tags.name field has length of 50 instead of 250
|
||||
$db->ex("ALTER TABLE {$db->prefix}tags CHANGE `name` `name` VARCHAR(250) NOT NULL default '' ");
|
||||
}
|
||||
|
||||
$db->ex("COMMIT");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue