diff --git a/composer.json b/composer.json index d2abd1385a82..36de436b07e0 100644 --- a/composer.json +++ b/composer.json @@ -114,4 +114,4 @@ "entry": "ServiceBuilder.php" } } -} \ No newline at end of file +} diff --git a/src/BigQuery/BigQueryClient.php b/src/BigQuery/BigQueryClient.php index 598f0f1f66fd..aa2e81fa3666 100644 --- a/src/BigQuery/BigQueryClient.php +++ b/src/BigQuery/BigQueryClient.php @@ -20,7 +20,6 @@ use Google\Cloud\BigQuery\Connection\ConnectionInterface; use Google\Cloud\BigQuery\Connection\Rest; use Google\Cloud\BigQuery\Job; -use Google\Cloud\Core\ArrayTrait; use Google\Cloud\Core\ClientTrait; use Google\Cloud\Core\ExponentialBackoff; use Google\Cloud\Core\Int64; @@ -43,7 +42,6 @@ */ class BigQueryClient { - use ArrayTrait; use ClientTrait; use JobConfigurationTrait; @@ -291,6 +289,8 @@ public function runQuery($query, array $options = []) * @type array $jobConfig Configuration settings for a query job are * outlined in the [API Docs for `configuration.query`](https://goo.gl/PuRa3I). * If not provided default settings will be used. + * @type string $jobIdPrefix [optional] If given, the returned job ID will + * be of format `{$jobIdPrefix-}{jobId}`. **Defaults to** `null`. * } * @return Job */ diff --git a/src/BigQuery/JobConfigurationTrait.php b/src/BigQuery/JobConfigurationTrait.php index 2a3829453b55..2ec37ca0be99 100644 --- a/src/BigQuery/JobConfigurationTrait.php +++ b/src/BigQuery/JobConfigurationTrait.php @@ -17,11 +17,16 @@ namespace Google\Cloud\BigQuery; +use Google\Cloud\Core\ArrayTrait; +use Ramsey\Uuid\Uuid; + /** * A trait used to build out configuration for jobs. */ trait JobConfigurationTrait { + use ArrayTrait; + /** * Builds a configuration for a job. * @@ -33,6 +38,8 @@ trait JobConfigurationTrait */ public function buildJobConfig($name, $projectId, array $config, array $userDefinedOptions) { + $jobIdPrefix = $this->pluck('jobIdPrefix', $userDefinedOptions, false); + if (isset($userDefinedOptions['jobConfig'])) { $config = $userDefinedOptions['jobConfig'] + $config; } @@ -41,9 +48,31 @@ public function buildJobConfig($name, $projectId, array $config, array $userDefi return [ 'projectId' => $projectId, + 'jobReference' => [ + 'projectId' => $projectId, + 'jobId' => $this->generateJobId($jobIdPrefix) + ], 'configuration' => [ $name => $config ] ] + $userDefinedOptions; } + + /** + * Generate a Job ID with an optional user-defined prefix. + * + * @param string $jobIdPrefix [optional] If given, the returned job ID will + * be of format `{$jobIdPrefix-}{jobId}`. **Defaults to** `null`. + * @return string + */ + protected function generateJobId($jobIdPrefix = null) + { + $jobId = ''; + + if ($jobIdPrefix) { + $jobId = $jobIdPrefix . '-'; + } + + return $jobId . Uuid::uuid4(); + } } diff --git a/src/BigQuery/Table.php b/src/BigQuery/Table.php index 12e8c7de2687..b7749ffdea1a 100644 --- a/src/BigQuery/Table.php +++ b/src/BigQuery/Table.php @@ -18,7 +18,6 @@ namespace Google\Cloud\BigQuery; use Google\Cloud\BigQuery\Connection\ConnectionInterface; -use Google\Cloud\Core\ArrayTrait; use Google\Cloud\Core\ConcurrencyControlTrait; use Google\Cloud\Core\Exception\NotFoundException; use Google\Cloud\Core\Iterator\ItemIterator; @@ -33,7 +32,6 @@ */ class Table { - use ArrayTrait; use ConcurrencyControlTrait; use JobConfigurationTrait; @@ -239,6 +237,8 @@ function (array $row) use ($schema) { * @type array $jobConfig Configuration settings for a copy job are * outlined in the [API Docs for `configuration.copy`](https://goo.gl/m8dro9). * If not provided default settings will be used. + * @type string $jobIdPrefix [optional] If given, the returned job ID will + * be of format `{$jobIdPrefix-}{jobId}`. **Defaults to** `null`. * } * @return Job */ @@ -287,6 +287,8 @@ public function copy(Table $destination, array $options = []) * @type array $jobConfig Configuration settings for an extract job are * outlined in the [API Docs for `configuration.extract`](https://goo.gl/SQ9XAE). * If not provided default settings will be used. + * @type string $jobIdPrefix [optional] If given, the returned job ID will + * be of format `{$jobIdPrefix-}{jobId}`. **Defaults to** `null`. * } * @return Job */ @@ -334,6 +336,8 @@ public function export($destination, array $options = []) * @type array $jobConfig Configuration settings for a load job are * outlined in the [API Docs for `configuration.load`](https://goo.gl/j6jyHv). * If not provided default settings will be used. + * @type string $jobIdPrefix [optional] If given, the returned job ID will + * be of format `{$jobIdPrefix-}{jobId}`. **Defaults to** `null`. * } * @return Job */ diff --git a/src/BigQuery/composer.json b/src/BigQuery/composer.json index 6eded48fdc12..cf54b78f6b6b 100644 --- a/src/BigQuery/composer.json +++ b/src/BigQuery/composer.json @@ -4,7 +4,8 @@ "license": "Apache-2.0", "minimum-stability": "stable", "require": { - "google/cloud-core": "^1.0" + "google/cloud-core": "^1.0", + "ramsey/uuid": "~3" }, "suggest": { "google/cloud-storage": "Makes it easier to load data from Cloud Storage into BigQuery" diff --git a/tests/unit/BigQuery/BigQueryClientTest.php b/tests/unit/BigQuery/BigQueryClientTest.php index 6fddc4bb132f..6a1edad3c270 100644 --- a/tests/unit/BigQuery/BigQueryClientTest.php +++ b/tests/unit/BigQuery/BigQueryClientTest.php @@ -34,8 +34,9 @@ */ class BigQueryClientTest extends \PHPUnit_Framework_TestCase { + const JOBID = 'myJobId'; + public $connection; - public $jobId = 'myJobId'; public $projectId = 'myProjectId'; public $datasetId = 'myDatasetId'; public $client; @@ -43,7 +44,7 @@ class BigQueryClientTest extends \PHPUnit_Framework_TestCase public function setUp() { $this->connection = $this->prophesize(ConnectionInterface::class); - $this->client = new BigQueryTestClient(['projectId' => $this->projectId]); + $this->client = \Google\Cloud\Dev\stub(BigQueryTestClient::class, ['options' => ['projectId' => $this->projectId]]); } /** @@ -54,16 +55,16 @@ public function testRunsQuery($query, $options, $expected) $this->connection->query($expected) ->willReturn([ 'jobReference' => [ - 'jobId' => $this->jobId + 'jobId' => self::JOBID ], 'jobComplete' => true ]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $queryResults = $this->client->runQuery($query, $options); $this->assertInstanceOf(QueryResults::class, $queryResults); - $this->assertEquals($this->jobId, $queryResults->identity()['jobId']); + $this->assertEquals(self::JOBID, $queryResults->identity()['jobId']); } /** @@ -74,7 +75,7 @@ public function testRunsQueryWithRetry($query, $options, $expected) $this->connection->query($expected) ->willReturn([ 'jobReference' => [ - 'jobId' => $this->jobId + 'jobId' => self::JOBID ], 'jobComplete' => false ]) @@ -83,17 +84,17 @@ public function testRunsQueryWithRetry($query, $options, $expected) $this->connection->getQueryResults(Argument::any()) ->willReturn([ 'jobReference' => [ - 'jobId' => $this->jobId + 'jobId' => self::JOBID ], 'jobComplete' => true ]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $queryResults = $this->client->runQuery($query, $options); $this->assertInstanceOf(QueryResults::class, $queryResults); - $this->assertEquals($this->jobId, $queryResults->identity()['jobId']); + $this->assertEquals(self::JOBID, $queryResults->identity()['jobId']); } /** @@ -107,17 +108,22 @@ public function testRunsQueryAsJob($query, $options, $expected) 'projectId' => $projectId, 'configuration' => [ 'query' => $expected + ], + 'jobReference' => [ + 'projectId' => $projectId, + 'jobId' => self::JOBID ] ]) ->willReturn([ - 'jobReference' => ['jobId' => $this->jobId] + 'jobReference' => ['jobId' => self::JOBID] ]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + + $this->client->___setProperty('connection', $this->connection->reveal()); $job = $this->client->runQueryAsJob($query, $options); $this->assertInstanceOf(Job::class, $job); - $this->assertEquals($this->jobId, $job->id()); + $this->assertEquals(self::JOBID, $job->id()); } public function queryDataProvider() @@ -193,8 +199,8 @@ public function queryDataProvider() public function testGetsJob() { - $this->client->setConnection($this->connection->reveal()); - $this->assertInstanceOf(Job::class, $this->client->job($this->jobId)); + $this->client->___setProperty('connection', $this->connection->reveal()); + $this->assertInstanceOf(Job::class, $this->client->job(self::JOBID)); } public function testGetsJobsWithNoResults() @@ -203,7 +209,7 @@ public function testGetsJobsWithNoResults() ->willReturn([]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $jobs = iterator_to_array($this->client->jobs()); $this->assertEmpty($jobs); @@ -214,15 +220,15 @@ public function testGetsJobsWithoutToken() $this->connection->listJobs(['projectId' => $this->projectId]) ->willReturn([ 'jobs' => [ - ['jobReference' => ['jobId' => $this->jobId]] + ['jobReference' => ['jobId' => self::JOBID]] ] ]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $jobs = iterator_to_array($this->client->jobs()); - $this->assertEquals($this->jobId, $jobs[0]->id()); + $this->assertEquals(self::JOBID, $jobs[0]->id()); } public function testGetsJobsWithToken() @@ -241,19 +247,19 @@ public function testGetsJobsWithToken() ]) ->willReturn([ 'jobs' => [ - ['jobReference' => ['jobId' => $this->jobId]] + ['jobReference' => ['jobId' => self::JOBID]] ] ])->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $job = iterator_to_array($this->client->jobs()); - $this->assertEquals($this->jobId, $job[1]->id()); + $this->assertEquals(self::JOBID, $job[1]->id()); } public function testGetsDataset() { - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $this->assertInstanceOf(Dataset::class, $this->client->dataset($this->datasetId)); } @@ -263,7 +269,7 @@ public function testGetsDatasetsWithNoResults() ->willReturn([]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $datasets = iterator_to_array($this->client->datasets()); $this->assertEmpty($datasets); @@ -279,7 +285,7 @@ public function testGetsDatasetsWithoutToken() ]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $datasets = iterator_to_array($this->client->datasets()); $this->assertEquals($this->datasetId, $datasets[0]->id()); @@ -303,7 +309,7 @@ public function testGetsDatasetsWithToken() ) ->shouldBeCalledTimes(2); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $dataset = iterator_to_array($this->client->datasets()); $this->assertEquals($this->datasetId, $dataset[1]->id()); @@ -318,7 +324,7 @@ public function testCreatesDataset() ] ]) ->shouldBeCalledTimes(1); - $this->client->setConnection($this->connection->reveal()); + $this->client->___setProperty('connection', $this->connection->reveal()); $dataset = $this->client->createDataset($this->datasetId, [ 'metadata' => [ @@ -360,8 +366,8 @@ public function testGetsTimestamp() class BigQueryTestClient extends BigQueryClient { - public function setConnection($connection) + protected function generateJobId($jobIdPrefix = null) { - $this->connection = $connection; + return $jobIdPrefix ? $jobIdPrefix . '-' . BigQueryClientTest::JOBID : BigQueryClientTest::JOBID; } } diff --git a/tests/unit/BigQuery/JobConfigurationTraitTest.php b/tests/unit/BigQuery/JobConfigurationTraitTest.php new file mode 100644 index 000000000000..22dd9c706306 --- /dev/null +++ b/tests/unit/BigQuery/JobConfigurationTraitTest.php @@ -0,0 +1,43 @@ +trait = \Google\Cloud\Dev\impl(JobConfigurationTrait::class); + } + + public function testGenerateJobId() + { + $this->assertTrue(is_string($this->trait->call('generateJobId'))); + } + + public function testGenerateJobIdWithPrefix() + { + $this->assertTrue(strpos($this->trait->call('generateJobId', ['foobar']), 'foobar-') === 0); + } +} diff --git a/tests/unit/BigQuery/TableTest.php b/tests/unit/BigQuery/TableTest.php index 783c5d65dfd5..46110adb5dd7 100644 --- a/tests/unit/BigQuery/TableTest.php +++ b/tests/unit/BigQuery/TableTest.php @@ -33,6 +33,8 @@ */ class TableTest extends \PHPUnit_Framework_TestCase { + const JOBID = 'myJobId'; + public $connection; public $storageConnection; public $mapper; @@ -58,7 +60,7 @@ class TableTest extends \PHPUnit_Framework_TestCase ]; public $insertJobResponse = [ 'jobReference' => [ - 'jobId' => 'myJobId' + 'jobId' => self::JOBID ] ]; @@ -80,7 +82,7 @@ public function getObject() public function getTable($connection, array $data = [], $tableId = null) { - return new Table( + return new TableStub( $connection->reveal(), $tableId ?: $this->tableId, $this->datasetId, @@ -221,6 +223,10 @@ public function testRunsCopyJob() 'projectId' => $this->projectId ] ] + ], + 'jobReference' => [ + 'projectId' => $this->projectId, + 'jobId' => self::JOBID ] ]; $this->connection->insertJob(Argument::exact($expectedArguments)) @@ -251,6 +257,10 @@ public function testRunsExportJob($destinationObject) 'projectId' => $this->projectId ] ] + ], + 'jobReference' => [ + 'projectId' => $this->projectId, + 'jobId' => self::JOBID ] ]; $this->connection->insertJob(Argument::exact($expectedArguments)) @@ -295,6 +305,10 @@ public function testRunsLoadJob() 'projectId' => $this->projectId ] ] + ], + 'jobReference' => [ + 'projectId' => $this->projectId, + 'jobId' => self::JOBID ] ]; $this->connection->insertJobUpload(Argument::exact($expectedArguments)) @@ -323,6 +337,10 @@ public function testRunsLoadJobFromStorage() 'projectId' => $this->projectId ] ] + ], + 'jobReference' => [ + 'projectId' => $this->projectId, + 'jobId' => self::JOBID ] ]; $this->connection->insertJob(Argument::exact($expectedArguments)) @@ -439,3 +457,11 @@ public function testGetsIdentity() $this->assertEquals($this->projectId, $table->identity()['projectId']); } } + +class TableStub extends Table +{ + protected function generateJobId($jobIdPrefix = null) + { + return $jobIdPrefix ? $jobIdPrefix . '-' . BigQueryClientTest::JOBID : BigQueryClientTest::JOBID; + } +}