Skip to content

Commit a47a953

Browse files
committed
Add tagWith() method to QueryBuilder for SQL comment tags
This implementation adds a tagWith() method to the QueryBuilder class, which allows adding SQL comment tags to generated queries for debugging, logging, and analysis purposes.
1 parent 748125c commit a47a953

2 files changed

Lines changed: 182 additions & 1 deletion

File tree

src/Query/QueryBuilder.php

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,13 @@ class QueryBuilder
175175
*/
176176
private ?QueryCacheProfile $resultCacheProfile = null;
177177

178+
/**
179+
* The comment tags to be added to the SQL query.
180+
*
181+
* @var string[]
182+
*/
183+
private array $commentTags = [];
184+
178185
/**
179186
* Initializes a new <tt>QueryBuilder</tt>.
180187
*
@@ -358,13 +365,19 @@ public function executeStatement(): int|string
358365
*/
359366
public function getSQL(): string
360367
{
361-
return $this->sql ??= match ($this->type) {
368+
if ($this->sql !== null) {
369+
return $this->sql;
370+
}
371+
372+
$sql = match ($this->type) {
362373
QueryType::INSERT => $this->getSQLForInsert(),
363374
QueryType::DELETE => $this->getSQLForDelete(),
364375
QueryType::UPDATE => $this->getSQLForUpdate(),
365376
QueryType::SELECT => $this->getSQLForSelect(),
366377
QueryType::UNION => $this->getSQLForUnion(),
367378
};
379+
380+
return $this->sql = $this->addCommentTagsToSQL($sql);
368381
}
369382

370383
/**
@@ -1661,4 +1674,52 @@ public function disableResultCache(): self
16611674

16621675
return $this;
16631676
}
1677+
1678+
/**
1679+
* Adds a comment tag to the SQL query.
1680+
*
1681+
* This method adds a SQL comment that will be prepended to the generated SQL query.
1682+
* Multiple tags can be added and will appear in the order they were added.
1683+
*
1684+
* <code>
1685+
* $qb = $conn->createQueryBuilder()
1686+
* ->select('u.id', 'u.name')
1687+
* ->from('users', 'u')
1688+
* ->tagWith('This is a custom tag')
1689+
* ->tagWith('Another tag');
1690+
* </code>
1691+
*
1692+
* @param string $tag The comment tag to add to the query.
1693+
*
1694+
* @return $this This QueryBuilder instance.
1695+
*/
1696+
public function tagWith(string $tag): self
1697+
{
1698+
$this->commentTags[] = $tag;
1699+
1700+
$this->sql = null;
1701+
1702+
return $this;
1703+
}
1704+
1705+
/**
1706+
* Adds comment tags to the SQL query.
1707+
*
1708+
* @param string $sql The SQL query to add tags to.
1709+
*
1710+
* @return string The SQL query with comment tags prepended.
1711+
*/
1712+
private function addCommentTagsToSQL(string $sql): string
1713+
{
1714+
if (count($this->commentTags) === 0) {
1715+
return $sql;
1716+
}
1717+
1718+
$commentLines = [];
1719+
foreach ($this->commentTags as $tag) {
1720+
$commentLines[] = '-- ' . $tag;
1721+
}
1722+
1723+
return implode("\n", $commentLines) . "\n\n" . $sql;
1724+
}
16641725
}

tests/Query/QueryBuilderTest.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,4 +1546,124 @@ public function testUnionAndOrderByReturnsUnionQueryWithOrderBy(): void
15461546
$qb->getSQL(),
15471547
);
15481548
}
1549+
1550+
public function testTagWithSingleTag(): void
1551+
{
1552+
$qb = new QueryBuilder($this->conn);
1553+
$qb->select('u.id', 'u.name')
1554+
->from('users', 'u')
1555+
->tagWith('This is a test query');
1556+
1557+
self::assertEquals(
1558+
"-- This is a test query\n\nSELECT u.id, u.name FROM users u",
1559+
$qb->getSQL(),
1560+
);
1561+
}
1562+
1563+
public function testTagWithMultipleTags(): void
1564+
{
1565+
$qb = new QueryBuilder($this->conn);
1566+
$qb->select('u.id', 'u.name')
1567+
->from('users', 'u')
1568+
->tagWith('First tag')
1569+
->tagWith('Second tag')
1570+
->tagWith('Third tag');
1571+
1572+
self::assertEquals(
1573+
"-- First tag\n-- Second tag\n-- Third tag\n\nSELECT u.id, u.name FROM users u",
1574+
$qb->getSQL(),
1575+
);
1576+
}
1577+
1578+
public function testTagWithInsertQuery(): void
1579+
{
1580+
$qb = new QueryBuilder($this->conn);
1581+
$qb->insert('users')
1582+
->values(['name' => '?', 'email' => '?'])
1583+
->tagWith('Insert operation');
1584+
1585+
self::assertEquals(
1586+
"-- Insert operation\n\nINSERT INTO users (name, email) VALUES(?, ?)",
1587+
$qb->getSQL(),
1588+
);
1589+
}
1590+
1591+
public function testTagWithUpdateQuery(): void
1592+
{
1593+
$qb = new QueryBuilder($this->conn);
1594+
$qb->update('users')
1595+
->set('name', '?')
1596+
->where('id = ?')
1597+
->tagWith('Update operation');
1598+
1599+
self::assertEquals(
1600+
"-- Update operation\n\nUPDATE users SET name = ? WHERE id = ?",
1601+
$qb->getSQL(),
1602+
);
1603+
}
1604+
1605+
public function testTagWithDeleteQuery(): void
1606+
{
1607+
$qb = new QueryBuilder($this->conn);
1608+
$qb->delete('users')
1609+
->where('id = ?')
1610+
->tagWith('Delete operation');
1611+
1612+
self::assertEquals(
1613+
"-- Delete operation\n\nDELETE FROM users WHERE id = ?", $qb->getSQL());
1614+
}
1615+
1616+
public function testTagWithNoTags(): void
1617+
{
1618+
$qb = new QueryBuilder($this->conn);
1619+
$qb->select('u.id', 'u.name')
1620+
->from('users', 'u');
1621+
1622+
self::assertEquals(
1623+
"SELECT u.id, u.name FROM users u",
1624+
$qb->getSQL(),
1625+
);
1626+
}
1627+
1628+
public function testTagWithMethodChaining(): void
1629+
{
1630+
$qb = new QueryBuilder($this->conn);
1631+
$qb->select('u.id')
1632+
->from('users', 'u')
1633+
->tagWith('Tag 1')
1634+
->where('u.id = ?')
1635+
->tagWith('Tag 2')
1636+
->orderBy('u.name');
1637+
1638+
self::assertEquals(
1639+
"-- Tag 1\n-- Tag 2\n\nSELECT u.id FROM users u WHERE u.id = ? ORDER BY u.name",
1640+
$qb->getSQL(),
1641+
);
1642+
}
1643+
1644+
public function testTagWithEmptyTag(): void
1645+
{
1646+
$qb = new QueryBuilder($this->conn);
1647+
$qb->select('u.id')
1648+
->from('users', 'u')
1649+
->tagWith('');
1650+
1651+
self::assertEquals(
1652+
"-- \n\nSELECT u.id FROM users u",
1653+
$qb->getSQL(),
1654+
);
1655+
}
1656+
1657+
public function testTagWithSpecialCharacters(): void
1658+
{
1659+
$qb = new QueryBuilder($this->conn);
1660+
$qb->select('u.id')
1661+
->from('users', 'u')
1662+
->tagWith("Tag with 'quotes' and \"double quotes\"");
1663+
1664+
self::assertEquals(
1665+
"-- Tag with 'quotes' and \"double quotes\"\n\nSELECT u.id FROM users u",
1666+
$qb->getSQL(),
1667+
);
1668+
}
15491669
}

0 commit comments

Comments
 (0)