• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

brick / geo / 14083182735

26 Mar 2025 12:23PM UTC coverage: 63.411% (+1.3%) from 62.112%
14083182735

push

github

BenMorel
Implement PgsqlDriver (pgsql extension)

40 of 53 new or added lines in 1 file covered. (75.47%)

41 existing lines in 3 files now uncovered.

1922 of 3031 relevant lines covered (63.41%)

1910.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.47
/src/Engine/Database/Driver/PgsqlDriver.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Brick\Geo\Engine\Database\Driver;
6

7
use Brick\Geo\Engine\Database\Query\BinaryValue;
8
use Brick\Geo\Engine\Database\Query\ScalarValue;
9
use Brick\Geo\Engine\Database\Result\Row;
10
use Brick\Geo\Exception\GeometryEngineException;
11
use Override;
12
use PgSql\Connection;
13

14
/**
15
 * Database driver using the pgsql extension for PostgreSQL.
16
 *
17
 * TODO error handling!
18
 */
19
final class PgsqlDriver implements DatabaseDriver
20
{
21
    public function __construct(
22
        private readonly Connection $connection,
23
    ) {
NEW
24
    }
×
25

26
    #[Override]
27
    public function executeQuery(string|BinaryValue|ScalarValue ...$query) : Row
28
    {
29
        $position = 1;
300✔
30

31
        $queryString = '';
300✔
32
        $queryParams = [];
300✔
33

34
        foreach ($query as $queryPart) {
300✔
35
            if ($queryPart instanceof BinaryValue) {
300✔
36
                $queryString .= '$' . $position++ . '::bytea';
300✔
37
                /** @var string */
38
                $queryParams[] = pg_escape_bytea($this->connection, $queryPart->value);
300✔
39
            } elseif ($queryPart instanceof ScalarValue) {
300✔
40
                $queryString .= '$' . $position++;
80✔
41

42
                if (is_int($queryPart->value)) {
80✔
43
                    $queryString .= '::int';
7✔
44
                    $queryParams[] = $queryPart->value;
7✔
45
                } elseif (is_float($queryPart->value)) {
73✔
46
                    $queryString .= '::float';
69✔
47
                    $queryParams[] = $queryPart->value;
69✔
48
                } elseif (is_bool($queryPart->value)) {
9✔
49
                    $queryString .= '::bool';
5✔
50
                    $queryParams[] = $queryPart->value ? 't' : 'f';
5✔
51
                } else {
52
                    $queryParams[] = $queryPart->value;
4✔
53
                }
54
            } else {
55
                $queryString .= $queryPart;
300✔
56
            }
57
        }
58

59
        // Mute warnings and back up the current error reporting level.
60
        $errorReportingLevel = error_reporting(0);
300✔
61

62
        try {
63
            $value = pg_prepare($this->connection, '', $queryString);
300✔
64

65
            if ($value === false) {
300✔
NEW
66
                $this->throwLastError();
×
67
            }
68

69
            $result = pg_execute($this->connection, '', $queryParams);
300✔
70

71
            if ($result === false) {
300✔
NEW
72
                $this->throwLastError();
×
73
            }
74

75
            /** @var list<list<mixed>>|false $rows */
76
            $rows = pg_fetch_all($result, PGSQL_NUM);
300✔
77

78
            if ($rows === false) {
300✔
NEW
79
                $this->throwLastError();
×
80
            }
81

82
            if (count($rows) !== 1) {
300✔
NEW
83
                throw new GeometryEngineException(sprintf('Expected exactly one row, got %d.', count($rows)));
×
84
            }
85
        } finally {
86
            // Restore the error reporting level.
87
            error_reporting($errorReportingLevel);
300✔
88
        }
89

90
        return new Row($this, $rows[0]);
300✔
91
    }
92

93
    /**
94
     * @throws GeometryEngineException
95
     */
96
    private function throwLastError() : never
97
    {
NEW
98
        throw new GeometryEngineException('The engine return an error: ' . pg_last_error($this->connection));
×
99
    }
100

101
    #[Override]
102
    public function convertBinaryResult(mixed $value) : string
103
    {
104
        if (is_string($value)) {
123✔
105
            return pg_unescape_bytea($value);
123✔
106
        }
107

NEW
108
        throw GeometryEngineException::unexpectedDatabaseReturnType('string', $value);
×
109
    }
110

111
    #[Override]
112
    public function convertStringResult(mixed $value) : string
113
    {
NEW
114
        if (is_string($value)) {
×
NEW
115
            return $value;
×
116
        }
117

NEW
118
        throw GeometryEngineException::unexpectedDatabaseReturnType('string', $value);
×
119
    }
120

121
    #[Override]
122
    public function convertIntResult(mixed $value) : int
123
    {
124
        // TODO check that actually returned as int;
125
        //      maybe checks for all types sent & received for each driver?
126

NEW
127
        if (is_int($value)) {
×
NEW
128
            return $value;
×
129
        }
130

NEW
131
        throw GeometryEngineException::unexpectedDatabaseReturnType('int', $value);
×
132
    }
133

134
    #[Override]
135
    public function convertFloatResult(mixed $value) : float
136
    {
137
        if (is_numeric($value)) {
41✔
138
            return (float) $value;
40✔
139
        }
140

141
        throw GeometryEngineException::unexpectedDatabaseReturnType('number or numeric string', $value);
1✔
142
    }
143

144
    #[Override]
145
    public function convertBoolResult(mixed $value) : bool
146
    {
147
        return match ($value) {
161✔
148
            't' => true,
89✔
149
            'f' => false,
78✔
150
            default => throw GeometryEngineException::unexpectedDatabaseReturnType('t or f', $value),
161✔
151
        };
161✔
152
    }
153
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc