From efb28324bc26c77c942a75b4443b7216dc2e6c99 Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 14 Nov 2023 11:37:45 +1100 Subject: [PATCH 1/6] feat(spanner): add PG.OID type support for parameterized queries --- Spanner/src/Database.php | 1 + Spanner/src/PgOid.php | 102 ++++++++++++++++++++++++++++++++++ Spanner/src/SpannerClient.php | 15 +++++ Spanner/src/ValueMapper.php | 15 ++++- 4 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 Spanner/src/PgOid.php diff --git a/Spanner/src/Database.php b/Spanner/src/Database.php index 9f544d06a668..8639f0f889f5 100644 --- a/Spanner/src/Database.php +++ b/Spanner/src/Database.php @@ -121,6 +121,7 @@ class Database const TYPE_PG_NUMERIC = 'pgNumeric'; const TYPE_PG_JSONB = 'pgJsonb'; const TYPE_JSON = TypeCode::JSON; + const TYPE_PG_OID = 'pgOid'; /** * @var ConnectionInterface diff --git a/Spanner/src/PgOid.php b/Spanner/src/PgOid.php new file mode 100644 index 000000000000..8a3d0b9a1ced --- /dev/null +++ b/Spanner/src/PgOid.php @@ -0,0 +1,102 @@ +pgOid('123'); + * ``` + */ +class PgOid implements ValueInterface, TypeAnnotationInterface +{ + /** + * @var string|null + */ + private ?string $value; + + /** + * @param string|null $value The OID value. + */ + public function __construct(?string $value) + { + $this->value = $value; + } + + /** + * Get the underlying value. + * + * @return string|null + */ + public function get(): ?string + { + return $this->value; + } + + /** + * Get the type. + * + * @access private + * @return int + */ + public function type(): int + { + return ValueMapper::TYPE_INT64; + } + + /** + * Get the type annotation code. + * This is to be used along type, to differentiate the value from TypeCode::INT64. + * + * @access private + * @return int + */ + public function typeAnnotation(): int + { + return TypeAnnotationCode::PG_OID; + } + + /** + * Format the value as a string. + * + * @return string + */ + public function formatAsString(): ?string + { + return (string) $this->value; + } + + /** + * Format the value as a string. + * + * @return string + */ + public function __toString() + { + return (string) $this->value; + } +} diff --git a/Spanner/src/SpannerClient.php b/Spanner/src/SpannerClient.php index d1c15835ec5a..e9d48ca25b6b 100644 --- a/Spanner/src/SpannerClient.php +++ b/Spanner/src/SpannerClient.php @@ -823,6 +823,21 @@ public function pgJsonb($value) return new PgJsonb($value); } + /** + * Represents a value with a data type of + * [PG OID](https://cloud.google.com/spanner/docs/reference/postgresql/data-types) for the + * Postgres Dialect database. + * + * Example: + * ``` + * $pgOid = $spanner->pgOid('123'); + * ``` + */ + public function pgOid($value) + { + return new pgOid($value); + } + /** * Create an Int64 object. This can be used to work with 64 bit integers as * a string value while on a 32 bit platform. diff --git a/Spanner/src/ValueMapper.php b/Spanner/src/ValueMapper.php index aa92c2eade6f..a0372524dbd7 100644 --- a/Spanner/src/ValueMapper.php +++ b/Spanner/src/ValueMapper.php @@ -44,6 +44,7 @@ class ValueMapper const TYPE_JSON = TypeCode::JSON; const TYPE_PG_NUMERIC = 'pgNumeric'; const TYPE_PG_JSONB = 'pgJsonb'; + const TYPE_PG_OID = 'pgOid'; /** * @var array @@ -62,6 +63,7 @@ class ValueMapper self::TYPE_JSON, self::TYPE_PG_NUMERIC, self::TYPE_PG_JSONB, + self::TYPE_PG_OID, ]; /* @@ -76,6 +78,7 @@ class ValueMapper private static $typeToClassMap = [ self::TYPE_PG_NUMERIC => PgNumeric::class, self::TYPE_PG_JSONB => PgJsonb::class, + self::TYPE_PG_OID => PgOid::class, ]; /* @@ -87,6 +90,7 @@ class ValueMapper private static $typeCodes = [ self::TYPE_PG_NUMERIC => self::TYPE_NUMERIC, self::TYPE_PG_JSONB => self::TYPE_JSON, + self::Type_PG_OID => self::TYPE_INT64, ]; /* @@ -98,6 +102,7 @@ class ValueMapper private static $typeAnnotations = [ self::TYPE_PG_NUMERIC => TypeAnnotationCode::PG_NUMERIC, self::TYPE_PG_JSONB => TypeAnnotationCode::PG_JSONB, + self::TYPE_PG_OID => TypeAnnotationCode::PG_OID, ]; /** @@ -277,9 +282,13 @@ private function decodeValue($value, array $type) switch ($type['code']) { case self::TYPE_INT64: - $value = $this->returnInt64AsObject - ? new Int64($value) - : (int) $value; + if (isset($type['typeAnnotation']) && $type['typeAnnotation'] === TypeAnnotationCode::PG_OID) { + $value = new PgOid($value); + } else { + $value = $this->returnInt64AsObject + ? new Int64($value) + : (int) $value; + } break; case self::TYPE_TIMESTAMP: From b4e45d2ae9003dbe47ef9911a0226b5e25f8cb9f Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 14 Nov 2023 13:01:39 +1100 Subject: [PATCH 2/6] test(spanner): add testing for PG.OID type --- Spanner/tests/Snippet/PgOidTest.php | 37 +++++++++++++++++++++ Spanner/tests/Snippet/SpannerClientTest.php | 2 ++ Spanner/tests/System/PgQueryTest.php | 36 +++++++++++++++++++- Spanner/tests/Unit/ArrayTypeTest.php | 1 + Spanner/tests/Unit/SpannerClientTest.php | 6 ++++ Spanner/tests/Unit/ValueMapperTest.php | 27 +++++++++++++++ 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 Spanner/tests/Snippet/PgOidTest.php diff --git a/Spanner/tests/Snippet/PgOidTest.php b/Spanner/tests/Snippet/PgOidTest.php new file mode 100644 index 000000000000..7cdf215a3ad5 --- /dev/null +++ b/Spanner/tests/Snippet/PgOidTest.php @@ -0,0 +1,37 @@ +snippetFromClass(PgOid::class); + $res = $snippet->invoke('pgOid'); + + $this->assertInstanceOf(PgOid::class, $res->returnVal()); + $this->assertEquals($expected, $res->returnVal()); + } +} diff --git a/Spanner/tests/Snippet/SpannerClientTest.php b/Spanner/tests/Snippet/SpannerClientTest.php index d0f316779e80..564f75698cc1 100644 --- a/Spanner/tests/Snippet/SpannerClientTest.php +++ b/Spanner/tests/Snippet/SpannerClientTest.php @@ -39,6 +39,7 @@ use Google\Cloud\Spanner\Timestamp; use Google\Cloud\Spanner\Numeric; use Google\Cloud\Spanner\PgNumeric; +use Google\Cloud\Spanner\PgOid; use Google\Cloud\Spanner\PgJsonb; use Prophecy\Argument; @@ -261,6 +262,7 @@ public function factoriesProvider() [Numeric::class, 'numeric'], [PgNumeric::class, 'pgNumeric'], [PgJsonB::class, 'pgJsonb'], + [PgOid::class, 'pgOid'], ]; } diff --git a/Spanner/tests/System/PgQueryTest.php b/Spanner/tests/System/PgQueryTest.php index 2a8b9caaba03..6ef787a48b38 100644 --- a/Spanner/tests/System/PgQueryTest.php +++ b/Spanner/tests/System/PgQueryTest.php @@ -515,6 +515,36 @@ public function testBindJsonbParameterNull() $this->assertCount($currentCount + 1, iterator_to_array($res)); } + public function testBindPgOidParameter() + { + $db = self::$database; + + $res = $db->execute('SELECT $1', [ + 'parameters' => [ + 'p1' => 1, + ], + 'types' => [ + 'p1' => Database::TYPE_PG_OID + ] + ]); + $this->assertCount(1, iterator_to_array($res)); + } + + public function testBindPgOidParameterNull() + { + $db = self::$database; + + $res = $db->execute('SELECT $1', [ + 'parameters' => [ + 'p1' => null, + ], + 'types' => [ + 'p1' => Database::TYPE_PG_OID + ] + ]); + $this->assertCount(1, iterator_to_array($res)); + } + public function arrayTypesProvider() { return [ @@ -612,7 +642,9 @@ function (array $res) { return $res; } - ] + ], + // pg_oid + [[5,4,3,2,1]], ]; } @@ -657,6 +689,7 @@ public function arrayTypesEmptyProvider() [Database::TYPE_DATE], [Database::TYPE_PG_NUMERIC], [Database::TYPE_PG_JSONB], + [Database::TYPE_PG_OID], ]; } @@ -693,6 +726,7 @@ public function arrayTypesNullProvider() [Database::TYPE_DATE], [Database::TYPE_PG_NUMERIC], [Database::TYPE_PG_JSONB], + [Database::TYPE_PG_OID], ]; } diff --git a/Spanner/tests/Unit/ArrayTypeTest.php b/Spanner/tests/Unit/ArrayTypeTest.php index 91524972c0e7..d04b0f2d7fd2 100644 --- a/Spanner/tests/Unit/ArrayTypeTest.php +++ b/Spanner/tests/Unit/ArrayTypeTest.php @@ -46,6 +46,7 @@ public function typesProvider() // types (w/ typeAnnotation) [Database::TYPE_PG_NUMERIC], [Database::TYPE_PG_JSONB], + [Database::TYPE_PG_OID], ]; } diff --git a/Spanner/tests/Unit/SpannerClientTest.php b/Spanner/tests/Unit/SpannerClientTest.php index 3f93170d22f1..93435813c5d2 100644 --- a/Spanner/tests/Unit/SpannerClientTest.php +++ b/Spanner/tests/Unit/SpannerClientTest.php @@ -433,6 +433,12 @@ public function testPgJsonB() $this->assertInstanceOf(PgJsonb::class, $objVal); } + public function testPgOid() + { + $oidVal = $this->client->pgOid('123'); + $this->assertInstanceOf(PgOid::class, $oidVal); + } + public function testInt64() { $i64 = $this->client->int64('123'); diff --git a/Spanner/tests/Unit/ValueMapperTest.php b/Spanner/tests/Unit/ValueMapperTest.php index 40d19142d68c..a6ae23669d7c 100644 --- a/Spanner/tests/Unit/ValueMapperTest.php +++ b/Spanner/tests/Unit/ValueMapperTest.php @@ -158,6 +158,23 @@ public function testFormatParamsForExecuteSqlJsonB() $this->assertEquals(TypeAnnotationCode::PG_JSONB, $res['paramTypes']['json']['typeAnnotation']); } + public function testFormatParamsForExecuteSqlJsonB() + { + $val = '123'; + $params = [ + 'oid' => $val + ]; + $types = [ + 'oid' => Database::TYPE_PG_OID + ]; + + $res = $this->mapper->formatParamsForExecuteSql($params, $types); + + $this->assertEquals($val, $res['params']['oid']); + $this->assertEquals(TypeCode::INT64, $res['paramTypes']['oid']['code']); + $this->assertEquals(TypeAnnotationCode::PG_OID, $res['paramTypes']['oid']['typeAnnotation']); + } + public function testFormatParamsForExecuteSqlValueInterface() { $val = 'hello world'; @@ -1020,6 +1037,16 @@ public function testDecodeValuesJsonB() $this->assertEquals('{\"rating\":9,\"open\":true}', $res['rowName']); } + public function testDecodeValuesOid() + { + $res = $this->mapper->decodeValues( + $this->createField(Database::TYPE_PG_OID), + $this->createRow('123'), + Result::RETURN_ASSOCIATIVE + ); + $this->assertEquals('123', $res['rowName']); + } + public function testDecodeValuesAnonymousField() { $fields = [ From 35cef64e164241055ab2514a363963951c2ed149 Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 14 Nov 2023 13:08:53 +1100 Subject: [PATCH 3/6] fix(spanner): fix typo --- Spanner/src/ValueMapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spanner/src/ValueMapper.php b/Spanner/src/ValueMapper.php index a0372524dbd7..b4d92ddcd37a 100644 --- a/Spanner/src/ValueMapper.php +++ b/Spanner/src/ValueMapper.php @@ -90,7 +90,7 @@ class ValueMapper private static $typeCodes = [ self::TYPE_PG_NUMERIC => self::TYPE_NUMERIC, self::TYPE_PG_JSONB => self::TYPE_JSON, - self::Type_PG_OID => self::TYPE_INT64, + self::TYPE_PG_OID => self::TYPE_INT64, ]; /* From 8469349c78cf0b3ab165bd29f9fb85f8f31ef361 Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 14 Nov 2023 13:11:42 +1100 Subject: [PATCH 4/6] test(spanner): fix typo --- Spanner/tests/Unit/ValueMapperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spanner/tests/Unit/ValueMapperTest.php b/Spanner/tests/Unit/ValueMapperTest.php index a6ae23669d7c..85c1037b1021 100644 --- a/Spanner/tests/Unit/ValueMapperTest.php +++ b/Spanner/tests/Unit/ValueMapperTest.php @@ -158,7 +158,7 @@ public function testFormatParamsForExecuteSqlJsonB() $this->assertEquals(TypeAnnotationCode::PG_JSONB, $res['paramTypes']['json']['typeAnnotation']); } - public function testFormatParamsForExecuteSqlJsonB() + public function testFormatParamsForExecuteSqlOid() { $val = '123'; $params = [ From fb4374a2ba682bdf7a9c6b77419270c58c4ea6f7 Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 14 Nov 2023 13:22:38 +1100 Subject: [PATCH 5/6] test(spanner): add missing dependency --- Spanner/tests/Unit/SpannerClientTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Spanner/tests/Unit/SpannerClientTest.php b/Spanner/tests/Unit/SpannerClientTest.php index 93435813c5d2..beeb17033339 100644 --- a/Spanner/tests/Unit/SpannerClientTest.php +++ b/Spanner/tests/Unit/SpannerClientTest.php @@ -33,6 +33,7 @@ use Google\Cloud\Spanner\Instance; use Google\Cloud\Spanner\InstanceConfiguration; use Google\Cloud\Spanner\PgJsonb; +use Google\Cloud\Spanner\PgOid; use Google\Cloud\Spanner\KeyRange; use Google\Cloud\Spanner\KeySet; use Google\Cloud\Spanner\Numeric; From 7b27b839901f679f127f3b47f5133537c6c4fb0d Mon Sep 17 00:00:00 2001 From: larkee Date: Tue, 14 Nov 2023 13:37:36 +1100 Subject: [PATCH 6/6] fix(spanner): fix typo --- Spanner/src/SpannerClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Spanner/src/SpannerClient.php b/Spanner/src/SpannerClient.php index e9d48ca25b6b..ad258d5cadfb 100644 --- a/Spanner/src/SpannerClient.php +++ b/Spanner/src/SpannerClient.php @@ -835,7 +835,7 @@ public function pgJsonb($value) */ public function pgOid($value) { - return new pgOid($value); + return new PgOid($value); } /**