From 0e7bff5d8267d316c3618f079bb0cc4230acfe16 Mon Sep 17 00:00:00 2001 From: Mike Colagrosso Date: Tue, 31 Dec 2024 21:24:58 -0700 Subject: [PATCH] Rewrite `MultiTableSelect` queries with `ON` Instead of `USING(EbookId)`, it would be easier to handle `MultiTableSelect` queries in `FromMultiTableRow()` if the queries used `ON Projects.EbookId = Ebooks.Ebooks` This is because `USING` will return only one `EbookId` column, but `ON` will return all columns from both tables. --- lib/DbConnection.php | 6 ++++-- lib/Ebook.php | 12 ++++++------ lib/Project.php | 7 +++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/DbConnection.php b/lib/DbConnection.php index 0c07774c..0e0421da 100644 --- a/lib/DbConnection.php +++ b/lib/DbConnection.php @@ -109,7 +109,7 @@ class DbConnection{ /** * Execute a select query that returns a join against multiple tables. * - * For example, `select * from Users inner join Posts using (UserId)`. + * For example, `select * from Users inner join Posts on Users.UserId = Posts.UserId`. * * The result is an array of rows. Each row is an array of objects, with each object containing its columns and values. For example, * @@ -122,6 +122,7 @@ class DbConnection{ * }, * 'Posts' => { * 'PostId' => 222, + * 'UserId' => 111, * 'Title' => 'Lorem Ipsum' * } * ], @@ -132,13 +133,14 @@ class DbConnection{ * }, * 'Posts' => { * 'PostId' => 444, + * 'UserId' => 333, * 'Title' => 'Dolor sit' * } * ] * ] * ``` * - * **Important note:** When joining against two tables, SQL only returns one column for the join key (typically an ID value). Therefore, if both objects require an ID, the filler method must explicitly assign the ID to one of the two objects that's missing it. The above example shows this behavior: note how we join on `UserId`, but only the `Users` result has the `UserId` column, even though the `Posts` table also has a `UserId` column. + * **Important note:** If the two tables above were joined via `using (UserId)` instead of `on Users.UserId = Posts.UserId`, the SQL query would return only one column for the join key (`UserId` in this case). Therefore, if both objects require an ID, the filler method must explicitly assign the ID to one of the two objects that's missing it. In the above example, the `Users` result would have the `UserId` column, and `Posts` would not. * * @template T * diff --git a/lib/Ebook.php b/lib/Ebook.php index 5b8cb766..64348e07 100644 --- a/lib/Ebook.php +++ b/lib/Ebook.php @@ -164,8 +164,8 @@ final class Ebook{ SELECT * from Projects inner join Ebooks - using(EbookId) - where EbookId = ? + on Projects.EbookId = Ebooks.EbookId + where Ebooks.EbookId = ? order by Projects.Created desc ', [$this->EbookId], Project::class); } @@ -183,8 +183,8 @@ final class Ebook{ SELECT * from Projects inner join Ebooks - using(EbookId) - where EbookId = ? + on Projects.EbookId = Ebooks.EbookId + where Ebooks.EbookId = ? and Status in (?, ?) ', [$this->EbookId, Enums\ProjectStatusType::InProgress, Enums\ProjectStatusType::Stalled], Project::class)[0] ?? null; } @@ -206,8 +206,8 @@ final class Ebook{ SELECT * from Projects inner join Ebooks - using(EbookId) - where EbookId = ? + on Projects.EbookId = Ebooks.EbookId + where Ebooks.EbookId = ? and Status in (?, ?) ', [$this->EbookId, Enums\ProjectStatusType::Completed, Enums\ProjectStatusType::Abandoned], Project::class); } diff --git a/lib/Project.php b/lib/Project.php index 4fb06f71..f96a49fb 100644 --- a/lib/Project.php +++ b/lib/Project.php @@ -660,21 +660,21 @@ final class Project{ * @return array */ public static function GetAllByStatus(Enums\ProjectStatusType $status): array{ - return Db::MultiTableSelect('SELECT * from Projects inner join Ebooks using (EbookId) where Projects.Status = ? order by regexp_replace(Title, \'^(A|An|The)\\\s\', \'\') asc', [$status], Project::class); + return Db::MultiTableSelect('SELECT * from Projects inner join Ebooks on Projects.EbookId = Ebooks.EbookId where Projects.Status = ? order by regexp_replace(Title, \'^(A|An|The)\\\s\', \'\') asc', [$status], Project::class); } /** * @return array */ public static function GetAllByManagerUserId(int $userId): array{ - return Db::MultiTableSelect('SELECT * from Projects inner join Ebooks using (EbookId) where ManagerUserId = ? and Status in (?, ?) order by regexp_replace(Title, \'^(A|An|The)\\\s\', \'\') asc', [$userId, Enums\ProjectStatusType::InProgress, Enums\ProjectStatusType::Stalled], Project::class); + return Db::MultiTableSelect('SELECT * from Projects inner join Ebooks on Projects.EbookId = Ebooks.EbookId where ManagerUserId = ? and Status in (?, ?) order by regexp_replace(Title, \'^(A|An|The)\\\s\', \'\') asc', [$userId, Enums\ProjectStatusType::InProgress, Enums\ProjectStatusType::Stalled], Project::class); } /** * @return array */ public static function GetAllByReviewerUserId(int $userId): array{ - return Db::MultiTableSelect('SELECT * from Projects inner join Ebooks using (EbookId) where ReviewerUserId = ? and Status in (?, ?) order by regexp_replace(Title, \'^(A|An|The)\\\s\', \'\') asc', [$userId, Enums\ProjectStatusType::InProgress, Enums\ProjectStatusType::Stalled], Project::class); + return Db::MultiTableSelect('SELECT * from Projects inner join Ebooks on Projects.EbookId = Ebooks.EbookId where ReviewerUserId = ? and Status in (?, ?) order by regexp_replace(Title, \'^(A|An|The)\\\s\', \'\') asc', [$userId, Enums\ProjectStatusType::InProgress, Enums\ProjectStatusType::Stalled], Project::class); } /** @@ -686,7 +686,6 @@ final class Project{ $object = Project::FromRow($row['Projects']); if($row['Projects']->EbookId !== null){ - $row['Ebooks']->EbookId = $object->EbookId; $object->Ebook = Ebook::FromRow($row['Ebooks']); }