Skip to content

Commit

Permalink
Npgsql: Explore communicating and marshalling GeoJSON types
Browse files Browse the repository at this point in the history
Currently, this has to be conducted "manually".
  • Loading branch information
amotl committed Dec 21, 2024
1 parent 6770795 commit ba814ca
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 11 deletions.
29 changes: 24 additions & 5 deletions by-language/csharp-npgsql/DemoProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ await Parser.Default.ParseArguments<Options>(args)
{
var connString = $"Host={options.Host};Port={options.Port};SSL Mode={options.SslMode};" +
$"Username={options.Username};Password={options.Password};Database={options.Database}";
Console.WriteLine($"Connecting to {connString}\n");

var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString);
dataSourceBuilder.EnableDynamicJson();
await using var dataSource = dataSourceBuilder.Build();
await using var conn = dataSource.OpenConnection();
await using var conn = GetConnection(connString);

await DatabaseWorkloads.SystemQueryExample(conn);
await DatabaseWorkloads.BasicConversationExample(conn);
Expand All @@ -34,11 +30,34 @@ await Parser.Default.ParseArguments<Options>(args)
// await dwt.ArrayJsonDocumentExample();
await dwt.ObjectPocoExample();
await dwt.ArrayPocoExample();
await dwt.GeoJsonTypesExample();
conn.Close();
});

}

public static NpgsqlConnection GetConnection(string connString)
{
Console.WriteLine($"Connecting to database: {connString}\n");

// Enable JSON POCO mapping and PostGIS/GeoJSON Type Plugin.
// https://www.npgsql.org/doc/types/json.html
// https://www.npgsql.org/doc/types/geojson.html
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString);

// Enable JSON POCO mapping Plugin.
// https://www.npgsql.org/doc/types/json.html
dataSourceBuilder.EnableDynamicJson();

// Enable PostGIS/GeoJSON Type Plugin.
// https://www.npgsql.org/doc/types/geojson.html
// dataSourceBuilder.UseGeoJson();

var dataSource = dataSourceBuilder.Build();
var conn = dataSource.OpenConnection();
return conn;
}

public class Options
{
[Option('h', "host", Required = false, HelpText = "Host name to connect to", Default = "localhost")]
Expand Down
97 changes: 97 additions & 0 deletions by-language/csharp-npgsql/DemoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Data;
using System.Text.Json;
using System.Threading.Tasks;
using GeoJSON.Net.Geometry;
using Newtonsoft.Json;
using Npgsql;
using NpgsqlTypes;
Expand Down Expand Up @@ -351,6 +352,102 @@ public async Task<List<BasicPoco>> ArrayPocoExample()
}
}

public async Task InsertGeoJsonTyped()
{
/***
* Verify Npgsql PostGIS/GeoJSON Type Plugin with CrateDB.
* https://www.npgsql.org/doc/types/geojson.html
*
* TODO: Does not work yet, because CrateDB communicates GEO_SHAPE as string?
* The error message is:
*
* System.NotSupportedException : The NpgsqlDbType 'Geometry' isn't present in your
* database. You may need to install an extension or upgrade to a newer version.
*/
Console.WriteLine("Running InsertGeo");

// Insert single data point.
await using (var cmd = new NpgsqlCommand("""
INSERT INTO testdrive.example (
"geoshape"
) VALUES (
@geoshape
);
""", conn))
{
var point = new Point(new Position(85.43, 66.23));
cmd.Parameters.AddWithValue("geoshape", NpgsqlDbType.Geometry, point);
cmd.ExecuteNonQuery();
}

// Flush data.
await RefreshTable();
}

public async Task InsertGeoJsonString()
{
/***
* Communicate GeoJSON types as strings, marshall from/to GeoJSON types manually.
*/
Console.WriteLine("Running InsertGeoRaw");

// Insert single data point.
await using (var cmd = new NpgsqlCommand("""
INSERT INTO testdrive.example (
"geoshape"
) VALUES (
@geoshape
);
""", conn))
{
var point = new Point(new Position(85.43, 66.23));
var poly = new Polygon([
new LineString([
new Position(longitude: 5.0, latitude: 5.0),
new Position(longitude: 5.0, latitude: 10.0),
new Position(longitude: 10.0, latitude: 10.0),
new Position(longitude: 10.0, latitude: 5.0),
new Position(longitude: 5.0, latitude: 5.0),
])
]);
// TODO: Can GEO_SHAPE types be directly marshalled to a .NET GeoJSON type?
// Currently, `InsertGeoJsonTyped` does not work yet.
cmd.Parameters.AddWithValue("geoshape", NpgsqlDbType.Json, JsonConvert.SerializeObject(point));
cmd.ExecuteNonQuery();

cmd.Parameters.Clear();

cmd.Parameters.AddWithValue("geoshape", NpgsqlDbType.Json, JsonConvert.SerializeObject(poly));
cmd.ExecuteNonQuery();
}

// Flush data.
await RefreshTable();

}

public async Task<Point> GeoJsonTypesExample()
{
Console.WriteLine("Running GeoJsonTypesExample");

// Provision data.
await CreateTable();
// await InsertGeoJsonTyped();
await InsertGeoJsonString();

// Query back data.
await using (var cmd = new NpgsqlCommand("SELECT * FROM testdrive.example", conn))
await using (var reader = cmd.ExecuteReader())
{
reader.Read();
// TODO: Can GEO_SHAPE types be directly marshalled to a .NET GeoJSON type?
// Currently, `InsertGeoJsonTyped` does not work yet.
var obj = reader.GetFieldValue<JsonDocument>("geoshape");
var geoJsonObject = JsonConvert.DeserializeObject<Point>(obj.RootElement.ToString());
return (Point) geoJsonObject;

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 8.0.x Npgsql: 8.0.6 CrateDB: nightly on ubuntu-22.04

Converting null literal or possible null value to non-nullable type.

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 8.0.x Npgsql: 8.0.6 CrateDB: nightly on ubuntu-22.04

Possible null reference return.

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 8.0.x Npgsql: 9.0.2 CrateDB: nightly on ubuntu-22.04

Converting null literal or possible null value to non-nullable type.

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 8.0.x Npgsql: 9.0.2 CrateDB: nightly on ubuntu-22.04

Possible null reference return.

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 9.0.x Npgsql: 8.0.6 CrateDB: nightly on ubuntu-22.04

Converting null literal or possible null value to non-nullable type.

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 9.0.x Npgsql: 8.0.6 CrateDB: nightly on ubuntu-22.04

Possible null reference return.

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 9.0.x Npgsql: 9.0.2 CrateDB: nightly on ubuntu-22.04

Converting null literal or possible null value to non-nullable type.

Check warning on line 447 in by-language/csharp-npgsql/DemoTypes.cs

View workflow job for this annotation

GitHub Actions / .NET: 9.0.x Npgsql: 9.0.2 CrateDB: nightly on ubuntu-22.04

Possible null reference return.
}
}

}

}
1 change: 1 addition & 0 deletions by-language/csharp-npgsql/demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GeoJSON.Net" Version="1.4.1" />
<PackageReference Include="Npgsql" Version="9.0.2" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
Expand Down
24 changes: 18 additions & 6 deletions by-language/csharp-npgsql/tests/DemoProgramTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using GeoJSON.Net.Geometry;
using Npgsql;
using NpgsqlTypes;
using Xunit;
Expand All @@ -22,12 +23,7 @@ public DatabaseFixture()
{
CRATEDB_DSN = $"Host=localhost;Port=5432;Username=crate;Password=;Database=testdrive";
}
Console.WriteLine($"Connecting to {CRATEDB_DSN}\n");

var dataSourceBuilder = new NpgsqlDataSourceBuilder(CRATEDB_DSN);
dataSourceBuilder.EnableDynamicJson();
using var dataSource = dataSourceBuilder.Build();
Db = dataSource.OpenConnection();
Db = DemoProgram.GetConnection(CRATEDB_DSN);
}

public void Dispose()
Expand Down Expand Up @@ -216,5 +212,21 @@ public async Task TestArrayPocoExample()

}

[Fact]
public async Task TestGeoJsonTypesExample()
{
var conn = fixture.Db;

// Provision data.
var task = new DatabaseWorkloadsTypes(conn).GeoJsonTypesExample();
var point = await task.WaitAsync(TimeSpan.FromSeconds(0.5));

// Validate the outcome.
var coords = new Point(new Position(85.43, 66.23)).Coordinates;
Assert.Equal(coords.Latitude, point.Coordinates.Latitude);
Assert.Equal(coords.Longitude, point.Coordinates.Longitude);

}

}
}

0 comments on commit ba814ca

Please sign in to comment.