From f51997087035b2430d89916ff5462ac9d2b40dbd Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Thu, 19 Dec 2024 22:21:39 +0100 Subject: [PATCH] Npgsql: Use improved .NET multi-line strings 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. --- by-language/csharp-npgsql/DemoTypes.cs | 41 ++++++++++--------- .../csharp-npgsql/tests/DemoProgramTest.cs | 10 ++--- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/by-language/csharp-npgsql/DemoTypes.cs b/by-language/csharp-npgsql/DemoTypes.cs index 4c9f7546..6f2ad062 100644 --- a/by-language/csharp-npgsql/DemoTypes.cs +++ b/by-language/csharp-npgsql/DemoTypes.cs @@ -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")] @@ -66,7 +67,7 @@ public static async Task 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, @@ -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, @@ -113,8 +114,8 @@ INSERT INTO testdrive.example ( timestamp_tz, timestamp_notz, ip, - ""array"", - ""object"", + "array", + "object", geopoint, geoshape, float_vector @@ -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); @@ -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(){{"foo", "bar"}}); - cmd.Parameters.AddWithValue("object", @"{""foo"": ""bar""}"); + cmd.Parameters.AddWithValue("object", """{"foo": "bar"}"""); cmd.Parameters.AddWithValue("geopoint", new List{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 {1.1, 2.2, 3.3}); cmd.ExecuteNonQuery(); @@ -194,34 +195,34 @@ public static async Task 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{"foo", "bar"}); - cmd.Parameters.AddWithValue("object", @"{""foo"": ""bar""}"); + cmd.Parameters.AddWithValue("object", """{"foo": "bar"}"""); cmd.ExecuteNonQuery(); } diff --git a/by-language/csharp-npgsql/tests/DemoProgramTest.cs b/by-language/csharp-npgsql/tests/DemoProgramTest.cs index fc49e73e..c0bfa08c 100644 --- a/by-language/csharp-npgsql/tests/DemoProgramTest.cs +++ b/by-language/csharp-npgsql/tests/DemoProgramTest.cs @@ -116,7 +116,7 @@ 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{"foo", "bar"}, row["array"]); - Assert.Equal(@"{""foo"":""bar""}", row["object"]); + Assert.Equal("""{"foo":"bar"}""", row["object"]); // Geospatial types // TODO: Unlock native data types? @@ -124,7 +124,7 @@ public async Task TestAllTypesExample() // GEO_POINT is using a tuple format, GEO_SHAPE is using the GeoJSON format. // Assert.Equal(new List{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{1.1, 2.2, 3.3}).Select(d => (float) d).ToArray(), row["float_vector"]); @@ -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{"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(); @@ -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();