├── .exrc ├── .gitignore ├── .scrutinizer.yml ├── LICENSE ├── README.md ├── circle.yml ├── composer.json ├── phpunit.xml.dist ├── src ├── Driver │ ├── InfluxDB.php │ └── InfluxDB │ │ ├── InfluxDBConnection.php │ │ └── InfluxDBStatement.php └── Platform │ └── InfluxDBPlatform.php └── tests └── Driver ├── InfluxDB.php └── InfluxDB ├── InfluxDBConnectionTest.php └── InfluxDBStatementTest.php /.exrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corley/dbal-influxdb/fa5a00ac761bff50c66f0a21979ee553e7a25b58/.exrc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | t.php 3 | tags 4 | composer.lock 5 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | tools: 2 | external_code_coverage: 3 | timeout: 600 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Walter Dal Mut 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Doctrine DBAL for InfluxDB 2 | 3 | [![Circle CI](https://circleci.com/gh/corley/dbal-influxdb/tree/master.svg?style=svg)](https://circleci.com/gh/corley/dbal-influxdb/tree/master) 4 | [![Code Coverage](https://scrutinizer-ci.com/g/corley/dbal-influxdb/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/corley/dbal-influxdb/?branch=master) 5 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/corley/dbal-influxdb/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/corley/dbal-influxdb/?branch=master) 6 | 7 | InfluxDB driver for Doctrine DBAL (Abstraction Layer) 8 | 9 | ## Query builder 10 | 11 | ```php 12 | $qb = $conn->createQueryBuilder(); 13 | 14 | $qb->select("*") 15 | ->from("cpu_load_short") 16 | ->where("time = ?") 17 | ->setParameter(0, 1434055562000000000); 18 | 19 | $data = $qb->execute(); 20 | foreach ($data->fetchAll() as $element) { 21 | // Use your element 22 | } 23 | ``` 24 | 25 | ## Create a connection 26 | 27 | ```php 28 | $config = new \Doctrine\DBAL\Configuration(); 29 | //.. 30 | $connectionParams = array( 31 | 'dbname' => 'mydb', 32 | 'user' => 'root', 33 | 'password' => 'root', 34 | 'host' => 'localhost', 35 | 'port' => 8086, 36 | "driverClass" => "Corley\\DBAL\\Driver\\InfluxDB", 37 | ); 38 | $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config); 39 | ``` 40 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | timezone: 3 | Europe/Rome 4 | php: 5 | version: 5.6.5 6 | 7 | dependencies: 8 | pre: 9 | - sed -i 's/^;//' ~/.phpenv/versions/$(phpenv global)/etc/conf.d/xdebug.ini 10 | 11 | test: 12 | override: 13 | - vendor/bin/phpunit --coverage-clover clover.xml 14 | post: 15 | - wget https://scrutinizer-ci.com/ocular.phar 16 | - php ocular.phar code-coverage:upload --format=php-clover clover.xml 17 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "corley/dbal-influxdb", 3 | "license": "MIT", 4 | "require": { 5 | "doctrine/dbal": "~2", 6 | "corley/influxdb-sdk": "0.5.*" 7 | }, 8 | "require-dev": { 9 | "phpunit/phpunit": "~4" 10 | }, 11 | "autoload": { 12 | "psr-4": { 13 | "Corley\\DBAL\\": "./src/" 14 | } 15 | }, 16 | "autoload-dev": { 17 | "psr-4": { 18 | "Corley\\DBAL\\": "./tests/" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | tests 12 | 13 | 14 | 15 | 16 | src 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Driver/InfluxDB.php: -------------------------------------------------------------------------------- 1 | getParams()["dbname"]; 38 | } 39 | 40 | public function convertException($message, DriverException $exception) 41 | { 42 | 43 | } 44 | 45 | public function createDatabasePlatformForVersion($version) 46 | { 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Driver/InfluxDB/InfluxDBConnection.php: -------------------------------------------------------------------------------- 1 | setHost($params["host"]); 20 | $options->setDatabase($params["dbname"]); 21 | $options->setUsername($username); 22 | $options->setPassword($password); 23 | $options->setPort($params["port"]); 24 | 25 | $adapter = new GuzzleAdapter($http, $options); 26 | 27 | $this->client = new Client($adapter); 28 | } 29 | 30 | public function prepare($prepareString) 31 | { 32 | return new InfluxDBStatement($this->client, $prepareString); 33 | } 34 | 35 | public function query() 36 | { 37 | $args = func_get_args(); 38 | $sql = $args[0]; 39 | $stmt = $this->prepare($sql); 40 | $stmt->execute(); 41 | 42 | return $stmt; 43 | } 44 | 45 | public function quote($input, $type=\PDO::PARAM_STR) 46 | { 47 | return "'" . addslashes($input) . "'"; 48 | } 49 | 50 | public function exec($statement) 51 | { 52 | $stmt = $this->query($statement); 53 | if (false === $stmt->execute()) { 54 | throw new \RuntimeException("Unable to execute query '{$statement}'"); 55 | } 56 | 57 | return $stmt->rowCount(); 58 | } 59 | 60 | public function lastInsertId($name = null) 61 | { 62 | throw new \RuntimeException("Unable to get last insert id in InfluxDB"); 63 | } 64 | 65 | public function beginTransaction() 66 | { 67 | throw new \RuntimeException("Transactions are not allowed in InfluxDB"); 68 | } 69 | 70 | public function commit() 71 | { 72 | throw new \RuntimeException("Transactions are not allowed in InfluxDB"); 73 | } 74 | 75 | public function rollBack() 76 | { 77 | throw new \RuntimeException("Transactions are not allowed in InfluxDB"); 78 | } 79 | 80 | public function errorCode() 81 | { 82 | 83 | } 84 | 85 | public function errorInfo() 86 | { 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Driver/InfluxDB/InfluxDBStatement.php: -------------------------------------------------------------------------------- 1 | client = $client; 24 | $this->statement = $statement; 25 | } 26 | 27 | public function bindValue($param, $value, $type = null) 28 | { 29 | $this->values[$param] = $value; 30 | } 31 | 32 | public function bindParam($column, &$variable, $type = null, $length = null) 33 | { 34 | $this->values[$column] =& $variable; 35 | } 36 | 37 | public function errorCode() 38 | { 39 | 40 | } 41 | 42 | public function errorInfo() 43 | { 44 | 45 | } 46 | 47 | public function execute($params = null) 48 | { 49 | $this->values = (is_array($params)) ? array_replace($this->values, $params) : $this->values; 50 | 51 | $stmt = $this->statement; 52 | 53 | foreach ($this->values as $key => $value) { 54 | $value = is_string($value) ? "'".addslashes($value)."'" : $value; 55 | $stmt = preg_replace("/(\?|:{$key})/i", "{$value}", $stmt, 1); 56 | } 57 | 58 | $results = $this->client->query($stmt); 59 | $return = false; 60 | if (is_array($results)) { 61 | $return = true; 62 | foreach ($results["results"][0]["series"][0]["values"] as $row => $elem) { 63 | foreach ($results["results"][0]["series"][0]["columns"] as $index => $value) { 64 | $this->results[$row][$value] = $results["results"][0]["series"][0]["values"][$row][$index]; 65 | } 66 | } 67 | } 68 | 69 | return $return; 70 | } 71 | 72 | public function rowCount() 73 | { 74 | return count($this->results); 75 | } 76 | 77 | public function getIterator() { 78 | return new ArrayIterator($this->results); 79 | } 80 | 81 | public function closeCursor() 82 | { 83 | 84 | } 85 | 86 | public function columnCount() 87 | { 88 | return (count($this->results)) ? count($this->results[0]) : null; 89 | } 90 | 91 | public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) 92 | { 93 | $this->defaultFetchMode = $fetchMode; 94 | } 95 | 96 | public function fetch($fetchMode = null) 97 | { 98 | if (!$this->currentIterator) { 99 | $this->currentIterator = $this->getIterator(); 100 | } 101 | 102 | $data = $this->currentIterator->current(); 103 | 104 | $this->currentIterator->next(); 105 | 106 | return $data; 107 | } 108 | 109 | public function fetchAll($fetchMode = null) 110 | { 111 | return $this->results; 112 | } 113 | 114 | public function fetchColumn($columnIndex = 0) 115 | { 116 | $elem = $this->fetch(); 117 | 118 | if ($elem) { 119 | if (array_key_exists($columnIndex, $elem)) { 120 | return $elem[$columnIndex]; 121 | } else { 122 | return $elem[array_keys($elem)[$columnIndex]]; 123 | } 124 | } 125 | 126 | return null; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/Platform/InfluxDBPlatform.php: -------------------------------------------------------------------------------- 1 | connect([ 10 | "host" => "", 11 | "dbname" => "", 12 | "port" => 8086, 13 | "user" => "root", 14 | "password" => "root", 15 | ], "root", "root", []); 16 | 17 | $this->assertInstanceOf("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBConnection", $conn); 18 | $this->assertInstanceOf("Corley\\DBAL\\Platform\\InfluxDBPlatform", $driver->getDatabasePlatform()); 19 | } 20 | 21 | public function testInfluxDBName() 22 | { 23 | $driver = new InfluxDB(); 24 | $this->assertEquals("influxdb", $driver->getName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Driver/InfluxDB/InfluxDBConnectionTest.php: -------------------------------------------------------------------------------- 1 | 'mydb', 13 | 'user' => 'root', 14 | 'password' => 'root', 15 | 'host' => 'localhost', 16 | 'port' => 8086, 17 | "driverClass" => "Corley\\DBAL\\Driver\\InfluxDB", 18 | ); 19 | $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config); 20 | 21 | $this->assertInstanceOf("Doctrine\DBAL\Connection", $conn); 22 | $this->assertInstanceOf("Corley\DBAL\Driver\InfluxDB", $conn->getDriver()); 23 | 24 | $this->assertEquals(8086, $conn->getPort()); 25 | $this->assertEquals("localhost", $conn->getHost()); 26 | 27 | $this->assertEquals("mydb", $conn->getDatabase()); 28 | } 29 | 30 | public function testCreateAStatement() 31 | { 32 | $conn = new InfluxDBConnection([ 33 | "host" => "locahost", 34 | "port" => 8086, 35 | "dbname" => "mydb", 36 | ], "root", "root", []); 37 | 38 | $stmt = $conn->prepare("SELECT * FROM cpu"); 39 | $this->assertInstanceOf("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBStatement", $stmt); 40 | } 41 | 42 | public function testDirectQuery() 43 | { 44 | $stmt = $this->prophesize("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBStatement"); 45 | $stmt->execute()->willReturn(true); 46 | 47 | $mock = $this->getMockBuilder("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBConnection") 48 | ->disableOriginalConstructor() 49 | ->setMethods(["prepare"]) 50 | ->getMock(); 51 | 52 | $mock->expects($this->once()) 53 | ->method("prepare") 54 | ->will($this->returnValue($stmt->reveal())); 55 | 56 | $stmt = $mock->query("SELECT * FROM cpu"); 57 | 58 | $this->assertInstanceOf("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBStatement", $stmt); 59 | } 60 | 61 | public function testQuoteWithSingle() 62 | { 63 | $mock = $this->getMockBuilder("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBConnection") 64 | ->disableOriginalConstructor() 65 | ->getMockForAbstractClass(); 66 | 67 | $this->assertEquals("'OK'", $mock->quote("OK")); 68 | } 69 | 70 | public function testExecStatement() 71 | { 72 | $stmt = $this->prophesize("Corley\\DBAL\\Driver\\InfluxDB\InfluxDBStatement"); 73 | $stmt->execute()->willReturn(true); 74 | $stmt->rowCount()->willReturn(5); 75 | 76 | $mock = $this->getMockBuilder("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBConnection") 77 | ->disableOriginalConstructor() 78 | ->setMethods(["query"]) 79 | ->getMockForAbstractClass(); 80 | 81 | $mock->expects($this->once()) 82 | ->method("query") 83 | ->will($this->returnValue($stmt->reveal())); 84 | 85 | $this->assertEquals(5, $mock->exec("OK")); 86 | } 87 | 88 | /** 89 | * @expectedException RuntimeException 90 | */ 91 | public function testExecStatementWithError() 92 | { 93 | $stmt = $this->prophesize("Corley\\DBAL\\Driver\\InfluxDB\InfluxDBStatement"); 94 | $stmt->execute()->willReturn(false); 95 | 96 | $mock = $this->getMockBuilder("Corley\\DBAL\\Driver\\InfluxDB\\InfluxDBConnection") 97 | ->disableOriginalConstructor() 98 | ->setMethods(["query"]) 99 | ->getMockForAbstractClass(); 100 | 101 | $mock->expects($this->once()) 102 | ->method("query") 103 | ->will($this->returnValue($stmt->reveal())); 104 | 105 | $mock->exec("OK"); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /tests/Driver/InfluxDB/InfluxDBStatementTest.php: -------------------------------------------------------------------------------- 1 | prophesize("InfluxDB\Client"); 11 | $client->query("SELECT * FROM cpu WHERE time = 1234")->shouldBeCalledTimes(1); 12 | 13 | $stmt = new InfluxDBStatement($client->reveal(), "SELECT * FROM cpu WHERE time = ?"); 14 | $stmt->bindValue(1, 1234); 15 | $stmt->execute(); 16 | } 17 | 18 | public function testPrepareMoreParamStatement() 19 | { 20 | $client = $this->prophesize("InfluxDB\Client"); 21 | $client->query("SELECT * FROM cpu WHERE time = 1234 and field = 12345 and another = 1847") 22 | ->shouldBeCalledTimes(1); 23 | 24 | $stmt = new InfluxDBStatement( 25 | $client->reveal(), 26 | "SELECT * FROM cpu WHERE time = ? and field = ? and another = ?" 27 | ); 28 | $stmt->bindValue(1, 1234); 29 | $stmt->bindValue(2, 12345); 30 | $stmt->bindValue(3, 1847); 31 | $stmt->execute(); 32 | } 33 | 34 | public function testStringEscape() 35 | { 36 | $client = $this->prophesize("InfluxDB\Client"); 37 | $client->query("SELECT * FROM cpu WHERE message = 'hello'")->shouldBeCalledTimes(1); 38 | 39 | $stmt = new InfluxDBStatement($client->reveal(), "SELECT * FROM cpu WHERE message = ?"); 40 | $stmt->bindValue(1, "hello"); 41 | $stmt->execute(); 42 | } 43 | 44 | public function testPrepareStatementWithName() 45 | { 46 | $client = $this->prophesize("InfluxDB\Client"); 47 | $client->query("SELECT * FROM cpu WHERE message = 'hello'")->shouldBeCalledTimes(1); 48 | 49 | $stmt = new InfluxDBStatement($client->reveal(), "SELECT * FROM cpu WHERE message = :name"); 50 | $stmt->bindValue("name", "hello"); 51 | $stmt->execute(); 52 | } 53 | 54 | public function testPrepareStatementWithBindParam() 55 | { 56 | $client = $this->prophesize("InfluxDB\Client"); 57 | $client->query("SELECT * FROM cpu WHERE message = 'hello'")->shouldBeCalledTimes(1); 58 | 59 | $ref = null; 60 | 61 | $stmt = new InfluxDBStatement($client->reveal(), "SELECT * FROM cpu WHERE message = :name"); 62 | $stmt->bindParam("name", $ref); 63 | 64 | $ref = "hello"; 65 | 66 | $stmt->execute(); 67 | } 68 | 69 | public function testExecuteAppendsParams() 70 | { 71 | $client = $this->prophesize("InfluxDB\Client"); 72 | $client->query("SELECT * FROM cpu WHERE message = 'hello'")->shouldBeCalledTimes(1); 73 | 74 | $stmt = new InfluxDBStatement($client->reveal(), "SELECT * FROM cpu WHERE message = :name"); 75 | $stmt->execute([ 76 | "name" => "hello" 77 | ]); 78 | } 79 | 80 | public function testCountResults() 81 | { 82 | $client = $this->prophesize("InfluxDB\Client"); 83 | $client->query(Argument::Any()) 84 | ->willReturn(json_decode(<<reveal(), "SELECT * FROM cpu"); 123 | $stmt->execute(); 124 | 125 | $this->assertEquals(3, $stmt->rowCount()); 126 | $this->assertCount(3, $stmt->fetchAll()); 127 | } 128 | 129 | public function testColumnCount() 130 | { 131 | $client = $this->prophesize("InfluxDB\Client"); 132 | $client->query(Argument::Any()) 133 | ->willReturn(json_decode(<<reveal(), "SELECT * FROM cpu"); 172 | $stmt->execute(); 173 | 174 | $this->assertEquals(2, $stmt->columnCount()); 175 | } 176 | 177 | public function testCountColumnWorkOnZero() 178 | { 179 | $client = $this->prophesize("InfluxDB\Client"); 180 | $client->query("SELECT * FROM cpu")->shouldBeCalledTimes(1); 181 | 182 | $stmt = new InfluxDBStatement($client->reveal(), "SELECT * FROM cpu"); 183 | $stmt->execute(); 184 | 185 | $this->assertNull($stmt->columnCount()); 186 | } 187 | 188 | public function testFetchSingleRecord() 189 | { 190 | $client = $this->prophesize("InfluxDB\Client"); 191 | $client->query(Argument::Any()) 192 | ->willReturn(json_decode(<<reveal(), "SELECT * FROM cpu"); 231 | $stmt->execute(); 232 | 233 | $this->assertEquals([ 234 | "time" => "2015-06-11T20:46:02Z", 235 | "value" => 0.64, 236 | ], $stmt->fetch()); 237 | 238 | $this->assertEquals([ 239 | "time" => "2015-06-12T02:19:22Z", 240 | "value" => 0.54, 241 | ], $stmt->fetch()); 242 | 243 | $this->assertEquals([ 244 | "time" => "2015-06-12T05:06:02Z", 245 | "value" => 0.92, 246 | ], $stmt->fetch()); 247 | 248 | $this->assertNull($stmt->fetch()); 249 | $this->assertNull($stmt->fetch()); 250 | } 251 | 252 | public function testFetchSingleColumn() 253 | { 254 | $client = $this->prophesize("InfluxDB\Client"); 255 | $client->query(Argument::Any()) 256 | ->willReturn(json_decode(<<reveal(), "SELECT * FROM cpu"); 295 | $stmt->execute(); 296 | 297 | $this->assertEquals("2015-06-11T20:46:02Z", $stmt->fetchColumn()); 298 | $this->assertEquals("2015-06-12T02:19:22Z", $stmt->fetchColumn()); 299 | $this->assertEquals("2015-06-12T05:06:02Z", $stmt->fetchColumn()); 300 | $this->assertNull($stmt->fetchColumn()); 301 | } 302 | 303 | public function testFetchNumberedColumn() 304 | { 305 | $client = $this->prophesize("InfluxDB\Client"); 306 | $client->query(Argument::Any()) 307 | ->willReturn(json_decode(<<reveal(), "SELECT * FROM cpu"); 346 | $stmt->execute(); 347 | 348 | $this->assertEquals(0.64, $stmt->fetchColumn(1)); 349 | $this->assertEquals(0.54, $stmt->fetchColumn("value")); 350 | } 351 | } 352 | --------------------------------------------------------------------------------