Skip to content

Commit

Permalink
First draft of PostgreSQL Dialact samples
Browse files Browse the repository at this point in the history
  • Loading branch information
Rishabh-V committed Mar 18, 2022
1 parent a09747b commit d33aa55
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 68 deletions.
45 changes: 45 additions & 0 deletions spanner/api/Spanner.Samples.Tests/CastDatatypesAsyncPostgreTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2022 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Threading.Tasks;
using Xunit;

[Collection(nameof(SpannerFixture))]
public class CastDatatypesAsyncPostgreTest
{
private readonly SpannerFixture _spannerFixture;

private readonly CastDatatypesAsyncPostgreSample _sample;

public CastDatatypesAsyncPostgreTest(SpannerFixture spannerFixture)
{
_spannerFixture = spannerFixture;
_sample = new CastDatatypesAsyncPostgreSample();
}

[Fact]
public async Task TestCastDatatypesAsyncPostgre()
{
// Act.
var result = await _sample.CastDatatypesAsyncPostgre(_spannerFixture.ProjectId, _spannerFixture.InstanceId, _spannerFixture.PostgreSqlDatabaseId);
//Assert.
Assert.Contains("String : 1", result);
Assert.Contains("Integer : 2", result);
Assert.Contains("Decimal : 3", result);
Assert.Contains("Bytes : 34", result);
Assert.Contains("Float : 5.00", result);
Assert.Contains("Bool : True", result);
Assert.Contains("Timestamp : 2021-11-03 09:35:01Z", result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2022 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Threading.Tasks;
using Xunit;

[Collection(nameof(SpannerFixture))]
public class ConnectToDatabaseAsyncPostgreTest
{
private readonly SpannerFixture _spannerFixture;

private readonly ConnectToDatabaseAsyncPostgreSample _sample;

public ConnectToDatabaseAsyncPostgreTest(SpannerFixture spannerFixture)
{
_spannerFixture = spannerFixture;
_sample = new ConnectToDatabaseAsyncPostgreSample();
}

[Fact]
public async Task TestConnectToDatabaseAsyncPostgre()
{
// Act.
var result = await _sample.ConnectToDatabaseAsyncPostgre(_spannerFixture.ProjectId, _spannerFixture.InstanceId, _spannerFixture.PostgreSqlDatabaseId);

//Assert.
Assert.Equal($"Hello from Spanner PostgreSQL!", result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,26 @@
using Xunit;

[Collection(nameof(SpannerFixture))]
public class CreatePostgreSqlDatabaseAsyncTest
public class CreateDatabaseAsyncPostgreTest
{
private readonly SpannerFixture _spannerFixture;

private readonly CreatePostgreSqlDatabaseAsyncSample _sample;
private readonly CreateDatabaseAsyncPostgreSample _sample;

public CreatePostgreSqlDatabaseAsyncTest(SpannerFixture spannerFixture)
public CreateDatabaseAsyncPostgreTest(SpannerFixture spannerFixture)
{
_spannerFixture = spannerFixture;
_sample = new CreatePostgreSqlDatabaseAsyncSample();
_sample = new CreateDatabaseAsyncPostgreSample();
}

[Fact]
public async Task TestCreatePostgreSqlDatabaseAsync()
public async Task TestCreateDatabaseAsyncPostgre()
{
// Arrange.
var databaseId = $"my-db-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
var database = await _sample.CreatePostgreSqlDatabaseAsync(_spannerFixture.ProjectId, _spannerFixture.InstanceId, databaseId);
// Act.
var database = await _sample.CreateDatabaseAsyncPostgre(_spannerFixture.ProjectId, _spannerFixture.InstanceId, databaseId);
// Assert.
Assert.Equal(DatabaseDialect.Postgresql, database.DatabaseDialect);
}
}
54 changes: 53 additions & 1 deletion spanner/api/Spanner.Samples.Tests/SpannerFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class SpannerFixture : IAsyncLifetime, ICollectionFixture<SpannerFixture>
// Allow environment variables to override the default instance and database names.
public string InstanceId { get; } = Environment.GetEnvironmentVariable("TEST_SPANNER_INSTANCE") ?? "my-instance";
public string DatabaseId { get; } = Environment.GetEnvironmentVariable("TEST_SPANNER_DATABASE") ?? $"my-db-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
public string PostgreSqlDatabaseId { get; } = Environment.GetEnvironmentVariable("TEST_SPANNER_POSTGRESQL_DATABASE") ?? $"my-db-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
public string BackupDatabaseId { get; } = "my-test-database";
public string BackupId { get; } = "my-test-database-backup";
public string ToBeCancelledBackupId { get; } = $"my-backup-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
Expand Down Expand Up @@ -78,7 +79,7 @@ public async Task InitializeAsync()

bool.TryParse(Environment.GetEnvironmentVariable("RUN_SPANNER_CMEK_BACKUP_SAMPLES_TESTS"), out var runCmekBackupSampleTests);
RunCmekBackupSampleTests = runCmekBackupSampleTests;

ConnectionString = $"Data Source=projects/{ProjectId}/instances/{InstanceId}/databases/{DatabaseId}";
// Don't need to cleanup stale Backups and Databases when instance is new.
var isExistingInstance = await InitializeInstanceAsync();
Expand All @@ -91,6 +92,7 @@ public async Task InitializeAsync()
await DeleteStaleInstancesAsync();
await InitializeDatabaseAsync();
await InitializeBackupAsync();
await InitializePostgreSqlDatabaseAsync();

// Create encryption key for creating an encrypted database and optionally backing up and restoring an encrypted database.
await InitializeEncryptionKeys();
Expand All @@ -100,6 +102,49 @@ public async Task InitializeAsync()
}
}

public async Task<List<string>> ListTablesAsync(string databaseId)
{
string connectionString = $"Data Source=projects/{ProjectId}/instances/{InstanceId}/databases/{databaseId}";
using var connection = new SpannerConnection(connectionString);
await connection.OpenAsync();

var command = connection.CreateSelectCommand("SELECT table_name FROM INFORMATION_SCHEMA.tables WHERE table_schema='public' OR table_schema=''");

var tableList = new List<string>();
using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
tableList.Add(reader.GetFieldValue<string>("table_name"));
}

return tableList;
}

public async Task CreateEmptyPostgreSqlDatabaseAsync(string databaseId)
{
DatabaseAdminClient databaseAdminClient = await new DatabaseAdminClientBuilder
{
QuotaProject = ProjectId // QuotaProject needs to be set for now while feature is in Pre-GA. May not be needed in final sample.
}.BuildAsync();

// Create the CreateDatabaseRequest with PostgreSQL dialect and execute it.
// There cannot be Extra DDL statements while creating PostgreSQL.
var createDatabaseRequest = new CreateDatabaseRequest
{
ParentAsInstanceName = InstanceName.FromProjectInstance(ProjectId, InstanceId),
CreateStatement = $"CREATE DATABASE \"{databaseId}\"",
DatabaseDialect = DatabaseDialect.Postgresql
};

var createOperation = await databaseAdminClient.CreateDatabaseAsync(createDatabaseRequest);

var completedResponse = await createOperation.PollUntilCompletedAsync();
if (completedResponse.IsFaulted)
{
throw completedResponse.Exception;
}
}

public Task DisposeAsync()
{
DeleteInstance(InstanceIdWithProcessingUnits);
Expand Down Expand Up @@ -388,6 +433,13 @@ private async Task InitializeBackupAsync()
}
}

private async Task InitializePostgreSqlDatabaseAsync()
{
// If the database has not been initialized, retry.
PostgreSqlCreateDatabaseAsyncSample createDatabaseAsyncSample = new PostgreSqlCreateDatabaseAsyncSample();
await createDatabaseAsyncSample.PostgreSqlCreateDatabaseAsync(ProjectId, InstanceId, PostgreSqlDatabaseId);
}

public async Task CreateVenuesTableAndInsertDataAsync(string databaseId)
{
// Create connection to Cloud Spanner.
Expand Down
55 changes: 55 additions & 0 deletions spanner/api/Spanner.Samples/CastDatatypesAsyncPostgre.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2022 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START spanner_postgresql_cast_data_type]
using Google.Cloud.Spanner.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class CastDatatypesAsyncPostgreSample
{
public async Task<string> CastDatatypesAsyncPostgre(string projectId, string instanceId, string databaseId)
{
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";

using var connection = new SpannerConnection(connectionString);
await connection.OpenAsync();

// The `::` cast operator can be used to cast from one data type to another.
var commandText = "SELECT 1::varchar as str, '2'::int as int, 3::decimal as dec, '4'::bytea as bytes, "
+ "5::float as float, 'true'::bool as bool, '2021-11-03T09:35:01UTC'::timestamptz as timestamp";
var command = connection.CreateSelectCommand(commandText);

using var reader = await command.ExecuteReaderAsync();
var resultBuilder = new StringBuilder();
while (await reader.ReadAsync())
{
resultBuilder.AppendLine($"String : {reader.GetFieldValue<string>("str")}");
resultBuilder.AppendLine($"Integer : {reader.GetFieldValue<int>("int")}");
resultBuilder.AppendLine($"Decimal : {reader.GetFieldValue<decimal>("dec")}");
resultBuilder.AppendLine($"Bytes : {BitConverter.ToString(reader.GetFieldValue<byte[]>("bytes"))}");
resultBuilder.AppendLine($"Float : {reader.GetFieldValue<float>("float"):F}");
resultBuilder.AppendLine($"Bool : {reader.GetFieldValue<bool>("bool")}");
resultBuilder.AppendLine($"Timestamp : {reader.GetFieldValue<DateTime>("timestamp"):u}");
}

string result = resultBuilder.ToString();
Console.WriteLine(result);
return result;
}
}
// [END spanner_postgresql_cast_data_type]
42 changes: 42 additions & 0 deletions spanner/api/Spanner.Samples/ConnectToDatabaseAsyncPostgre.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2022 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// [START spanner_connect_postgresql_database]
using Google.Cloud.Spanner.Data;
using System;
using System.Threading.Tasks;

public class ConnectToDatabaseAsyncPostgreSample
{
public async Task<string> ConnectToDatabaseAsyncPostgre(string projectId, string instanceId, string databaseId)
{
string connectionString = $"Data Source=projects/{projectId}/instances/{instanceId}/databases/{databaseId}";

using var connection = new SpannerConnection(connectionString);
await connection.OpenAsync();

var command = connection.CreateSelectCommand("SELECT 'Hello from Spanner PostgreSQL!'");

using var reader = await command.ExecuteReaderAsync();
string result = default;
while (await reader.ReadAsync())
{
result = $"{reader.GetString(0)}";
}

Console.WriteLine(result);
return result;
}
}
// [END spanner_connect_postgresql_database]
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
using System;
using System.Threading.Tasks;

public class CreatePostgreSqlDatabaseAsyncSample
public class CreateDatabaseAsyncPostgreSample
{
public async Task<Database> CreatePostgreSqlDatabaseAsync(string projectId, string instanceId, string databaseId)
public async Task<Database> CreateDatabaseAsyncPostgre(string projectId, string instanceId, string databaseId)
{
DatabaseAdminClient databaseAdminClient = await new DatabaseAdminClientBuilder
{
QuotaProject = projectId // QuotaProject needs to be set for now while feature is in Pre-GA. May not be needed in final sample.
// QuotaProject needs to be set for now while feature is in Pre-GA. May not be needed in final sample.
QuotaProject = projectId
}.BuildAsync();

// Create the CreateDatabaseRequest with PostgreSQL dialect and execute it.
Expand All @@ -44,7 +45,7 @@ public async Task<Database> CreatePostgreSqlDatabaseAsync(string projectId, stri
var completedResponse = await createOperation.PollUntilCompletedAsync();
if (completedResponse.IsFaulted)
{
Console.WriteLine($"Error while creating database: {completedResponse.Exception}");
Console.WriteLine($"Error while creating PostgreSQL database: {completedResponse.Exception}");
throw completedResponse.Exception;
}

Expand Down Expand Up @@ -85,7 +86,7 @@ AlbumTitle text
throw updateResponse.Exception;
}

// Return the created database.
// Return the database.
var database = await databaseAdminClient.GetDatabaseAsync(databaseName);
return database;
}
Expand Down
4 changes: 2 additions & 2 deletions spanner/api/Spanner.Samples/Spanner.Samples.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Google.Cloud.Spanner.Data" Version="3.13.0" />
<PackageReference Include="Google.Cloud.Spanner.Data" Version="3.14.0" />
</ItemGroup>

</Project>
Loading

0 comments on commit d33aa55

Please sign in to comment.