Skip to content

Commit

Permalink
Add property/param types
Browse files Browse the repository at this point in the history
  • Loading branch information
davidrans committed Aug 20, 2024
1 parent f708e25 commit 23e743e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 26 deletions.
43 changes: 32 additions & 11 deletions QueryGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ class QueryGenerator {
* statements. These correspond to methods that can be called on this class.
* The values are the syntax rules for collapsing the corresponding clauses.
*
* @var array<string, array{clause: string, prefix: string, glue: string|false, suffix: string, requiresArgument?: bool}>
* @var non-empty-array<string, array{
* clause: string,
* prefix: string,
* glue: string|false,
* suffix: string,
* requiresArgument?: bool
* }>
*/
private static array $methods = [
'select' => [
Expand Down Expand Up @@ -186,7 +192,7 @@ class QueryGenerator {
* MySQL query. Each primary clause has a set of valid sub-clauses that can
* be present in a completed query of that type.
*
* @var array<string, list<string>>
* @var non-empty-array<string, list<string>>
*/
private static array $possibleClauses = [
'select' => ['from', 'join', 'where', 'group', 'having', 'order', 'limit', 'offset', 'forupdate'],
Expand Down Expand Up @@ -322,13 +328,15 @@ public function __call(string $method, array $args) {
* (one of MissingPrimaryClauseException or MissingRequiredClauseException)
* unless `skipValidation` has been called.
*
* @param $skipClauses : Exclude the 'clause' part (WHERE, SELECT, FROM,
* @param bool $skipClauses : Exclude the 'clause' part (WHERE, SELECT, FROM,
* ...) of each sub-expression. See constructClause
* for more info. This is mostly for internal usage.
*
* Returns an array containing the query and paramter list, respectively.
*
* @return array{0: string, 1: array<string, mixed>}
*/
public function build($skipClauses = false) {
public function build(bool $skipClauses = false): array {
if ($this->validateQuery) {
$this->assertCompleteQuery();
}
Expand Down Expand Up @@ -373,8 +381,11 @@ public function useOr(): self {
/**
* Assert the completeness of this QueryGenerator instance by verifying
* that all required clauses have been set.
*
* @throws MissingPrimaryClauseException
* @throws MissingRequiredClauseException
*/
private function assertCompleteQuery() {
private function assertCompleteQuery(): void {
$primaryMethod = $this->getPrimaryMethod();

if (!$primaryMethod) {
Expand Down Expand Up @@ -404,29 +415,37 @@ private function assertCompleteQuery() {
}, $minimumClauses);
$requiredClauseStr = '{' . implode('}, {', $requiredClauseOptions) . '}';
throw new MissingRequiredClauseException(
"Missing required clauses. One of $requiredClauseStr needed.");
"Missing required clauses. One of $requiredClauseStr needed."
);
}

/**
* Return the list of primary query clauses.
*
* @return non-empty-list<string>
*/
private static function getPrimaryClauses() {
private static function getPrimaryClauses(): array {
return array_keys(self::$possibleClauses);
}

/**
* Return the primary clause in this QueryGenerator instance.
* If multiple primary clauses have been set, all but the first set clause
* will be ignored.
*
* @return string|false
*/
private function getPrimaryMethod() {
private function getPrimaryMethod(): string|bool {
$primaryClauses = self::getPrimaryClauses();
$setMethods = $this->getSetMethods();
$setPrimaryClauses = array_intersect($primaryClauses, $setMethods);
return reset($setPrimaryClauses);
}

private function getSetMethods() {
/**
* @return array<string, string>
*/
private function getSetMethods(): array {
$methods = array_keys(array_filter($this->clauses));
return array_combine($methods, $methods);
}
Expand All @@ -440,7 +459,7 @@ private function getSetMethods() {
* constructClause('where') => 'WHERE (foo = ?) AND (bar != ?)'
* constructClause('where', false) => '(foo = ?) AND (bar != ?)'
*/
private function constructClause($method, $skipClause = false) {
private function constructClause(string $method, bool $skipClause = false): string {
$clauseInfo = self::$methods[$method];
$prefix = $clauseInfo['prefix'];
$clause = $clauseInfo['clause'];
Expand All @@ -465,8 +484,10 @@ private function constructClause($method, $skipClause = false) {
/**
* return the appropriate glue string for the given clause, taking into
* account $this->useOr
*
* @return string|false
*/
private function getGlue($method) {
private function getGlue(string $method): string|bool {
if ($method !== 'where' || !$this->useOr) {
return self::$methods[$method]['glue'];
} else {
Expand Down
21 changes: 6 additions & 15 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.25.0@01a8eb06b9e9cc6cfb6a320bf9fb14331919d505">
<file src="QueryGenerator.php">
<MissingParamType>
<code><![CDATA[$method]]></code>
<code><![CDATA[$method]]></code>
<code><![CDATA[$skipClause]]></code>
<code><![CDATA[$skipClauses]]></code>
</MissingParamType>
<MissingReturnType>
<code><![CDATA[assertCompleteQuery]]></code>
<code><![CDATA[build]]></code>
<code><![CDATA[constructClause]]></code>
<code><![CDATA[getGlue]]></code>
<code><![CDATA[getPrimaryClauses]]></code>
<code><![CDATA[getPrimaryMethod]]></code>
<code><![CDATA[getSetMethods]]></code>
</MissingReturnType>
<PossiblyFalseArgument>
<code><![CDATA[$glue]]></code>
</PossiblyFalseArgument>
<PossiblyUnusedMethod>
<code><![CDATA[useOr]]></code>
</PossiblyUnusedMethod>
<RiskyTruthyFalsyComparison>
<code><![CDATA[!$primaryMethod]]></code>
</RiskyTruthyFalsyComparison>
<UnusedProperty>
<code><![CDATA[$queryModifiers]]></code>
</UnusedProperty>
Expand Down

0 comments on commit 23e743e

Please sign in to comment.