<?php namespace ShSo\Lacassa\Query; use Cassandra; use Illuminate\Support\Arr; use ShSo\Lacassa\Connection; use InvalidArgumentException; use Illuminate\Database\Query\Builder as BaseBuilder; class Builder extends BaseBuilder { /** * The current query value bindings. * * @var array */ public $bindings = [ 'select' => [], 'where' => [], 'updateCollection' => [], 'insertCollection' => [], ]; public $allowFiltering = false; public $distinct = false; /** * The where constraints for the query. * * @var array */ public $updateCollections; /** * The where constraints for the query. * * @var array */ public $insertCollections; /** * All of the available clause operators. * * @var array */ public $operators = [ '=', '<', '>', '<=', '>=', 'like', 'contains', 'contains key', ]; /** * Operator conversion. * * @var array */ protected $conversion = [ '=' => '$eq', '!=' => '$ne', '<>' => '$ne', '<' => '$lt', '<=' => '$lte', '>' => '$gt', '>=' => '$gte', ]; /** * @var array */ public $collectionTypes = ['set', 'list', 'map']; /** * @param Connection $connection */ public function __construct(Connection $connection) { $this->grammar = $connection->getQueryGrammar(); $this->connection = $connection; } public function distinct() { $this->distinct = true; return $this; } public function allowFiltering() { $this->allowFiltering = true; return $this; } /** * Execute the query as a "select" statement. * * @param array $columns * * @return Cassandra\Rows */ public function get($columns = ['*']) { if (is_null($this->columns)) { $this->columns = $columns; } $cql = $this->grammar->compileSelect($this); return $this->execute($cql); } /** * Execute the query as a "select" statement. * * @param array $columns * * @return Cassandra\FutureRows */ public function getAsync($columns = ['*']) { if (is_null($this->columns)) { $this->columns = $columns; } $cql = $this->grammar->compileSelect($this); return $this->executeAsync($cql); } /** * Execute the CQL query. * * @param string $cql * * @return Cassandra\Rows */ private function execute($cql) { return $this->connection->execute($cql, ['arguments' => $this->getBindings()]); } /** * Execute the CQL query asyncronously. * * @param string $cql * * @return Cassandra\FutureRows */ private function executeAsync($cql) { return $this->connection->executeAsync($cql, ['arguments' => $this->getBindings()]); } /** * Delete a record from the database. * * @return Cassandra\Rows */ public function deleteRow() { $query = $this->grammar->compileDelete($this); return $this->executeAsync($query); } /** * Delete a column from the database. * * @param array $columns * * @return Cassandra\Rows */ public function deleteColumn($columns) { $this->delParams = $columns; $query = $this->grammar->compileDelete($this); return $this->executeAsync($query); } /** * Retrieve the "count" result of the query. * * @param string $columns * * @return Cassandra\Rows */ public function count($columns = '*') { $count = 0; $result = $this->get(array_wrap($columns)); while (true) { $count += $result->count(); if ($result->isLastPage()) { break; } $result = $result->nextPage(); } return $count; } /** * Used to update the colletions like set, list and map. * * @param string $type * @param string $column * @param string $operation * @param string $value * * @return string */ public function updateCollection($type, $column, $operation = null, $value = null) { //Check if the type is anyone in SET, LIST or MAP. else throw ERROR. if (!in_array(strtolower($type), $this->collectionTypes)) { throw new InvalidArgumentException("Invalid binding type: {$type}, Should be any one of ".implode(', ', $this->collectionTypes)); } // Here we will make some assumptions about the operator. If only 2 values are // passed to the method, we will assume that the operator is an equals sign // and keep going. Otherwise, we'll require the operator to be passed in. if (func_num_args() == 3) { $value = $operation; $operation = null; } $updateCollection = compact('type', 'column', 'value', 'operation'); $this->updateCollections[] = $updateCollection; $this->addCollectionBinding($updateCollection, 'updateCollection'); return $this; } /** * Add a binding to the query. * * @param array $value * @param string $type * * @return $this * * @throws \InvalidArgumentException */ public function addCollectionBinding($value, $type = 'updateCollection') { if (!array_key_exists($type, $this->bindings)) { throw new InvalidArgumentException("Invalid binding type: {$type}."); } $this->bindings[$type][] = $value; return $this; } /** * Update a record in the database. * * @param array $values * * @return int */ public function update(array $values = []) { $cql = $this->grammar->compileUpdate($this, $values); return $this->connection->update($cql, $this->cleanBindings( $this->grammar->prepareBindingsForUpdate($this->bindings, $values) )); } /** * Insert a new record into the database. * * @param array $values * * @return bool */ public function insert(array $values = []) { $insertCollectionArray = []; // Since every insert gets treated like a batch insert, we will make sure the // bindings are structured in a way that is convenient when building these // inserts statements by verifying these elements are actually an array. if (empty($values)) { return true; } if (!is_array(reset($values))) { $values = [$values]; } else { // Here, we will sort the insert keys for every record so that each insert is // in the same order for the record. We need to make sure this is the case // so there are not any errors or problems when inserting these records. foreach ($values as $key => $value) { ksort($value); $values[$key] = $value; } } // Finally, we will run this query against the database connection and return // the results. We will need to also flatten these bindings before running // the query so they are all in one huge, flattened array for execution. return $this->connection->insert( $this->grammar->compileInsert($this, $values), $this->cleanBindings(Arr::flatten($values, 1)) ); } /** * Insert a colletion type in cassandra. * * @param string $type * @param string $column * @param string $value * * @return $this */ public function insertCollection($type, $column, $value) { $insertCollection = compact('type', 'column', 'value'); $this->insertCollections[] = $insertCollection; $this->addCollectionBinding($insertCollection, 'insertCollection'); return $this; } /** * @param array $columns * * @return Cassandra\Rows */ public function index($columns = []) { $cql = $this->grammar->compileIndex($this, $columns); return $this->execute($cql); } }