Passed
Pull Request — master (#47)
by Eugene
03:15
created

Client::withMiddleware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
/**
4
 * This file is part of the Tarantool Client package.
5
 *
6
 * (c) Eugene Leonovich <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Tarantool\Client;
15
16
use Tarantool\Client\Connection\StreamConnection;
17
use Tarantool\Client\Exception\RequestFailed;
18
use Tarantool\Client\Handler\DefaultHandler;
19
use Tarantool\Client\Handler\Handler;
20
use Tarantool\Client\Handler\MiddlewareHandler;
21
use Tarantool\Client\Middleware\AuthMiddleware;
22
use Tarantool\Client\Middleware\Middleware;
23
use Tarantool\Client\Middleware\RetryMiddleware;
24
use Tarantool\Client\Packer\PackerFactory;
25
use Tarantool\Client\Request\CallRequest;
26
use Tarantool\Client\Request\EvaluateRequest;
27
use Tarantool\Client\Request\ExecuteRequest;
28
use Tarantool\Client\Request\PingRequest;
29
use Tarantool\Client\Schema\Criteria;
30
use Tarantool\Client\Schema\IndexIds;
31
use Tarantool\Client\Schema\Space;
32
33
final class Client
34
{
35
    private $handler;
36
    private $spaces = [];
37
38 260
    public function __construct(Handler $handler)
39
    {
40 260
        $this->handler = $handler;
41 260
    }
42
43
    public static function fromDefaults() : self
44
    {
45
        return new self(new DefaultHandler(
46
            StreamConnection::createTcp(),
47
            PackerFactory::create()
48
        ));
49
    }
50
51 2
    public static function fromOptions(array $options) : self
52
    {
53 2
        $connectionOptions = [];
54 2
        if (isset($options['connect_timeout'])) {
55
            $connectionOptions['connect_timeout'] = $options['connect_timeout'];
56
        }
57 2
        if (isset($options['socket_timeout'])) {
58
            $connectionOptions['socket_timeout'] = $options['socket_timeout'];
59
        }
60 2
        if (isset($options['tcp_nodelay'])) {
61
            $connectionOptions['tcp_nodelay'] = $options['tcp_nodelay'];
62
        }
63 2
        if (isset($options['persistent'])) {
64
            $connectionOptions['persistent'] = $options['persistent'];
65
        }
66
67 2
        $connection = StreamConnection::create($options['uri'] ?? StreamConnection::DEFAULT_URI, $connectionOptions);
68 2
        $handler = new DefaultHandler($connection, PackerFactory::create());
69
70 2
        if (isset($options['max_retries']) && 0 !== $options['max_retries']) {
71 2
            $handler = MiddlewareHandler::create($handler, RetryMiddleware::linear($options['max_retries']));
72
        }
73 2
        if (isset($options['username'])) {
74 2
            $handler = MiddlewareHandler::create($handler, new AuthMiddleware($options['username'], $options['password'] ?? ''));
75
        }
76
77 2
        return new self($handler);
78
    }
79
80
    public static function fromDsn(string $dsn) : self
81
    {
82
        $dsn = Dsn::parse($dsn);
83
84
        $connectionOptions = [];
85
        if (null !== $timeout = $dsn->getInt('connect_timeout')) {
86
            $connectionOptions['connect_timeout'] = $timeout;
87
        }
88
        if (null !== $timeout = $dsn->getInt('socket_timeout')) {
89
            $connectionOptions['socket_timeout'] = $timeout;
90
        }
91
        if (null !== $tcpNoDelay = $dsn->getBool('tcp_nodelay')) {
92
            $connectionOptions['tcp_nodelay'] = $tcpNoDelay;
93
        }
94
        if (null !== $persistent = $dsn->getBool('persistent')) {
95
            $connectionOptions['persistent'] = $persistent;
96
        }
97
98
        $connection = $dsn->isTcp()
99
            ? StreamConnection::createTcp($dsn->getConnectionUri(), $connectionOptions)
100
            : StreamConnection::createUds($dsn->getConnectionUri(), $connectionOptions);
101
102
        $handler = new DefaultHandler($connection, PackerFactory::create());
103
104
        if ($maxRetries = $dsn->getInt('max_retries')) {
105
            $handler = MiddlewareHandler::create($handler, RetryMiddleware::linear($maxRetries));
106
        }
107
        if ($username = $dsn->getUsername()) {
108
            $handler = MiddlewareHandler::create($handler, new AuthMiddleware($username, $dsn->getPassword() ?? ''));
109
        }
110
111
        return new self($handler);
112
    }
113
114 2
    public function withMiddleware(Middleware $middleware, Middleware ...$middlewares) : self
115
    {
116 2
        $new = clone $this;
117 2
        $new->handler = MiddlewareHandler::create($new->handler, $middleware, ...$middlewares);
118
119 2
        return $new;
120
    }
121
122 14
    public function getHandler() : Handler
123
    {
124 14
        return $this->handler;
125
    }
126
127 58
    public function ping() : void
128
    {
129 58
        $this->handler->handle(new PingRequest());
130 6
    }
131
132 104
    public function getSpace(string $spaceName) : Space
133
    {
134 104
        if (isset($this->spaces[$spaceName])) {
135 2
            return $this->spaces[$spaceName];
136
        }
137
138 104
        $spaceId = $this->getSpaceIdByName($spaceName);
139
140 100
        return $this->spaces[$spaceName] = $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
141
    }
142
143 112
    public function getSpaceById(int $spaceId) : Space
144
    {
145 112
        if (isset($this->spaces[$spaceId])) {
146
            return $this->spaces[$spaceId];
147
        }
148
149 112
        return $this->spaces[$spaceId] = new Space($this->handler, $spaceId);
150
    }
151
152 4
    public function call(string $funcName, ...$args) : array
153
    {
154 4
        $request = new CallRequest($funcName, $args);
155
156 4
        return $this->handler->handle($request)->getBodyField(Keys::DATA);
157
    }
158
159 8
    public function executeQuery(string $sql, ...$params) : SqlQueryResult
160
    {
161 8
        $request = new ExecuteRequest($sql, $params);
162 8
        $response = $this->handler->handle($request);
163
164 8
        return new SqlQueryResult(
165 8
            $response->getBodyField(Keys::DATA),
166 8
            $response->getBodyField(Keys::METADATA)
167
        );
168
    }
169
170 10
    public function executeUpdate(string $sql, ...$params) : SqlUpdateResult
171
    {
172 10
        $request = new ExecuteRequest($sql, $params);
173
174 10
        return new SqlUpdateResult(
175 10
            $this->handler->handle($request)->getBodyField(Keys::SQL_INFO)
176
        );
177
    }
178
179 116
    public function evaluate(string $expr, ...$args) : array
180
    {
181 116
        $request = new EvaluateRequest($expr, $args);
182
183 116
        return $this->handler->handle($request)->getBodyField(Keys::DATA);
184
    }
185
186 4
    public function flushSpaces() : void
187
    {
188 4
        $this->spaces = [];
189 4
    }
190
191 2
    public function __clone()
192
    {
193 2
        $this->spaces = [];
194 2
    }
195
196 104
    private function getSpaceIdByName(string $spaceName) : int
197
    {
198 104
        $schema = $this->getSpaceById(Space::VSPACE_ID);
199 104
        $data = $schema->select(Criteria::key([$spaceName])->andIndex(IndexIds::SPACE_NAME));
200
201 104
        if ([] === $data) {
202 4
            throw RequestFailed::unknownSpace($spaceName);
203
        }
204
205 100
        return $data[0][0];
206
    }
207
}
208