Skip to content

Commit

Permalink
feat: updated method added to query builder
Browse files Browse the repository at this point in the history
  • Loading branch information
mgcostaParedes committed May 7, 2021
1 parent 2b60af5 commit 93a5bd6
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 19 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ $user = User::find($id);

```

**Updating/Deleting using the Query Builder**

```PHP
use MgCosta\Spanner\Model\Model;

class User extends Model {}

// deleting
User::where('id', 1)->delete();

// updating
$status = User::where('id', 5)->update(['name' => 'Richard', 'age' => 30]);

```

**Saving a model**

```PHP
Expand All @@ -59,6 +74,8 @@ class User extends Model {

protected $primaryKey = 'UserId';

// available strategies [uuid4, increment]
// increment is not recommend by cloud spanner
protected $keyStrategy = 'uuid4';

public $name;
Expand Down
4 changes: 1 addition & 3 deletions codeception.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,4 @@ paths:
coverage:
enabled: true
include:
- src/*
exclude:
- src/Spanner/Config/analytics-auth-config.json
- src/*
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "mgcosta/spanner-orm-builder",
"type": "library",
"description": "Google Spanner ORM Builder",
"version": "0.0.1",
"description": "Google Spanner ORM With Query Builder",
"version": "0.0.2",
"license": "MIT",
"authors": [
{
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ services:
container_name: spanner-orm-builder
environment:
ENVIRONMENT: "development"
XDEBUG_MODE: "coverage"
volumes:
- $PWD:/var/www/html:delegated
networks:
Expand Down
29 changes: 28 additions & 1 deletion src/Spanner/Builder/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,28 @@ public function find($id, $columns = ['*']): array
return $this->where($this->model->getPrimaryKey() ?? 'id', '=', $id)->first($columns);
}

public function update(array $values): Timestamp
{
$valuesWithParams = [];
foreach ($values as $key => $value) {
$parameter = $this->getValueKey();
$valuesWithParams[$key] = [
'parameter' => $parameter,
'value' => $value
];
$this->addBinding([$parameter => $value]);
}
$sql = $this->grammar->compileUpdate($this, $valuesWithParams);

$query = $this;
return $this->connection->runTransaction(function (Transaction $t) use ($sql, $query) {
$t->executeUpdate($sql, [
'parameters' => $query->getBindings()
]);
return $t->commit();
});
}

public function delete($id = null): Timestamp
{
if (!is_null($id)) {
Expand Down Expand Up @@ -786,6 +808,11 @@ private function tap($value, $callback)

private function getParameterKey(): string
{
return '@param' . ParamCounter::getKey();
return '@param' . ParamCounter::getKeyParam();
}

private function getValueKey(): string
{
return '@value' . ParamCounter::getKeyValue();
}
}
2 changes: 2 additions & 0 deletions src/Spanner/Builder/Grammar/Grammatical.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
interface Grammatical
{
public function compile(Builder $query): string;
public function compileUpdate(Builder $query, array $values): string;
public function compileDelete(Builder $query): string;
}
51 changes: 43 additions & 8 deletions src/Spanner/Builder/Grammar/SpannerGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
class SpannerGrammar implements Grammatical
{
protected $tablePrefix = '';

protected $selectComponents = [
'aggregate',
'columns',
Expand Down Expand Up @@ -39,6 +40,34 @@ public function compile(Builder $query): string
return $sql;
}

public function compileUpdate(Builder $query, array $values): string
{
$table = $this->wrapTable($query->from);

$columns = $this->compileUpdateColumns($query, $values);

$where = $this->compileWheres($query);

return trim(
isset($query->joins)
? $this->compileUpdateWithJoins($query, $table, $columns, $where)
: $this->compileUpdateWithoutJoins($query, $table, $columns, $where)
);
}

public function compileDelete(Builder $query): string
{
$table = $this->wrapTable($query->from);

$where = $this->compileWheres($query);

return trim(
isset($query->joins)
? $this->compileDeleteWithJoins($query, $table, $where)
: $this->compileDeleteWithoutJoins($query, $table, $where)
);
}

protected function compileComponents(Builder $query): array
{
$sql = [];
Expand Down Expand Up @@ -156,17 +185,23 @@ protected function compileBasicHaving($having): string
return $having['boolean'] . ' ' . $column . ' ' . $having['operator'] . ' ' . $parameter;
}

public function compileDelete(Builder $query): string
protected function compileUpdateColumns(Builder $query, array $values): string
{
$table = $this->wrapTable($query->from);
return collect($values)->map(function ($value, $key) {
return $this->wrap($key) . ' = ' . $this->parameter($value);
})->implode(', ');
}

$where = $this->compileWheres($query);
protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where): string
{
return "update {$table} set {$columns} {$where}";
}

return trim(
isset($query->joins)
? $this->compileDeleteWithJoins($query, $table, $where)
: $this->compileDeleteWithoutJoins($query, $table, $where)
);
protected function compileUpdateWithJoins(Builder $query, $table, $columns, $where): string
{
$joins = $this->compileJoins($query, $query->joins);

return "update {$table} {$joins} set {$columns} {$where}";
}

protected function compileDeleteWithoutJoins(Builder $query, $table, $where): string
Expand Down
3 changes: 3 additions & 0 deletions src/Spanner/Builder/Interfaces/Fetchable.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ interface Fetchable
{
public function take($value): Builder;
public function find($id, $columns = ['*']): array;
public function value($column);
public function first(array $columns = ['*']);
public function get(array $columns = ['*']): Collection;
public function update(array $values);
public function delete($id = null): Timestamp;
}
3 changes: 3 additions & 0 deletions src/Spanner/Builder/Interfaces/Operator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public function whereNotExists(Closure $callback, $boolean = 'and'): Builder;
public function orWhereExists(Closure $callback, $not = false): Builder;
public function orWhereNotExists(Closure $callback): Builder;

public function offset($value): Builder;
public function limit($value): Builder;

public function joinWhere($table, $first, $operator, $second, $type = 'inner'): Builder;
public function rightJoin($table, $first, $operator = null, $second = null): Builder;
public function leftJoin($table, $first, $operator = null, $second = null): Builder;
Expand Down
18 changes: 13 additions & 5 deletions src/Spanner/Builder/ParamCounter.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@

class ParamCounter
{
protected static $counter = 0;
protected static $counterParams = 0;
protected static $counterValues = 0;

public static function getKey(): int
public static function getKeyParam(): int
{
static::$counter++;
return static::$counter;
static::$counterParams++;
return static::$counterParams;
}

public static function getKeyValue(): int
{
static::$counterValues++;
return static::$counterValues;
}

public static function flushCounter(): void
{
static::$counter = 0;
static::$counterParams = 0;
static::$counterValues = 0;
}
}
20 changes: 20 additions & 0 deletions tests/unit/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,26 @@ public function testShouldReturnATimestampWhenCallingDeleteMethodProperly()
$this->assertEquals($timestamp, $result);
}

public function testShouldReturnATimestampWhenCallingUpdatedMethodProperly()
{
$date = new DateTimeImmutable(date('Y-m-d'));
$timestamp = new Timestamp($date);
$this->mockedModel->shouldReceive('getPrimaryKey')->andReturn('DummyID');

$this->database->shouldReceive('runTransaction')->once()->with(
m::on(function(Closure $transaction) use($timestamp) {
$mockTransaction = m::mock(Transaction::class);
$mockTransaction->shouldReceive('executeUpdate')->andReturn(1)->once();
$mockTransaction->shouldReceive('commit')->andReturn($timestamp)->once();
$this->assertSame($timestamp, $transaction($mockTransaction));
return true;
})
)->andReturn($timestamp);

$result = $this->builder->where('id', 1)->update(['age' => 30]);
$this->assertEquals($timestamp, $result);
}

public function testShouldReturnAnExpressionWhenCallingRawMethod()
{
$result = $this->builder->raw('select count(*) from testA');
Expand Down
55 changes: 55 additions & 0 deletions tests/unit/GrammarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,61 @@ public function testShouldCompileDeleteSuccessfullyWhenPassBuilderWithJoinDelete
);
}

public function testShouldCompileUpdateSuccessfullyWhenPassBuilderWithUpdateProperties()
{
$this->builder->from = 'test';
$this->builder->wheres[] = [
'type' => 'Basic',
'column' => 'id',
'operator' => '=',
'value' => 1,
'boolean' => 'and',
'parameter' => '@param1'
];

$values = [
'age' => ['parameter' => '@value1', 'value' => 30]
];

$this->assertEquals(
'update test set age = @value1 where id = @param1',
$this->grammar->compileUpdate($this->builder, $values)
);
}

public function testShouldCompileUpdateSuccessfullyWhenPassBuilderWithJoinDeleteProperties()
{
$joinClause = m::mock(JoinClause::class);
$joinClause->type = 'inner';
$joinClause->table = 'TestB';
$joinClause->wheres[] = [
'type' => 'Column',
'first' => 'TestA.id',
'operator' => '=',
'second' => 'TestB.id',
'boolean' => 'and'
];
$this->builder->from = 'TestA';
$this->builder->joins[0] = $joinClause;
$this->builder->wheres[] = [
'type' => 'Basic',
'column' => 'id',
'operator' => '=',
'value' => 1,
'boolean' => 'and',
'parameter' => '@param1'
];

$values = [
'age' => ['parameter' => '@value1', 'value' => 30]
];

$this->assertEquals(
'update TestA inner join TestB on TestA.id = TestB.id set age = @value1 where id = @param1',
$this->grammar->compileUpdate($this->builder, $values)
);
}

public function testShouldReturnAnExpressionValueWhenGettingParameterWithExpression()
{
$this->builder->from = 'TestA';
Expand Down

0 comments on commit 93a5bd6

Please sign in to comment.