Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add firstOrNew, firstOrCreate, and updateOrCreate methods #241

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
9 changes: 4 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@ stages:
- test

php:
- '5.6'
- '7.0'
- '7.1'
- '7.2'
- '7.3'
- '7.4'

before_script:
- java -Djava.library.path=./DynamoDBLocal_lib -jar dynamodb_local/DynamoDBLocal.jar --port 3000 &
- sleep 2
- composer self-update
- composer install
- COMPOSER_MEMORY_LIMIT=-1 travis_retry composer install --prefer-dist --no-interaction

script: phpunit
script: ./vendor/bin/phpunit

jobs:
include:
Expand Down
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Install
composer require baopham/dynamodb
```

* Install service provider:
* Install service provider (< Laravel 5.5):

```php
// config/app.php
Expand All @@ -64,7 +64,7 @@ Install
* Run

```php
php artisan vendor:publish
php artisan vendor:publish --provider 'BaoPham\DynamoDb\DynamoDbServiceProvider'
```

* Update DynamoDb config in [config/dynamodb.php](config/dynamodb.php)
Expand All @@ -82,7 +82,10 @@ Install

// Load dynamodb config file
$app->configure('dynamodb');


// Enable Facade support
$app->withFacades();

// Enable Eloquent support
$app->withEloquent();
```
Expand All @@ -101,7 +104,8 @@ Usage
#### find() and delete()

```php
$model->find(<id>);
$model->find($id, array $columns = []);
$model->findMany($ids, array $columns = []);
$model->delete();
$model->deleteAsync()->wait();
```
Expand All @@ -118,12 +122,12 @@ $model->where(['key' => 'key value']);

// Chainable for 'AND'.
$model->where('foo', 'bar')
->where('foo2', '!=' 'bar2')
->where('foo2', '!=', 'bar2')
->get();

// Chainable for 'OR'.
$model->where('foo', 'bar')
->orWhere('foo2', '!=' 'bar2')
->orWhere('foo2', '!=', 'bar2')
->get();

// Other types of conditions
Expand Down Expand Up @@ -500,7 +504,7 @@ DynamoDb::table('articles')
->scan(); // supports any DynamoDbClient methods (e.g. batchWriteItem, batchGetItem, etc.)

DynamoDb::table('articles')
->setIndex('author_name')
->setIndexName('author_name')
->setKeyConditionExpression('#name = :name')
->setProjectionExpression('id, author_name')
// Can set the attribute mapping one by one instead
Expand Down Expand Up @@ -596,6 +600,9 @@ Q: How to use with factory?
A: Please see [this issue](https://github.com/baopham/laravel-dynamodb/issues/111)


Q: How do I use with Job? Getting a SerializesModels error
A: You can either [write your own restoreModel](https://github.com/baopham/laravel-dynamodb/issues/132) or remove the `SerializesModels` trait from your Job.


Author and Contributors
-------
Expand All @@ -604,3 +611,5 @@ Author and Contributors
* [Alexander Ward](https://github.com/cthos)
* [Quang Ngo](https://github.com/vanquang9387)
* [David Higgins](https://github.com/zoul0813)
* [Damon Williams](https://github.com/footballencarta)
* [David Palmer](https://github.com/dp88)
7 changes: 3 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"keywords": ["laravel", "dynamodb", "aws"],
"require": {
"aws/aws-sdk-php": "^3.0.0",
"illuminate/support": "5.1.* || 5.2.* || 5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*",
"illuminate/database": "5.1.* || 5.2.* || 5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*"
"illuminate/support": "5.1.* || 5.2.* || 5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.* || 5.8.* || ^6.0 || ^7.0 || ^8.0",
"illuminate/database": "5.1.* || 5.2.* || 5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.* || 5.8.* || ^6.0 || ^7.0 || ^8.0"
},
"license": "MIT",
"authors": [
Expand All @@ -19,9 +19,8 @@
"BaoPham\\DynamoDb\\": "src/"
}
},
"minimum-stability": "dev",
"require-dev": {
"orchestra/testbench": "~3.0"
"orchestra/testbench": "~3.0 || ~5.0"
},
"scripts": {
"test": "phpunit",
Expand Down
19 changes: 9 additions & 10 deletions src/ConditionAnalyzer/Analyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use BaoPham\DynamoDb\ComparisonOperator;
use BaoPham\DynamoDb\DynamoDbModel;
use BaoPham\DynamoDb\H;
use Illuminate\Support\Arr;

/**
* Class ConditionAnalyzer
Expand Down Expand Up @@ -71,7 +72,7 @@ public function isExactSearch()
}

foreach ($this->conditions as $condition) {
if (array_get($condition, 'type') !== ComparisonOperator::EQ) {
if (Arr::get($condition, 'type') !== ComparisonOperator::EQ) {
return false;
}
}
Expand Down Expand Up @@ -173,15 +174,15 @@ private function getIndex()
$index = null;

foreach ($this->model->getDynamoDbIndexKeys() as $name => $keysInfo) {
$conditionKeys = array_pluck($this->conditions, 'column');
$conditionKeys = Arr::pluck($this->conditions, 'column');
$keys = array_values($keysInfo);

if (count(array_intersect($conditionKeys, $keys)) === count($keys)) {
if (!isset($this->indexName) || $this->indexName === $name) {
$index = new Index(
$name,
array_get($keysInfo, 'hash'),
array_get($keysInfo, 'range')
Arr::get($keysInfo, 'hash'),
Arr::get($keysInfo, 'range')
);

break;
Expand All @@ -198,15 +199,13 @@ private function getIndex()

private function hasValidQueryOperator($hash, $range = null)
{
$hashCondition = $this->getCondition($hash);

$validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator($hashCondition['type']);
$hashConditionType = $this->getCondition($hash)['type'] ?? null;
$validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator($hashConditionType);

if ($validQueryOp && $range) {
$rangeCondition = $this->getCondition($range);

$rangeConditionType = $this->getCondition($range)['type'] ?? null;
$validQueryOp = ComparisonOperator::isValidQueryDynamoDbOperator(
$rangeCondition['type'],
$rangeConditionType,
true
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/DynamoDb/QueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use BadMethodCallException;
use BaoPham\DynamoDb\DynamoDbClientInterface;
use BaoPham\DynamoDb\RawDynamoDbQuery;
use Illuminate\Support\Str;

/**
* Class QueryBuilder
Expand Down Expand Up @@ -109,7 +110,7 @@ public function prepare(DynamoDbClient $client = null)
*/
public function __call($method, $parameters)
{
if (starts_with($method, 'set')) {
if (Str::startsWith($method, 'set')) {
$key = array_reverse(explode('set', $method, 2))[0];
$this->query[$key] = current($parameters);

Expand Down
3 changes: 2 additions & 1 deletion src/DynamoDbClientService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Marshaler;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;

class DynamoDbClientService implements DynamoDbClientInterface
Expand Down Expand Up @@ -43,7 +44,7 @@ public function getClient($connection = null)

$config = config("dynamodb.connections.$connection", []);
$config['version'] = '2012-08-10';
$config['debug'] = $this->getDebugOptions(array_get($config, 'debug'));
$config['debug'] = $this->getDebugOptions(Arr::get($config, 'debug'));

$client = new DynamoDbClient($config);

Expand Down
7 changes: 4 additions & 3 deletions src/DynamoDbModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Exception;
use DateTime;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;

/**
* Class DynamoDbModel.
Expand Down Expand Up @@ -183,7 +184,7 @@ public function saveAsync(array $options = [])
$savePromise = $this->newQuery()->saveAsync();

$savePromise->then(function ($result) use ($create, $options) {
if (array_get($result, '@metadata.statusCode') === 200) {
if (Arr::get($result, '@metadata.statusCode') === 200) {
$this->exists = true;
$this->wasRecentlyCreated = $create;
$this->fireModelEvent($create ? 'created' : 'updated', false);
Expand Down Expand Up @@ -351,7 +352,7 @@ public function setId($id)
*/
public function getClient()
{
return static::$dynamoDb->getClient($this->connection);
return static::$dynamoDb->getClient($this->getConnectionName());
}

/**
Expand Down Expand Up @@ -446,7 +447,7 @@ public function getMarshaler()
public function __sleep()
{
return array_keys(
array_except(get_object_vars($this), ['marshaler', 'attributeFilter'])
Arr::except(get_object_vars($this), ['marshaler', 'attributeFilter'])
);
}

Expand Down
44 changes: 37 additions & 7 deletions src/DynamoDbQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Arr;

class DynamoDbQueryBuilder
{
Expand Down Expand Up @@ -211,8 +212,10 @@ public function where($column, $operator = null, $value = null, $boolean = 'and'
// received when the method was called and pass it into the nested where.
if (is_array($column)) {
foreach ($column as $key => $value) {
return $this->where($key, '=', $value);
$this->where($key, '=', $value, $boolean);
}

return $this;
}

// Here we will make some assumptions about the operator. If only 2 values are
Expand Down Expand Up @@ -427,7 +430,7 @@ public function chunk($chunkSize, callable $callback)
while (true) {
$results = $this->getAll([], $chunkSize, false);

if ($results->isNotEmpty()) {
if (!$results->isEmpty()) {
if (call_user_func($callback, $results) === false) {
return false;
}
Expand Down Expand Up @@ -468,7 +471,7 @@ public function find($id, array $columns = [])

$item = $query->prepare($this->client)->getItem();

$item = array_get($item->toArray(), 'Item');
$item = Arr::get($item->toArray(), 'Item');

if (empty($item)) {
return null;
Expand Down Expand Up @@ -530,6 +533,33 @@ public function findMany($ids, array $columns = [])
return $collection;
}

public function firstOrNew(array $attributes, array $values = [])
{
if (! is_null($instance = $this->where($attributes)->first())) {
return $instance;
}

return $this->model->newInstance($attributes + $values);
}

public function firstOrCreate(array $attributes, array $values = [])
{
if (! is_null($instance = $this->where($attributes)->first())) {
return $instance;
}

$newInstance = $this->model->newInstance($attributes + $values);
$newInstance->save();
return $newInstance;
}

public function updateOrCreate(array $attributes, array $values = [])
{
$instance = $this->firstOrNew($attributes);
$instance->fill($values)->save();
return $instance;
}

public function findOrFail($id, $columns = [])
{
$result = $this->find($id, $columns);
Expand Down Expand Up @@ -599,7 +629,7 @@ public function removeAttribute(...$attributes)
->prepare($this->client)
->updateItem();

$success = array_get($result, '@metadata.statusCode') === 200;
$success = Arr::get($result, '@metadata.statusCode') === 200;

if ($success) {
$this->model->setRawAttributes(DynamoDb::unmarshalItem($result->get('Attributes')));
Expand All @@ -616,7 +646,7 @@ public function delete()
->prepare($this->client)
->deleteItem();

return array_get($result->toArray(), '@metadata.statusCode') === 200;
return Arr::get($result->toArray(), '@metadata.statusCode') === 200;
}

public function deleteAsync()
Expand All @@ -636,7 +666,7 @@ public function save()
->prepare($this->client)
->putItem();

return array_get($result, '@metadata.statusCode') === 200;
return Arr::get($result, '@metadata.statusCode') === 200;
}

public function saveAsync()
Expand Down Expand Up @@ -708,7 +738,7 @@ protected function getAll(
$res = $this->client->query($raw->query);
}

$this->lastEvaluatedKey = array_get($res, 'LastEvaluatedKey');
$this->lastEvaluatedKey = Arr::get($res, 'LastEvaluatedKey');
$iterator = $res['Items'];
}

Expand Down
9 changes: 5 additions & 4 deletions src/Parsers/ConditionExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use BaoPham\DynamoDb\ComparisonOperator;
use BaoPham\DynamoDb\NotSupportedException;
use BaoPham\DynamoDb\Facades\DynamoDb;
use Illuminate\Support\Arr;

class ConditionExpression
{
Expand Down Expand Up @@ -70,9 +71,9 @@ public function parse($where)
$parsed = [];

foreach ($where as $condition) {
$boolean = array_get($condition, 'boolean');
$value = array_get($condition, 'value');
$type = array_get($condition, 'type');
$boolean = Arr::get($condition, 'boolean');
$value = Arr::get($condition, 'value');
$type = Arr::get($condition, 'type');

$prefix = '';

Expand All @@ -86,7 +87,7 @@ public function parse($where)
}

$parsed[] = $prefix . $this->parseCondition(
array_get($condition, 'column'),
Arr::get($condition, 'column'),
$type,
$value
);
Expand Down
Loading