Skip to content

Commit

Permalink
Npgsql: Use improved .NET multi-line strings
Browse files Browse the repository at this point in the history
Newer .NET/C# language versions borrow from Python for defining
multi-line strings, using `"""`. This is much better for inlining
JSON documents, because it doesn't need additional quoting.
  • Loading branch information
amotl committed Dec 19, 2024
1 parent 4c7b18b commit f519970
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 25 deletions.
41 changes: 21 additions & 20 deletions by-language/csharp-npgsql/DemoTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public class AllTypesRecord
public double? Double { get; set; }
[JsonProperty("decimal")]
public decimal? Decimal { get; set; }
// TODO: Review the handling of the `BIT` type here.
//[JsonProperty("bit")]
//public BitArray Bit { get; set; }
[JsonProperty("bool")]
Expand Down Expand Up @@ -66,7 +67,7 @@ public static async Task<DataTable> AllTypesExample(NpgsqlConnection conn)
cmd.ExecuteNonQuery();
}

await using (var cmd = new NpgsqlCommand(@"
await using (var cmd = new NpgsqlCommand("""
CREATE TABLE testdrive.example (
-- Numeric types
null_integer INT,
Expand All @@ -84,21 +85,21 @@ char CHARACTER(5),
timestamp_notz TIMESTAMP WITHOUT TIME ZONE,
ip IP,
-- Container types
""array"" ARRAY(STRING),
""object"" OBJECT(DYNAMIC),
"array" ARRAY(STRING),
"object" OBJECT(DYNAMIC),
-- Geospatial types
geopoint GEO_POINT,
geoshape GEO_SHAPE,
-- Vector type
""float_vector"" FLOAT_VECTOR(3)
float_vector FLOAT_VECTOR(3)
);
", conn))
""", conn))
{
cmd.ExecuteNonQuery();
}

// Insert single data point.
await using (var cmd = new NpgsqlCommand(@"
await using (var cmd = new NpgsqlCommand("""
INSERT INTO testdrive.example (
null_integer,
integer,
Expand All @@ -113,8 +114,8 @@ INSERT INTO testdrive.example (
timestamp_tz,
timestamp_notz,
ip,
""array"",
""object"",
"array",
"object",
geopoint,
geoshape,
float_vector
Expand All @@ -138,9 +139,8 @@ INSERT INTO testdrive.example (
@geoshape,
@float_vector
);
", conn))
""", conn))
{
Console.WriteLine(cmd);
cmd.Parameters.AddWithValue("null_integer", DBNull.Value);
cmd.Parameters.AddWithValue("integer", 42);
cmd.Parameters.AddWithValue("bigint", 42);
Expand All @@ -158,8 +158,9 @@ INSERT INTO testdrive.example (
// FIXME: System.NotSupportedException: Cannot resolve 'hstore' to a fully qualified datatype name. The datatype was not found in the current database info.
// https://github.com/crate/zk/issues/26
// cmd.Parameters.AddWithValue("object", new Dictionary<string, string>(){{"foo", "bar"}});
cmd.Parameters.AddWithValue("object", @"{""foo"": ""bar""}");
cmd.Parameters.AddWithValue("object", """{"foo": "bar"}""");
cmd.Parameters.AddWithValue("geopoint", new List<double>{85.43, 66.23});
// TODO: Check if `GEO_SHAPE` types can be represented by real .NET or Npgsql data types.
cmd.Parameters.AddWithValue("geoshape", "POLYGON ((5 5, 10 5, 10 10, 5 10, 5 5))");
cmd.Parameters.AddWithValue("float_vector", new List<double> {1.1, 2.2, 3.3});
cmd.ExecuteNonQuery();
Expand Down Expand Up @@ -194,34 +195,34 @@ public static async Task<DataTable> ContainerTypesExample(NpgsqlConnection conn)
cmd.ExecuteNonQuery();
}

await using (var cmd = new NpgsqlCommand(@"
await using (var cmd = new NpgsqlCommand("""
CREATE TABLE testdrive.container (
-- Container types
""array"" ARRAY(STRING),
""object"" OBJECT(DYNAMIC)
"array" ARRAY(STRING),
"object" OBJECT(DYNAMIC)
);
", conn))
""", conn))
{
cmd.ExecuteNonQuery();
}

// Insert single data point.
await using (var cmd = new NpgsqlCommand(@"
await using (var cmd = new NpgsqlCommand("""
INSERT INTO testdrive.container (
""array"",
""object""
"array",
"object"
) VALUES (
@array,
@object
);
", conn))
""", conn))
{
Console.WriteLine(cmd);
// FIXME: While doing conversations with ARRAY types works natively,
// it doesn't work for OBJECT types.
// Yet, they can be submitted as STRING in JSON format.
cmd.Parameters.AddWithValue("array", new List<string>{"foo", "bar"});
cmd.Parameters.AddWithValue("object", @"{""foo"": ""bar""}");
cmd.Parameters.AddWithValue("object", """{"foo": "bar"}""");
cmd.ExecuteNonQuery();
}

Expand Down
10 changes: 5 additions & 5 deletions by-language/csharp-npgsql/tests/DemoProgramTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,15 @@ public async Task TestAllTypesExample()
// it doesn't work for OBJECT types.
// Yet, they can be submitted as STRING in JSON format.
Assert.Equal(new List<string>{"foo", "bar"}, row["array"]);
Assert.Equal(@"{""foo"":""bar""}", row["object"]);
Assert.Equal("""{"foo":"bar"}""", row["object"]);

// Geospatial types
// TODO: Unlock native data types?
// GEO_POINT and GEO_SHAPE types can be marshalled back and forth using STRING.
// GEO_POINT is using a tuple format, GEO_SHAPE is using the GeoJSON format.
// Assert.Equal(new List<double>{85.43, 66.23}, row["geopoint"]); // TODO
Assert.Equal("(85.42999997735023,66.22999997343868)", row["geopoint"].ToString()); // FIXME
Assert.Equal(@"{""coordinates"":[[[5.0,5.0],[5.0,10.0],[10.0,10.0],[10.0,5.0],[5.0,5.0]]],""type"":""Polygon""}", row["geoshape"]);
Assert.Equal("""{"coordinates":[[[5.0,5.0],[5.0,10.0],[10.0,10.0],[10.0,5.0],[5.0,5.0]]],"type":"Polygon"}""", row["geoshape"]);

// Vector type
Assert.Equal((new List<double>{1.1, 2.2, 3.3}).Select(d => (float) d).ToArray(), row["float_vector"]);
Expand All @@ -145,10 +145,10 @@ public async Task TestContainerTypesExample()
// it doesn't work for OBJECT types.
// Yet, they can be submitted as STRING in JSON format.
Assert.Equal(new List<string>{"foo", "bar"}, row["array"]);
Assert.Equal(@"{""foo"":""bar""}", row["object"]);
Assert.Equal("""{"foo":"bar"}""", row["object"]);

// Run a special query indexing into ARRAY types.
await using (var cmd = new NpgsqlCommand(@"SELECT ""array[2]"" AS foo FROM testdrive.container", conn))
await using (var cmd = new NpgsqlCommand("""SELECT "array[2]" AS foo FROM testdrive.container""", conn))
await using (var reader = cmd.ExecuteReader())
{
var dataTable = new DataTable();
Expand All @@ -157,7 +157,7 @@ public async Task TestContainerTypesExample()
}

// Run a special query indexing into OBJECT types.
await using (var cmd = new NpgsqlCommand(@"SELECT ""object['foo']"" AS foo FROM testdrive.container", conn))
await using (var cmd = new NpgsqlCommand("""SELECT "object['foo']" AS foo FROM testdrive.container""", conn))
await using (var reader = cmd.ExecuteReader())
{
var dataTable = new DataTable();
Expand Down

0 comments on commit f519970

Please sign in to comment.