Skip to content

Commit

Permalink
Merge pull request #63 from corley/feature/query-manager
Browse files Browse the repository at this point in the history
Support for custom query manager
  • Loading branch information
wdalmut committed Oct 18, 2015
2 parents dd30958 + a056cc2 commit 3dfc6c5
Show file tree
Hide file tree
Showing 13 changed files with 443 additions and 73 deletions.
79 changes: 69 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,6 @@ array(1) {
}
```

## Database operations

You can create, list or destroy databases using dedicated methods

```php
$client->getDatabases(); // list all databases
$client->createDatabase("my-name"); // create a new database with name "my.name"
$client->deleteDatabase("my-name"); // delete an existing database with name "my.name"
```

## Global tags and retention policy

You can set a set of default tags, that the SDK will add to your metrics:
Expand Down Expand Up @@ -300,6 +290,75 @@ $connectionParams = array(
$conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
```

## Database operations and custom queries

The class `InfluxDB\Client` does not support any database operation by itself.
That means that you don't have any helper function for create new databases, or
list actual databases and so on.
Thanks to `InfluxDB\Manager` you can use a preset of queries and create your own
personal queries that will run against the Influxdb instance.

### Create the manager

The `Manager` instance is very simple, you have to create it with a client
instance.

```php
$manager = new Manager($client); // InfluxDB\Client instance
```

### Attach new queries

The manager allows to attach new queries via an helper method `addQuery`.

```php
$manager->addQuery("getExceptionsInMinutes", function($minutes) {
return "SELECT * FROM app_exceptions WHERE time > now() - {$minutes}m";
});

$manager->getExceptionsInMinutes(10); // The callable name
```

As you can see you have to label your anonymous function and reuse it via the
manager.

In order to collect and reuse custom queries you can define query objects:

```php
class GetExceptionsInMinutes
{
public function __invoke($minutes)
{
return "SELECT * FROM app_exceptions WHERE time > now() - {$minutes}m";
}

public function __toString()
{
return "getExceptionsInMinutes";
}
}

$manager->addQuery(new GetExceptionsInMinutes());

$manger->getExceptionsInMinutes(10); //Use the query
```

As you can see valid query command should be `callable` via the `__invoke`
method and should be also serializable as strings via `__toString` method

### Existing queries

This project comes out with a preset of valid queries:

* Create new database `InfluxDB\Query\CreateDatabase`
* Drop existing databases `InfluxDB\Query\DeleteDatabase`
* List existing databases `InfluxDB\Query\GetDatabases`

```php
$manager->addQuery(new CreateDatabase());
$manager->addQuery(new DeleteDatabase());
$manager->addQuery(new GetDatabases());
```

## FAQ

Expand Down
18 changes: 0 additions & 18 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,4 @@ public function query($query)
{
return $this->getReader()->query($query);
}

public function getDatabases()
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 0.8.1 and will be removed in 0.9.', E_USER_DEPRECATED);
return $this->query("show databases");
}

public function createDatabase($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 0.8.1 and will be removed in 0.9.', E_USER_DEPRECATED);
return $this->query("create database \"{$name}\"");
}

public function deleteDatabase($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since version 0.8.1 and will be removed in 0.9.', E_USER_DEPRECATED);
return $this->query("drop database \"{$name}\"");
}
}
52 changes: 52 additions & 0 deletions src/Manager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
namespace InfluxDB;

use InvalidArgumentException;
use RuntimeException;
use InfluxDB\Client;

class Manager
{
private $client;
private $queries;

public function __construct(Client $client)
{
$this->client = $client;
$this->queries = [];
}

public function addQuery($name, callable $query = null)
{
if ($query === null) {
list($name, $query) = $this->fromObjectToNameCallableList($name);
}

$this->queries[$name] = $query;
}

private function fromObjectToNameCallableList($name)
{
if (is_object($name) && is_callable($name)) {
if (method_exists($name, "__toString")) {
return [(string)$name, $name];
}
}

throw new InvalidArgumentException("Your command should implements '__toString' method and should be a callable thing");
}

public function __call($name, $args)
{
if (method_exists($this->client, $name)) {
return call_user_func_array([$this->client, $name], $args);
}

if (array_key_exists($name, $this->queries)) {
$query = call_user_func_array($this->queries[$name], $args);
return $this->client->query($query);
}

throw new RuntimeException("The method you are using is not allowed: '{$name}', do you have to add it with 'addQuery'");
}
}
15 changes: 15 additions & 0 deletions src/Query/CreateDatabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
namespace InfluxDB\Query;

class CreateDatabase
{
public function __invoke($name)
{
return "CREATE DATABASE \"" . addslashes($name) . "\"";
}

public function __toString()
{
return "createDatabase";
}
}
16 changes: 16 additions & 0 deletions src/Query/DeleteDatabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php
namespace InfluxDB\Query;

class DeleteDatabase
{
public function __invoke($name)
{
return "DROP DATABASE \"" . addslashes($name) . "\"";
}

public function __toString()
{
return "deleteDatabase";
}
}

17 changes: 17 additions & 0 deletions src/Query/GetDatabases.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
namespace InfluxDB\Query;

class GetDatabases
{
public function __invoke()
{
return "show databases";
}

public function __toString()
{
return "getDatabases";
}
}


43 changes: 0 additions & 43 deletions tests/integration/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,49 +70,6 @@ public function testDirectMessagesMarkPublicSignature()
$this->assertValueExistsInSerie("tcp.test", "tt", "mem", 2);
}

public function testListActiveDatabases()
{
$options = new Options();
$guzzleHttp = new GuzzleHttpClient();
$writer = new Writer($guzzleHttp, $options);
$reader = new Reader($guzzleHttp, $options);
$client = new Client($reader, $writer);

$databases = $client->getDatabases();

$this->assertCount(2, $databases["results"][0]["series"][0]["values"]);
}

public function testCreateANewDatabase()
{
$options = new Options();
$guzzleHttp = new GuzzleHttpClient();
$writer = new Writer($guzzleHttp, $options);
$reader = new Reader($guzzleHttp, $options);
$client = new Client($reader, $writer);

$client->createDatabase("walter");

$databases = $client->getDatabases();

$this->assertCount(3, $databases["results"][0]["series"][0]["values"]);
}

public function testDropExistingDatabase()
{
$options = new Options();
$guzzleHttp = new GuzzleHttpClient();
$writer = new Writer($guzzleHttp, $options);
$reader = new Reader($guzzleHttp, $options);
$client = new Client($reader, $writer);

$client->createDatabase("walter");
$this->assertDatabasesCount(3);

$client->deleteDatabase("walter");
$this->assertDatabasesCount(2);
}

/**
* Test that we handle socket problems correctly in the UDP
* adapter, and that they don't inturrupt the user's application.
Expand Down
17 changes: 15 additions & 2 deletions tests/integration/Framework/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@

use GuzzleHttp\Client as GuzzleHttpClient;
use InfluxDB\Client;
use InfluxDB\Manager;
use InfluxDB\Adapter\Http\Options as HttpOptions;
use InfluxDB\Adapter\Http\Writer;
use InfluxDB\Adapter\Http\Reader;
use InfluxDB\Query\CreateDatabase;
use InfluxDB\Query\DeleteDatabase;
use InfluxDB\Query\GetDatabases;

class TestCase extends \PHPUnit_Framework_TestCase
{
Expand All @@ -19,7 +23,11 @@ public function setUp()
$writer = new Writer($guzzleHttp, $options);
$reader = new Reader($guzzleHttp, $options);

$client = $this->client = new Client($reader, $writer);
$client = $this->client = new Manager(new Client($reader, $writer));

$client->addQuery(new CreateDatabase());
$client->addQuery(new DeleteDatabase());
$client->addQuery(new GetDatabases());

$this->dropAll();
}
Expand Down Expand Up @@ -78,7 +86,12 @@ public function assertSerieExists($database, $serieName)
public function assertDatabasesCount($count)
{
$databases = $this->client->getDatabases();
$this->assertCount($count, $databases["results"][0]["series"][0]["values"]);
$databaseList = [];
if (array_key_exists("values", $databases["results"][0]["series"][0])) {
$databaseList = $databases["results"][0]["series"][0]["values"];
}

$this->assertCount($count, $databaseList);
}

public function getOptions()
Expand Down
79 changes: 79 additions & 0 deletions tests/integration/ManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
namespace InfluxDB\Integration;

use InfluxDB\Adapter\Http\Options;
use InfluxDB\Adapter\Http\Writer;
use InfluxDB\Adapter\Http\Reader;
use InfluxDB\Client;
use InfluxDB\Query\CreateDatabase;
use InfluxDB\Query\DeleteDatabase;
use InfluxDB\Query\GetDatabases;
use GuzzleHttp\Client as GuzzleHttpClient;
use InfluxDB\Manager;
use InfluxDB\Integration\Framework\TestCase;

class ManagerTest extends TestCase
{
public function testCreateANewDatabase()
{
$options = new Options();
$guzzleHttp = new GuzzleHttpClient();
$writer = new Writer($guzzleHttp, $options);
$reader = new Reader($guzzleHttp, $options);
$client = new Client($reader, $writer);
$manager = new Manager($client);

$manager->addQuery(new CreateDatabase());
$manager->addQuery(new DeleteDatabase());
$manager->addQuery(new GetDatabases());

$manager->createDatabase("one");
$manager->createDatabase("two");
$manager->createDatabase("walter");

$databases = $manager->getDatabases();

$this->assertCount(3, $databases["results"][0]["series"][0]["values"]);
}

public function testDropExistingDatabase()
{
$options = new Options();
$guzzleHttp = new GuzzleHttpClient();
$writer = new Writer($guzzleHttp, $options);
$reader = new Reader($guzzleHttp, $options);
$client = new Client($reader, $writer);
$manager = new Manager($client);

$manager->addQuery(new CreateDatabase());
$manager->addQuery(new DeleteDatabase());
$manager->addQuery(new GetDatabases());

$manager->createDatabase("walter");
$this->assertDatabasesCount(1);

$manager->deleteDatabase("walter");
$this->assertDatabasesCount(0);
}

public function testListActiveDatabases()
{
$options = new Options();
$guzzleHttp = new GuzzleHttpClient();
$writer = new Writer($guzzleHttp, $options);
$reader = new Reader($guzzleHttp, $options);
$client = new Client($reader, $writer);
$manager = new Manager($client);

$manager->addQuery(new CreateDatabase());
$manager->addQuery(new DeleteDatabase());
$manager->addQuery(new GetDatabases());

$manager->createDatabase("one");
$manager->createDatabase("two");

$databases = $manager->getDatabases();

$this->assertCount(2, $databases["results"][0]["series"][0]["values"]);
}
}
Loading

0 comments on commit 3dfc6c5

Please sign in to comment.