diff --git a/.travis.yml b/.travis.yml index 0bfd4b8..53e57ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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: diff --git a/README.md b/README.md index 2486e7b..82a557b 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Install composer require baopham/dynamodb ``` -* Install service provider: +* Install service provider (< Laravel 5.5): ```php // config/app.php @@ -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) @@ -82,7 +82,10 @@ Install // Load dynamodb config file $app->configure('dynamodb'); - + + // Enable Facade support + $app->withFacades(); + // Enable Eloquent support $app->withEloquent(); ``` @@ -101,7 +104,8 @@ Usage #### find() and delete() ```php -$model->find(); +$model->find($id, array $columns = []); +$model->findMany($ids, array $columns = []); $model->delete(); $model->deleteAsync()->wait(); ``` @@ -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 @@ -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 @@ -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 ------- @@ -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) diff --git a/composer.json b/composer.json index fdc83dc..f233eb5 100644 --- a/composer.json +++ b/composer.json @@ -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": [ @@ -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", diff --git a/src/ConditionAnalyzer/Analyzer.php b/src/ConditionAnalyzer/Analyzer.php index cdbb96a..1d023e5 100644 --- a/src/ConditionAnalyzer/Analyzer.php +++ b/src/ConditionAnalyzer/Analyzer.php @@ -5,6 +5,7 @@ use BaoPham\DynamoDb\ComparisonOperator; use BaoPham\DynamoDb\DynamoDbModel; use BaoPham\DynamoDb\H; +use Illuminate\Support\Arr; /** * Class ConditionAnalyzer @@ -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; } } @@ -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; @@ -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 ); } diff --git a/src/DynamoDb/QueryBuilder.php b/src/DynamoDb/QueryBuilder.php index bad1008..bebbf12 100644 --- a/src/DynamoDb/QueryBuilder.php +++ b/src/DynamoDb/QueryBuilder.php @@ -6,6 +6,7 @@ use BadMethodCallException; use BaoPham\DynamoDb\DynamoDbClientInterface; use BaoPham\DynamoDb\RawDynamoDbQuery; +use Illuminate\Support\Str; /** * Class QueryBuilder @@ -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); diff --git a/src/DynamoDbClientService.php b/src/DynamoDbClientService.php index b567426..efa32df 100644 --- a/src/DynamoDbClientService.php +++ b/src/DynamoDbClientService.php @@ -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 @@ -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); diff --git a/src/DynamoDbModel.php b/src/DynamoDbModel.php index 658f027..25949ed 100644 --- a/src/DynamoDbModel.php +++ b/src/DynamoDbModel.php @@ -5,6 +5,7 @@ use Exception; use DateTime; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Arr; /** * Class DynamoDbModel. @@ -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); @@ -351,7 +352,7 @@ public function setId($id) */ public function getClient() { - return static::$dynamoDb->getClient($this->connection); + return static::$dynamoDb->getClient($this->getConnectionName()); } /** @@ -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']) ); } diff --git a/src/DynamoDbQueryBuilder.php b/src/DynamoDbQueryBuilder.php index 011a69b..c7e0312 100644 --- a/src/DynamoDbQueryBuilder.php +++ b/src/DynamoDbQueryBuilder.php @@ -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 { @@ -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 @@ -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; } @@ -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; @@ -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); @@ -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'))); @@ -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() @@ -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() @@ -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']; } diff --git a/src/Parsers/ConditionExpression.php b/src/Parsers/ConditionExpression.php index 0ae0ff3..e45df64 100644 --- a/src/Parsers/ConditionExpression.php +++ b/src/Parsers/ConditionExpression.php @@ -5,6 +5,7 @@ use BaoPham\DynamoDb\ComparisonOperator; use BaoPham\DynamoDb\NotSupportedException; use BaoPham\DynamoDb\Facades\DynamoDb; +use Illuminate\Support\Arr; class ConditionExpression { @@ -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 = ''; @@ -86,7 +87,7 @@ public function parse($where) } $parsed[] = $prefix . $this->parseCondition( - array_get($condition, 'column'), + Arr::get($condition, 'column'), $type, $value ); diff --git a/src/Parsers/KeyConditionExpression.php b/src/Parsers/KeyConditionExpression.php index 5d7ff04..fc1b7b7 100644 --- a/src/Parsers/KeyConditionExpression.php +++ b/src/Parsers/KeyConditionExpression.php @@ -3,12 +3,13 @@ namespace BaoPham\DynamoDb\Parsers; use BaoPham\DynamoDb\ComparisonOperator; +use Illuminate\Support\Arr; class KeyConditionExpression extends ConditionExpression { protected function getSupportedOperators() { - return array_only(static::OPERATORS, [ + return Arr::only(static::OPERATORS, [ ComparisonOperator::EQ, ComparisonOperator::LE, ComparisonOperator::LT, diff --git a/src/RawDynamoDbQuery.php b/src/RawDynamoDbQuery.php index f009a84..3f7705f 100644 --- a/src/RawDynamoDbQuery.php +++ b/src/RawDynamoDbQuery.php @@ -136,6 +136,8 @@ public function count() * For backward compatibility, previously we use array to represent the raw query * * @var array + * + * @return array */ private function internal() { diff --git a/tests/DynamoDb/DynamoDbManagerTest.php b/tests/DynamoDb/DynamoDbManagerTest.php index 9ec6d4c..e4a48c1 100644 --- a/tests/DynamoDb/DynamoDbManagerTest.php +++ b/tests/DynamoDb/DynamoDbManagerTest.php @@ -20,7 +20,7 @@ class DynamoDbManagerTest extends DynamoDbTestCase */ protected $mockedClient; - public function setUp() + public function setUp(): void { parent::setUp(); diff --git a/tests/DynamoDbClientServiceTest.php b/tests/DynamoDbClientServiceTest.php index 0cae378..3e7b4dc 100644 --- a/tests/DynamoDbClientServiceTest.php +++ b/tests/DynamoDbClientServiceTest.php @@ -13,7 +13,7 @@ */ class DynamoDbClientServiceTest extends TestCase { - public function setUp() + public function setUp(): void { parent::setUp(); @@ -75,7 +75,7 @@ public function testUnsetDynamoDbClientService() /** * Make sure we are not leaving any values set on the DynamoDbModel */ - public function tearDown() + public function tearDown(): void { parent::tearDown(); diff --git a/tests/DynamoDbCompositeModelTest.php b/tests/DynamoDbCompositeModelTest.php index 29c9f3b..64c842d 100644 --- a/tests/DynamoDbCompositeModelTest.php +++ b/tests/DynamoDbCompositeModelTest.php @@ -5,7 +5,10 @@ use BaoPham\DynamoDb\DynamoDbModel; use BaoPham\DynamoDb\Facades\DynamoDb; use BaoPham\DynamoDb\RawDynamoDbQuery; +use Illuminate\Database\Eloquent\Model; use \Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Support\Arr; +use Illuminate\Support\Str; /** * Class DynamoDbCompositeModelTest @@ -22,7 +25,7 @@ protected function getTestModel() public function testCreateRecord() { $this->testModel->id = 'id1'; - $this->testModel->id2 = str_random(36); + $this->testModel->id2 = Str::random(36); $this->testModel->name = 'Test Create'; $this->testModel->count = 1; $this->testModel->save(); @@ -45,7 +48,7 @@ public function testCreateRecord() public function testCreateAsyncRecord() { $this->testModel->id = 'id1'; - $this->testModel->id2 = str_random(36); + $this->testModel->id2 = Str::random(36); $this->testModel->name = 'Test Create Async'; $this->testModel->count = 1; $this->testModel->saveAsync()->wait(); @@ -68,9 +71,9 @@ public function testCreateAsyncRecord() public function testFindRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); - $seedName = array_get($seed, 'name.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); + $seedName = Arr::get($seed, 'name.S'); $item = $this->testModel->find(['id' => $seedId, 'id2' => $seedId2]); @@ -80,6 +83,109 @@ public function testFindRecord() $this->assertEquals($seedName, $item->name); } + public function testFirstOrNewFirst() + { + $seed = $this->seed(); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); + $seedName = Arr::get($seed, 'name.S'); + $item = $this->testModel->firstOrNew(['id' => $seedId, 'id2' => $seedId2], ['name' => ['S' => Str::random()]]); + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$seedId, $seedId2, $seedName], [$item->id, $item->id2, $item->name]); + } + + public function testFirstOrNewNew() + { + $attributes = [ + 'id' => 'id', + 'id2' => Str::random(), + 'count' => rand() + ]; + $extra = [ + 'name' => Str::random() + ]; + + $item = $this->testModel->firstOrNew($attributes, $extra); + $item->id = $attributes['id']; + $item->id2 = $attributes['id2']; + $this->assertNotEmpty($item); + $this->assertEquals([$attributes['count'], $extra['name']], [$item->count, $item->name]); + $this->assertFalse($item->exists); + } + + public function testFirstOrCreateFirst() + { + $seed = $this->seed(); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); + $seedName = Arr::get($seed, 'name.S'); + + $item = $this->testModel->firstOrCreate(['id' => $seedId, 'id2' => $seedId2], ['name' => Str::random()]); + + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$seedId, $seedId2, $seedName], [$item->id, $item->id2, $item->name]); + } + + public function testFirstOrCreateCreate() + { + Model::unguard(); + $attributes = [ + 'id' => 'id', + 'id2' => Str::random(), + 'count' => rand() + ]; + $extra = [ + 'name' => Str::random() + ]; + + $item = $this->testModel->firstOrCreate($attributes, $extra); + + Model::reguard(); + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$attributes['id'], $attributes['id2'], $attributes['count'], $extra['name']], [$item->id, $item->id2, $item->count, $item->name]); + } + + public function testUpdateOrCreateUpdate() + { + $seed = $this->seed(); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); + + $newName = Str::random(); + + $item = $this->testModel->updateOrCreate(['id' => $seedId, 'id2' => $seedId2], ['name' => $newName]); + + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$seedId, $seedId2, $newName], [$item->id , $item->id2, $item->name]); + } + + public function testUpdateOrCreateCreate() + { + Model::unguard(); + $attributes = [ + 'id' => 'id', + 'id2' => Str::random(), + 'count' => rand() + ]; + $extra = [ + 'name' => Str::random() + ]; + + $item = $this->testModel->updateOrCreate($attributes, $extra); + + Model::reguard(); + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals($attributes['id'], $item->id); + $this->assertEquals($attributes['id2'], $item->id2); + $this->assertEquals($attributes['count'], $item->count); + $this->assertEquals($extra['name'], $item->name); + } + public function testFindMultiple() { $hash = ['foo', 'foo1']; @@ -111,9 +217,9 @@ public function testFindMultiple() public function testFindOrFailRecordPass() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); - $seedName = array_get($seed, 'name.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); + $seedName = Arr::get($seed, 'name.S'); $item = $this->testModel->findOrFail(['id' => $seedId, 'id2' => $seedId2]); @@ -146,9 +252,9 @@ public function testFindOrFailMultiple() public function testFirstOrFailRecordPass() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); - $seedName = array_get($seed, 'name.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); + $seedName = Arr::get($seed, 'name.S'); $query = $this->testModel ->where('id', $seedId) @@ -180,8 +286,8 @@ public function testFirstOrFailRecordFail() public function testUpdateRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); $newName = 'New Name'; $this->testModel = $this->testModel->find(['id' => $seedId, 'id2' => $seedId2]); @@ -199,14 +305,14 @@ public function testUpdateRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testUpdateAsyncRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); $newName = 'New Name'; $this->testModel = $this->testModel->find(['id' => $seedId, 'id2' => $seedId2]); @@ -222,14 +328,14 @@ public function testUpdateAsyncRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testSaveRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); $newName = 'New Name to be saved'; $this->testModel = $this->testModel->find(['id' => $seedId, 'id2' => $seedId2]); @@ -247,14 +353,14 @@ public function testSaveRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testSaveAsyncRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); $newName = 'New Name to be saved asynchronously'; $this->testModel = $this->testModel->find(['id' => $seedId, 'id2' => $seedId2]); @@ -272,14 +378,14 @@ public function testSaveAsyncRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testDeleteRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); $this->testModel->find(['id' => $seedId, 'id2' => $seedId2])->delete(); @@ -299,8 +405,8 @@ public function testDeleteRecord() public function testDeleteAsyncRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedId2 = array_get($seed, 'id2.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedId2 = Arr::get($seed, 'id2.S'); $this->testModel->find(['id' => $seedId, 'id2' => $seedId2])->deleteAsync()->wait(); @@ -451,7 +557,7 @@ public function testSetIndexManually() ->withIndex('id_author_index') ->toDynamoDbQuery(); - $this->assertEquals('id_author_index', array_get($raw->query, 'IndexName')); + $this->assertEquals('id_author_index', Arr::get($raw->query, 'IndexName')); $this->assertEquals('Query', $raw->op); } @@ -573,13 +679,13 @@ public function testAfterKeyForQueryOperation() $query = $this->testModel->where('id', 'id')->where('id2', '>', '-1'); $this->assertEquals('Query', $query->toDynamoDbQuery()->op); - + do { $items = $query->afterKey($afterKey)->limit(2)->all(); $paginationResult = $paginationResult->merge($items->pluck('id2')); $afterKey = $getKey($items); } while ($afterKey); - + $this->assertCount(10, $paginationResult); $paginationResult->each(function ($id) { $this->assertGreaterThan('-1', $id); @@ -756,11 +862,11 @@ public function seed($attributes = [], $exclude = []) { $item = [ 'id' => ['S' => 'id1'], - 'id2' => ['S' => str_random(36)], - 'name' => ['S' => str_random(36)], - 'description' => ['S' => str_random(256)], + 'id2' => ['S' => Str::random(36)], + 'name' => ['S' => Str::random(36)], + 'description' => ['S' => Str::random(256)], 'count' => ['N' => rand()], - 'author' => ['S' => str_random()], + 'author' => ['S' => Str::random()], 'nested' => [ 'M' => [ 'foo' => ['S' => 'bar'], @@ -777,7 +883,7 @@ public function seed($attributes = [], $exclude = []) ]; $item = array_merge($item, $attributes); - $item = array_except($item, $exclude); + $item = Arr::except($item, $exclude); $this->getClient()->putItem([ 'TableName' => $this->testModel->getTable(), diff --git a/tests/DynamoDbModelTest.php b/tests/DynamoDbModelTest.php index 645b3e0..32ce202 100644 --- a/tests/DynamoDbModelTest.php +++ b/tests/DynamoDbModelTest.php @@ -21,7 +21,7 @@ abstract class DynamoDbModelTest extends DynamoDbTestCase */ protected $marshaler; - public function setUp() + public function setUp(): void { parent::setUp(); diff --git a/tests/DynamoDbNonCompositeModelTest.php b/tests/DynamoDbNonCompositeModelTest.php index 515c6bd..a72cfd1 100644 --- a/tests/DynamoDbNonCompositeModelTest.php +++ b/tests/DynamoDbNonCompositeModelTest.php @@ -4,7 +4,10 @@ use BaoPham\DynamoDb\DynamoDbModel; use BaoPham\DynamoDb\RawDynamoDbQuery; +use Illuminate\Database\Eloquent\Model; use \Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Support\Arr; +use Illuminate\Support\Str; /** * Class DynamoDbNonCompositeModelTest @@ -20,7 +23,7 @@ protected function getTestModel() public function testCreateRecord() { - $this->testModel->id = str_random(36); + $this->testModel->id = Str::random(36); $this->testModel->name = 'Test Create'; $this->testModel->count = 1; $this->testModel->save(); @@ -40,7 +43,7 @@ public function testCreateRecord() public function testCreateAsyncRecord() { - $this->testModel->id = str_random(36); + $this->testModel->id = Str::random(36); $this->testModel->name = 'Test Create Async'; $this->testModel->count = 1; $this->testModel->saveAsync()->wait(); @@ -61,8 +64,8 @@ public function testCreateAsyncRecord() public function testFindRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedName = array_get($seed, 'name.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedName = Arr::get($seed, 'name.S'); $item = $this->testModel->find($seedId); @@ -71,6 +74,101 @@ public function testFindRecord() $this->assertEquals($seedName, $item->name); } + public function testFirstOrNewFirst() + { + $seed = $this->seed(); + $seedId = Arr::get($seed, 'id.S'); + $seedName = Arr::get($seed, 'name.S'); + $item = $this->testModel->firstOrNew(['id' => $seedId], ['name' => ['S' => Str::random()]]); + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$seedId, $seedName], [$item->id, $item->name]); + } + + public function testFirstOrNewNew() + { + $attributes = [ + 'id' => 'id', + 'count' => rand() + ]; + $extra = [ + 'name' => Str::random() + ]; + + $item = $this->testModel->firstOrNew($attributes, $extra); + $item->id = $attributes['id']; + $this->assertNotEmpty($item); + $this->assertEquals([$attributes['count'], $extra['name']], [$item->count, $item->name]); + $this->assertFalse($item->exists); + } + + public function testFirstOrCreateFirst() + { + $seed = $this->seed(); + $seedId = Arr::get($seed, 'id.S'); + $seedName = Arr::get($seed, 'name.S'); + + $item = $this->testModel->firstOrCreate(['id' => $seedId], ['name' => Str::random()]); + + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$seedId, $seedName], [$item->id, $item->name]); + } + + public function testFirstOrCreateCreate() + { + Model::unguard(); + $attributes = [ + 'id' => 'id', + 'count' => rand() + ]; + $extra = [ + 'name' => Str::random() + ]; + + $item = $this->testModel->firstOrCreate($attributes, $extra); + + Model::reguard(); + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals($attributes['id'], $item->id); + $this->assertEquals($attributes['count'], $item->count); + $this->assertEquals($extra['name'], $item->name); + } + + public function testUpdateOrCreateUpdate() + { + $seed = $this->seed(); + $seedId = Arr::get($seed, 'id.S'); + + $newName = Str::random(); + + $item = $this->testModel->updateOrCreate(['id' => $seedId], ['name' => $newName]); + + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$seedId, $newName], [$item->id, $item->name]); + } + + public function testUpdateOrCreateCreate() + { + Model::unguard(); + $attributes = [ + 'id' => 'id', + 'count' => rand() + ]; + $extra = [ + 'name' => Str::random() + ]; + + $item = $this->testModel->updateOrCreate($attributes, $extra); + + Model::reguard(); + $this->assertNotEmpty($item); + $this->assertTrue($item->exists); + $this->assertEquals([$attributes['id'], $attributes['count'], $extra['name']], [$item->id, $item->count, $item->name]); + } + public function testFindMultiple() { $ids = ['foo', 'bar']; @@ -95,8 +193,8 @@ public function testFindMultiple() public function testFindOrFailRecordPass() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedName = array_get($seed, 'name.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedName = Arr::get($seed, 'name.S'); $item = $this->testModel->findOrFail($seedId); @@ -121,8 +219,8 @@ public function testFindOrFailMultiple() public function testFirstOrFailRecordPass() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); - $seedName = array_get($seed, 'name.S'); + $seedId = Arr::get($seed, 'id.S'); + $seedName = Arr::get($seed, 'name.S'); $query = $this->testModel ->where('id', $seedId); @@ -161,7 +259,7 @@ public function testGetAllRecords() public function testUpdateRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); + $seedId = Arr::get($seed, 'id.S'); $newName = 'New Name'; $this->testModel = $this->testModel->find($seedId); @@ -178,13 +276,13 @@ public function testUpdateRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testUpdateAsyncRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); + $seedId = Arr::get($seed, 'id.S'); $newName = 'New Name'; $this->testModel = $this->testModel->find($seedId); @@ -199,13 +297,13 @@ public function testUpdateAsyncRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testSaveRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); + $seedId = Arr::get($seed, 'id.S'); $newName = 'New Name to be saved'; $this->testModel = $this->testModel->find($seedId); @@ -222,13 +320,13 @@ public function testSaveRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testSaveAsyncRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); + $seedId = Arr::get($seed, 'id.S'); $newName = 'New Name to be saved asynchronously'; $this->testModel = $this->testModel->find($seedId); @@ -245,13 +343,13 @@ public function testSaveAsyncRecord() $record = $this->getClient()->getItem($query)->toArray(); - $this->assertEquals($newName, array_get($record, 'Item.name.S')); + $this->assertEquals($newName, Arr::get($record, 'Item.name.S')); } public function testDeleteRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); + $seedId = Arr::get($seed, 'id.S'); $this->testModel->find($seedId)->delete(); @@ -270,7 +368,7 @@ public function testDeleteRecord() public function testDeleteAsyncRecord() { $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); + $seedId = Arr::get($seed, 'id.S'); $this->testModel->find($seedId)->deleteAsync()->wait(); @@ -492,7 +590,7 @@ public function testGetFirstRecord() $items = $this->testModel->first(); - $this->assertEquals(array_get($firstItem, 'id.S'), $items->id); + $this->assertEquals(Arr::get($firstItem, 'id.S'), $items->id); } public function testChainedMethods() @@ -909,7 +1007,7 @@ public function testAfterKeyForQueryOperation() $this->assertEquals(10, $count); }); } - + public function testAfterKeyForScanOperation() { foreach (range(0, 9) as $i) { @@ -919,7 +1017,7 @@ public function testAfterKeyForScanOperation() $assert = function (callable $getKey) { $paginationResult = collect(); $afterKey = null; - + do { $items = $this->testModel ->afterKey($afterKey) @@ -927,10 +1025,10 @@ public function testAfterKeyForScanOperation() $afterKey = $getKey($items); $paginationResult = $paginationResult->merge($items->pluck('count')); } while ($afterKey); - + $this->assertEquals(range(0, 9), $paginationResult->sort()->values()->toArray()); }; - + $assert(function ($items) { return $items->lastKey(); }); @@ -1156,6 +1254,28 @@ public function testQueryNestedAttributes() $this->assertEquals($item['id']['S'], $results->first()->id); } + public function testBuilderContainsAllWhereClausesWhenGivenArrayOfConditions() + { + /** @var array $conditions */ + $conditions = [ + "foo" => "bar", + "bin" => "baz" + ]; + + $builder = $this->getTestModel()->where($conditions); + + /** @var array $conditionsFromBuilder */ + $conditionsFromBuilder = []; + + /** @var array $builderConditions */ + foreach ($builder->wheres as $builderConditions) { + $conditionsFromBuilder[$builderConditions['column']] = $builderConditions['value']; + } + + // Assert that the builder has the where-conditions we expect to see + $this->assertEquals($conditions, $conditionsFromBuilder); + } + protected function assertRemoveAttributes($item) { $this->assertNull($item->name); @@ -1172,11 +1292,11 @@ protected function assertRemoveAttributes($item) public function seed($attributes = [], $exclude = []) { $item = [ - 'id' => ['S' => str_random(36)], - 'name' => ['S' => str_random(36)], - 'description' => ['S' => str_random(256)], + 'id' => ['S' => Str::random(36)], + 'name' => ['S' => Str::random(36)], + 'description' => ['S' => Str::random(256)], 'count' => ['N' => rand()], - 'author' => ['S' => str_random()], + 'author' => ['S' => Str::random()], 'nested' => [ 'M' => [ 'foo' => ['S' => 'bar'], @@ -1193,7 +1313,7 @@ public function seed($attributes = [], $exclude = []) ]; $item = array_merge($item, $attributes); - $item = array_except($item, $exclude); + $item = Arr::except($item, $exclude); $this->getClient()->putItem([ 'TableName' => $this->testModel->getTable(), diff --git a/tests/DynamoDbQueryScopeTest.php b/tests/DynamoDbQueryScopeTest.php index b8cafa4..21a827f 100644 --- a/tests/DynamoDbQueryScopeTest.php +++ b/tests/DynamoDbQueryScopeTest.php @@ -3,6 +3,7 @@ namespace BaoPham\DynamoDb\Tests; use BaoPham\DynamoDb\DynamoDbQueryBuilder; +use Illuminate\Support\Str; /** * Class DynamoDbQueryScopeTest @@ -114,11 +115,11 @@ public function testChunkWithDynamicLocalScope() public function seed($attributes = []) { $item = [ - 'id' => ['S' => str_random(36)], - 'name' => ['S' => str_random(36)], - 'description' => ['S' => str_random(256)], + 'id' => ['S' => Str::random(36)], + 'name' => ['S' => Str::random(36)], + 'description' => ['S' => Str::random(256)], 'count' => ['N' => rand()], - 'author' => ['S' => str_random()], + 'author' => ['S' => Str::random()], ]; $item = array_merge($item, $attributes); diff --git a/tests/DynamoDbTestCase.php b/tests/DynamoDbTestCase.php index 0e99f00..f0c0c19 100644 --- a/tests/DynamoDbTestCase.php +++ b/tests/DynamoDbTestCase.php @@ -12,7 +12,7 @@ */ abstract class DynamoDbTestCase extends TestCase { - public function setUp() + public function setUp(): void { parent::setUp(); diff --git a/tests/DynamoDbTimestampTest.php b/tests/DynamoDbTimestampTest.php index 74344f4..8353abe 100644 --- a/tests/DynamoDbTimestampTest.php +++ b/tests/DynamoDbTimestampTest.php @@ -3,6 +3,8 @@ namespace BaoPham\DynamoDb\Tests; use Carbon\Carbon; +use Illuminate\Support\Arr; +use Illuminate\Support\Str; /** * Class DynamoDbTimestampTest @@ -20,7 +22,7 @@ public function testCreateRecord() { Carbon::setTestNow(Carbon::create(2017, 06, 24, 5, 30, 0)); $now = new Carbon; - $this->testModel->id = str_random(36); + $this->testModel->id = Str::random(36); $this->testModel->name = 'Test Create'; $this->testModel->count = 1; $this->testModel->save(); @@ -43,7 +45,7 @@ public function testUpdateRecord() Carbon::setTestNow(Carbon::create(2017, 03, 01, 8, 30, 0)); $now = new Carbon(); $seed = $this->seed(); - $seedId = array_get($seed, 'id.S'); + $seedId = Arr::get($seed, 'id.S'); $newName = 'New Name'; $model = $this->testModel->find($seedId); @@ -67,11 +69,11 @@ public function testUpdateRecord() public function seed($attributes = []) { $item = [ - 'id' => ['S' => str_random(36)], - 'name' => ['S' => str_random(36)], - 'description' => ['S' => str_random(256)], + 'id' => ['S' => Str::random(36)], + 'name' => ['S' => Str::random(36)], + 'description' => ['S' => Str::random(256)], 'count' => ['N' => rand()], - 'author' => ['S' => str_random()], + 'author' => ['S' => Str::random()], ]; $item = array_merge($item, $attributes); diff --git a/tests/Parsers/ConditionExpressionTest.php b/tests/Parsers/ConditionExpressionTest.php index e1e2ad7..021bcab 100644 --- a/tests/Parsers/ConditionExpressionTest.php +++ b/tests/Parsers/ConditionExpressionTest.php @@ -8,6 +8,7 @@ use BaoPham\DynamoDb\Parsers\ExpressionAttributeValues; use BaoPham\DynamoDb\Parsers\Placeholder; use PHPUnit\Framework\TestCase; +use Illuminate\Support\Arr; class ConditionExpressionTest extends TestCase { @@ -26,7 +27,7 @@ class ConditionExpressionTest extends TestCase */ private $values; - public function setUp() + public function setUp(): void { parent::setUp(); $this->names = new ExpressionAttributeNames(); @@ -156,7 +157,7 @@ public function testParse() $this->assertEquals(['BOOL' => true], $this->values->get(':a13')); $this->assertEquals(['S' => 'android'], $this->values->get(':a14')); - $columns = array_filter(array_pluck($where, 'column')); + $columns = array_filter(Arr::pluck($where, 'column')); foreach ($columns as $column) { $this->assertEquals($column, $this->names->get("#{$column}")); diff --git a/tests/Parsers/UpdateExpressionTest.php b/tests/Parsers/UpdateExpressionTest.php index b8b0f27..a536755 100644 --- a/tests/Parsers/UpdateExpressionTest.php +++ b/tests/Parsers/UpdateExpressionTest.php @@ -18,7 +18,7 @@ class UpdateExpressionTest extends TestCase */ private $names; - public function setUp() + public function setUp(): void { parent::setUp(); $this->names = new ExpressionAttributeNames();