diff --git a/README.md b/README.md index d10a34c..696ff70 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ composer require stellarwp/db - [CRUD](#crud) - [Insert](#insert) - [Update](#update) + - [Upsert](#upsert) - [Delete](#delete) - [Get](#get) @@ -847,6 +848,28 @@ DB::table('posts') ]); ``` +### Upsert + +The `QueryBuilder::upsert` method may be used to update an existing record or create a new record if it doesn't exist. + +```php +// Would result in a new row - Oakland to San Diego for 100. +DB::table('table_name') + ->upsert( + ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => '100'] , + ['departure','destination'] + ); + + +// Would update the row that was just inserted - Oakland to San Diego for 99. +DB::table('table_name') + ->upsert( + ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => '99'] , + ['departure','destination'] + ); + +``` + ### Delete The `QueryBuilder::delete` method may be used to delete records from the table. diff --git a/src/DB/QueryBuilder/Concerns/CRUD.php b/src/DB/QueryBuilder/Concerns/CRUD.php index 43bbcf8..269ef5f 100644 --- a/src/DB/QueryBuilder/Concerns/CRUD.php +++ b/src/DB/QueryBuilder/Concerns/CRUD.php @@ -48,6 +48,32 @@ public function update( $data, $format = null ) { ); } + /** + * Upsert allows for inserting or updating a row depending on whether it already exists. + * + * @since 1.0.8 + * + * @param array $data The data to insert or update. + * @param array $match The columns to match on. + * @param string|array|null $format Array of formats to be mapped to each value in $data. If string, the format will be used for all values in $data. + * + * @return false|int Number of rows updated/inserted, false on error. + */ + public function upsert( $data, $match = [], $format = null ) { + // Build the where clause(s). + foreach ( $match as $column ) { + $this->where( $column, $data[ $column ] ); + } + + // If the row exists, update it. + if ( $this->get() ) { + return $this->update( $data, $format ); + } + + // Otherwise, insert it. + return $this->insert( $data, $format ); + } + /** * @since 1.0.0 * diff --git a/tests/wpunit/QueryBuilder/CRUDTest.php b/tests/wpunit/QueryBuilder/CRUDTest.php index b554790..894e692 100644 --- a/tests/wpunit/QueryBuilder/CRUDTest.php +++ b/tests/wpunit/QueryBuilder/CRUDTest.php @@ -129,4 +129,89 @@ public function testDeleteShouldDeleteRowInDatabase() $this->assertNull($post); } + /** + * Tests if upsert() adds a row to the database. + * + * @return void + */ + public function testUpsertShouldAddRowToDatabase() + { + $data = [ + 'post_title' => 'Query Builder CRUD test', + 'post_type' => 'crud_test', + 'post_content' => 'Hello World!', + ]; + + DB::table('posts')->upsert($data); + + $id = DB::last_insert_id(); + + $post = DB::table('posts') + ->select('post_title', 'post_type', 'post_content') + ->where('ID', $id) + ->get(); + + $this->assertEquals($data['post_title'], $post->post_title); + $this->assertEquals($data['post_type'], $post->post_type); + $this->assertEquals($data['post_content'], $post->post_content); + } + + /** + * Tests if upsert() updates a row in the database. + * + * @return void + */ + public function testUpsertShouldUpdateRowInDatabase() + { + $data = [ + 'post_title' => 'Query Builder CRUD test - upsert update', + 'post_type' => 'crud_test', + 'post_content' => 'Hello World from upsert!', + ]; + + DB::table('posts')->insert($data); + + $original_id = DB::last_insert_id(); + + $updated_data = [ + 'post_title' => 'Query Builder CRUD test - upsert update', + 'post_type' => 'crud_test', + 'post_content' => 'Hello World from upsert! - updated', + ]; + + $match = [ + 'post_title', + ]; + + DB::table('posts')->upsert( $updated_data, $match ); + + $post = DB::table('posts') + ->select('post_title', 'post_type', 'post_content') + ->where('ID', $original_id) + ->get(); + + $this->assertEquals($updated_data['post_content'], $post->post_content); + + // Test multiple match columns + $further_updated_data = [ + 'post_title' => 'Query Builder CRUD test - upsert update', + 'post_type' => 'crud_test', + 'post_content' => 'Hello World from upsert! - updated even more!', + ]; + + $match = [ + 'post_title', + 'post_type', + ]; + + DB::table('posts')->upsert( $further_updated_data, $match ); + + $post = DB::table('posts') + ->select('post_title', 'post_type', 'post_content') + ->where('ID', $original_id) + ->get(); + + $this->assertEquals($further_updated_data['post_content'], $post->post_content); + } + }