From 383bf8e55c5f250495696b5753bcd037be899d20 Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Thu, 2 Feb 2023 16:26:18 -0800 Subject: [PATCH 1/7] throw custom error for unsupported types --- samples/samples-csharp/Common/Product.cs | 7 +++ .../AddProductUnsupportedTypes.cs | 23 +++++++++ .../AddProductUnsupportedTypes/function.json | 27 ++++++++++ .../AddProductUnsupportedTypes/run.ps1 | 17 +++++++ src/SqlAsyncCollector.cs | 24 ++++++++- test-outofproc/AddProductUnsupportedTypes.cs | 28 +++++++++++ test-outofproc/Product.cs | 7 +++ test/Common/ProductUnsupportedTypes.cs | 12 +++++ .../Tables/ProductsUnsupportedTypes.sql | 4 ++ .../SqlOutputBindingIntegrationTests.cs | 21 ++++++++ .../test-csharp/AddProductUnsupportedTypes.cs | 23 +++++++++ .../function/AddProductUnsupportedTypes.java | 49 +++++++++++++++++++ .../Common/ProductUnsupportedTypes.java | 40 +++++++++++++++ .../AddProductUnsupportedTypes/function.json | 27 ++++++++++ .../AddProductUnsupportedTypes/index.js | 13 +++++ .../AddProductUnsupportedTypes/function.json | 27 ++++++++++ .../AddProductUnsupportedTypes/run.ps1 | 17 +++++++ .../AddProductUnsupportedTypes/__init__.py | 20 ++++++++ .../AddProductUnsupportedTypes/function.json | 28 +++++++++++ 19 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs create mode 100644 samples/samples-powershell/AddProductUnsupportedTypes/function.json create mode 100644 samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 create mode 100644 test-outofproc/AddProductUnsupportedTypes.cs create mode 100644 test/Common/ProductUnsupportedTypes.cs create mode 100644 test/Database/Tables/ProductsUnsupportedTypes.sql create mode 100644 test/Integration/test-csharp/AddProductUnsupportedTypes.cs create mode 100644 test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java create mode 100644 test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java create mode 100644 test/Integration/test-js/AddProductUnsupportedTypes/function.json create mode 100644 test/Integration/test-js/AddProductUnsupportedTypes/index.js create mode 100644 test/Integration/test-powershell/AddProductUnsupportedTypes/function.json create mode 100644 test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 create mode 100644 test/Integration/test-python/AddProductUnsupportedTypes/__init__.py create mode 100644 test/Integration/test-python/AddProductUnsupportedTypes/function.json diff --git a/samples/samples-csharp/Common/Product.cs b/samples/samples-csharp/Common/Product.cs index cc56e53d5..3ea2afdb1 100644 --- a/samples/samples-csharp/Common/Product.cs +++ b/samples/samples-csharp/Common/Product.cs @@ -52,4 +52,11 @@ public class ProductWithDefaultPK public int Cost { get; set; } } + + public class ProductUnsupportedTypes + { + public int ProductId { get; set; } + + public string Text { get; set; } + } } \ No newline at end of file diff --git a/samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs b/samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs new file mode 100644 index 000000000..32e29b50e --- /dev/null +++ b/samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common; +namespace Microsoft.Azure.WebJobs.Extensions.Sql.Samples.OutputBindingSamples +{ + public static class AddProductUnsupportedTypes + { + // This output binding should throw an exception because the target table has a column of type + // TEXT, which is not supported. + [FunctionName("AddProductUnsupportedTypes")] + public static IActionResult Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] + [FromBody] ProductUnsupportedTypes prod, + [Sql("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] out ProductUnsupportedTypes product) + { + product = prod; + return new CreatedResult($"/api/addproduct-unsupportedtypes", product); + } + } +} diff --git a/samples/samples-powershell/AddProductUnsupportedTypes/function.json b/samples/samples-powershell/AddProductUnsupportedTypes/function.json new file mode 100644 index 000000000..97d7511ec --- /dev/null +++ b/samples/samples-powershell/AddProductUnsupportedTypes/function.json @@ -0,0 +1,27 @@ +{ + "bindings": [ + { + "authLevel": "function", + "name": "Request", + "direction": "in", + "type": "httpTrigger", + "methods": [ + "post" + ], + "route": "addproduct-unsupportedtypes" + }, + { + "name": "response", + "type": "http", + "direction": "out" + }, + { + "name": "product", + "type": "sql", + "direction": "out", + "commandText": "[dbo].[ProductsUnsupportedTypes]", + "connectionStringSetting": "SqlConnectionString" + } + ], + "disabled": false +} \ No newline at end of file diff --git a/samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 b/samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 new file mode 100644 index 000000000..f48d3b6d6 --- /dev/null +++ b/samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 @@ -0,0 +1,17 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. + +using namespace System.Net + +# This output binding should throw an exception because the target table has a column of type +# TEXT, which is not supported. +param($Request, $TriggerMetadata) + +$req_body = $Request.Body + +Push-OutputBinding -Name product -Value $req_body + +Push-OutputBinding -Name response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $req_body +}) \ No newline at end of file diff --git a/src/SqlAsyncCollector.cs b/src/SqlAsyncCollector.cs index 91bfac5b6..b7cdf1d69 100644 --- a/src/SqlAsyncCollector.cs +++ b/src/SqlAsyncCollector.cs @@ -57,6 +57,7 @@ public enum QueryType /// A user-defined POCO that represents a row of the user's table internal class SqlAsyncCollector : IAsyncCollector, IDisposable { + private static readonly string[] UnsupportedTypes = { "NTEXT", "TEXT", "IMAGE" }; private const string RowDataParameter = "@rowData"; private const string ColumnName = "COLUMN_NAME"; private const string ColumnDefinition = "COLUMN_DEFINITION"; @@ -231,7 +232,16 @@ private async Task UpsertRowsAsync(IList rows, SqlAttribute attribute, IConfi throw ex; } - IEnumerable bracketedColumnNamesFromItem = GetColumnNamesFromItem(rows.First()) + IEnumerable columnNamesFromItem = GetColumnNamesFromItem(rows.First()); + IEnumerable unsupportedColumns = columnNamesFromItem.Where(prop => IsUnsupportedType(prop, tableInfo.Columns)); + if (unsupportedColumns.Any()) + { + string message = $"The type(s) of the following column(s) are not supported: {string.Join(", ", unsupportedColumns.ToArray())}."; + var ex = new InvalidOperationException(message); + throw ex; + } + + IEnumerable bracketedColumnNamesFromItem = columnNamesFromItem .Where(prop => !tableInfo.PrimaryKeys.Any(k => k.IsIdentity && string.Equals(k.Name, prop, StringComparison.Ordinal))) // Skip any identity columns, those should never be updated .Select(prop => prop.AsBracketQuotedString()); var table = new SqlObject(fullTableName); @@ -292,6 +302,18 @@ private async Task UpsertRowsAsync(IList rows, SqlAttribute attribute, IConfi } } + private static bool IsUnsupportedType(string property, IDictionary columns) + { + foreach (string unsupportedType in UnsupportedTypes) + { + if (columns[property].StartsWith(unsupportedType, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + return false; + } + /// /// Checks if any properties in T do not exist as columns in the table /// to upsert to and returns the extra property names in a List. diff --git a/test-outofproc/AddProductUnsupportedTypes.cs b/test-outofproc/AddProductUnsupportedTypes.cs new file mode 100644 index 000000000..f4a06211f --- /dev/null +++ b/test-outofproc/AddProductUnsupportedTypes.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Azure.Functions.Worker.Extensions.Sql; +using DotnetIsolatedTests.Common; +using System.Threading.Tasks; + +namespace DotnetIsolatedTests +{ + public static class AddProductUnsupportedTypes + { + /// + /// This output binding should fail since the target table has a column of type + /// TEXT which is not supported. + /// + [Function("AddProductUnsupportedTypes")] + [SqlOutput("dbo.ProductUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] + public static async Task RunAsync( + [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] + HttpRequestData req) + { + ProductUnsupportedTypes product = await req.ReadFromJsonAsync(); + return product; + } + } +} diff --git a/test-outofproc/Product.cs b/test-outofproc/Product.cs index d797ff20e..a4b803288 100644 --- a/test-outofproc/Product.cs +++ b/test-outofproc/Product.cs @@ -188,4 +188,11 @@ public class ProductMissingColumns public string Name { get; set; } } + + public class ProductUnsupportedTypes + { + public int ProductId { get; set; } + + public string Text { get; set; } + } } \ No newline at end of file diff --git a/test/Common/ProductUnsupportedTypes.cs b/test/Common/ProductUnsupportedTypes.cs new file mode 100644 index 000000000..cb0380399 --- /dev/null +++ b/test/Common/ProductUnsupportedTypes.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common +{ + public class ProductUnsupportedTypes + { + public int ProductId { get; set; } + + public string Text { get; set; } + } +} \ No newline at end of file diff --git a/test/Database/Tables/ProductsUnsupportedTypes.sql b/test/Database/Tables/ProductsUnsupportedTypes.sql new file mode 100644 index 000000000..9d6350a2e --- /dev/null +++ b/test/Database/Tables/ProductsUnsupportedTypes.sql @@ -0,0 +1,4 @@ +CREATE TABLE [ProductsUnsupportedTypes] ( + [ProductId] [int] NOT NULL PRIMARY KEY, + [Text] [text] +) \ No newline at end of file diff --git a/test/Integration/SqlOutputBindingIntegrationTests.cs b/test/Integration/SqlOutputBindingIntegrationTests.cs index 212839310..d54474492 100644 --- a/test/Integration/SqlOutputBindingIntegrationTests.cs +++ b/test/Integration/SqlOutputBindingIntegrationTests.cs @@ -472,5 +472,26 @@ public void AddProductWithDifferentPropertiesTest(SupportedLanguages lang) // Verify result Assert.Equal("test2", this.ExecuteScalar($"select Name from Products where ProductId=0")); } + + /// + /// Tests that an error is thrown when the upserted item contains a unsupported column type. + /// + [Theory] + [SqlInlineData()] + public void AddProductWithUnsupportedTypes(SupportedLanguages lang) + { + this.StartFunctionHost(nameof(AddProductWithUnsupportedTypes), lang); + + var query = new Dictionary() + { + { "ProductId", 0 }, + { "Text", "test" } + }; + + Assert.Equal(0, this.ExecuteScalar("SELECT COUNT(*) FROM dbo.ProductsUnsupportedTypes")); + Assert.Throws(() => this.SendOutputPostRequest(nameof(AddProductWithUnsupportedTypes), JsonConvert.SerializeObject(query)).Wait()); + // Nothing should have been inserted + Assert.Equal(0, this.ExecuteScalar("SELECT COUNT(*) FROM dbo.ProductsUnsupportedTypes")); + } } } diff --git a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs new file mode 100644 index 000000000..6edfd893b --- /dev/null +++ b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common; +namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration +{ + public static class AddProductUnsupportedTypes + { + // This output binding should throw an exception because the target table has a column of type + // TEXT, which is not supported. + [FunctionName("AddProductUnsupportedTypes")] + public static IActionResult Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] + [FromBody] ProductUnsupportedTypes prod, + [Sql("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] out ProductUnsupportedTypes product) + { + product = prod; + return new CreatedResult($"/api/addproduct-unsupportedtypes", product); + } + } +} diff --git a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java new file mode 100644 index 000000000..4c3ceb130 --- /dev/null +++ b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + */ + +package com.function; + +import com.microsoft.azure.functions.HttpMethod; +import com.microsoft.azure.functions.HttpRequestMessage; +import com.microsoft.azure.functions.HttpResponseMessage; +import com.microsoft.azure.functions.HttpStatus; +import com.microsoft.azure.functions.OutputBinding; +import com.microsoft.azure.functions.annotation.AuthorizationLevel; +import com.microsoft.azure.functions.annotation.FunctionName; +import com.microsoft.azure.functions.annotation.HttpTrigger; +import com.microsoft.azure.functions.sql.annotation.SQLOutput; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.function.Common.ProductUnsupportedTypes; + +import java.util.Optional; + + +public class AddProductUnsupportedTypes { + // This output binding should throw an exception because the target table has a column of type + // TEXT, which is not supported. + @FunctionName("AddProductUnsupportedTypes") + public HttpResponseMessage run( + @HttpTrigger( + name = "req", + methods = {HttpMethod.POST}, + authLevel = AuthorizationLevel.ANONYMOUS, + route = "addproduct-unsupportedtypes") + HttpRequestMessage> request, + @SQLOutput( + name = "product", + commandText = "dbo.ProductsUnsupportedTypes", + connectionStringSetting = "SqlConnectionString") + OutputBinding product) throws JsonMappingException, JsonProcessingException { + + String json = request.getBody().get(); + ObjectMapper mapper = new ObjectMapper(); + ProductUnsupportedTypes p = mapper.readValue(json, ProductUnsupportedTypes.class); + product.setValue(p); + return request.createResponseBuilder(HttpStatus.OK).header("Content-Type", "application/json").body(product).build(); + } +} diff --git a/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java new file mode 100644 index 000000000..ac570080e --- /dev/null +++ b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + */ + +package com.function.Common; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ProductUnsupportedTypes { + @JsonProperty("ProductId") + private int ProductId; + @JsonProperty("Text") + private String Text; + + public ProductUnsupportedTypes() { + } + + public ProductUnsupportedTypes(int productId, String text) { + ProductId = productId; + Text = text; + } + + public int getProductId() { + return ProductId; + } + + public void setProductId(int productId) { + ProductId = productId; + } + + public String getText() { + return Text; + } + + public void setText(String text) { + Text = text; + } +} \ No newline at end of file diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/function.json b/test/Integration/test-js/AddProductUnsupportedTypes/function.json new file mode 100644 index 000000000..570bac155 --- /dev/null +++ b/test/Integration/test-js/AddProductUnsupportedTypes/function.json @@ -0,0 +1,27 @@ +{ + "bindings": [ + { + "authLevel": "function", + "name": "req", + "direction": "in", + "type": "httpTrigger", + "methods": [ + "post" + ], + "route": "addproduct-unsupportedtypes" + }, + { + "name": "$return", + "type": "http", + "direction": "out" + }, + { + "name": "product", + "type": "sql", + "direction": "out", + "commandText": "[dbo].[ProductsUnsupportedTypes]", + "connectionStringSetting": "SqlConnectionString" + } + ], + "disabled": false +} \ No newline at end of file diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/index.js b/test/Integration/test-js/AddProductUnsupportedTypes/index.js new file mode 100644 index 000000000..ca8f349b6 --- /dev/null +++ b/test/Integration/test-js/AddProductUnsupportedTypes/index.js @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +// This output binding should throw an exception because the target table has a column of type +// TEXT, which is not supported. +module.exports = async function (context, req) { + context.bindings.product = req.body; + + return { + status: 201, + body: req.body + }; +} \ No newline at end of file diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json b/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json new file mode 100644 index 000000000..97d7511ec --- /dev/null +++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json @@ -0,0 +1,27 @@ +{ + "bindings": [ + { + "authLevel": "function", + "name": "Request", + "direction": "in", + "type": "httpTrigger", + "methods": [ + "post" + ], + "route": "addproduct-unsupportedtypes" + }, + { + "name": "response", + "type": "http", + "direction": "out" + }, + { + "name": "product", + "type": "sql", + "direction": "out", + "commandText": "[dbo].[ProductsUnsupportedTypes]", + "connectionStringSetting": "SqlConnectionString" + } + ], + "disabled": false +} \ No newline at end of file diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 new file mode 100644 index 000000000..f48d3b6d6 --- /dev/null +++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 @@ -0,0 +1,17 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. + +using namespace System.Net + +# This output binding should throw an exception because the target table has a column of type +# TEXT, which is not supported. +param($Request, $TriggerMetadata) + +$req_body = $Request.Body + +Push-OutputBinding -Name product -Value $req_body + +Push-OutputBinding -Name response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $req_body +}) \ No newline at end of file diff --git a/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py new file mode 100644 index 000000000..030513921 --- /dev/null +++ b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import json +import azure.functions as func + +def main(req: func.HttpRequest, product: func.Out[func.SqlRow]) -> func.HttpResponse: + """This output binding should throw an exception because the target table has a column of type + TEXT, which is not supported. + """ + + body = json.loads(req.get_body()) + row = func.SqlRow.from_dict(body) + product.set(row) + + return func.HttpResponse( + body=req.get_body(), + status_code=201, + mimetype="application/json" + ) diff --git a/test/Integration/test-python/AddProductUnsupportedTypes/function.json b/test/Integration/test-python/AddProductUnsupportedTypes/function.json new file mode 100644 index 000000000..431df314e --- /dev/null +++ b/test/Integration/test-python/AddProductUnsupportedTypes/function.json @@ -0,0 +1,28 @@ +{ + "scriptFile": "__init__.py", + "bindings": [ + { + "authLevel": "function", + "name": "req", + "direction": "in", + "type": "httpTrigger", + "methods": [ + "post" + ], + "route": "addproduct-unsupportedtypes" + }, + { + "name": "$return", + "type": "http", + "direction": "out" + }, + { + "name": "product", + "type": "sql", + "direction": "out", + "commandText": "[dbo].[ProductsUnsupportedTypes]", + "connectionStringSetting": "SqlConnectionString" + } + ], + "disabled": false +} From 394946857b4900e4372b266c4b417dc18c528f2a Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Fri, 3 Feb 2023 11:41:03 -0800 Subject: [PATCH 2/7] add ntext & image to test + cleanup --- samples/samples-csharp/Common/Product.cs | 7 ----- .../AddProductUnsupportedTypes.cs | 23 ---------------- .../AddProductUnsupportedTypes/function.json | 27 ------------------- .../AddProductUnsupportedTypes/run.ps1 | 17 ------------ src/SqlAsyncCollector.cs | 3 +-- test-outofproc/AddProductUnsupportedTypes.cs | 5 ++-- test/Common/ProductUnsupportedTypes.cs | 4 +++ .../Tables/ProductsUnsupportedTypes.sql | 4 ++- .../SqlOutputBindingIntegrationTests.cs | 21 ++++++++++----- .../test-csharp/AddProductUnsupportedTypes.cs | 3 +-- .../function/AddProductUnsupportedTypes.java | 3 +-- .../Common/ProductUnsupportedTypes.java | 24 ++++++++++++++++- .../AddProductUnsupportedTypes/index.js | 3 +-- .../AddProductUnsupportedTypes/run.ps1 | 3 +-- .../AddProductUnsupportedTypes/__init__.py | 3 +-- 15 files changed, 52 insertions(+), 98 deletions(-) delete mode 100644 samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs delete mode 100644 samples/samples-powershell/AddProductUnsupportedTypes/function.json delete mode 100644 samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 diff --git a/samples/samples-csharp/Common/Product.cs b/samples/samples-csharp/Common/Product.cs index 3ea2afdb1..cc56e53d5 100644 --- a/samples/samples-csharp/Common/Product.cs +++ b/samples/samples-csharp/Common/Product.cs @@ -52,11 +52,4 @@ public class ProductWithDefaultPK public int Cost { get; set; } } - - public class ProductUnsupportedTypes - { - public int ProductId { get; set; } - - public string Text { get; set; } - } } \ No newline at end of file diff --git a/samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs b/samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs deleted file mode 100644 index 32e29b50e..000000000 --- a/samples/samples-csharp/OutputBindingSamples/AddProductUnsupportedTypes.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using Microsoft.AspNetCore.Mvc; -using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common; -namespace Microsoft.Azure.WebJobs.Extensions.Sql.Samples.OutputBindingSamples -{ - public static class AddProductUnsupportedTypes - { - // This output binding should throw an exception because the target table has a column of type - // TEXT, which is not supported. - [FunctionName("AddProductUnsupportedTypes")] - public static IActionResult Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] - [FromBody] ProductUnsupportedTypes prod, - [Sql("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] out ProductUnsupportedTypes product) - { - product = prod; - return new CreatedResult($"/api/addproduct-unsupportedtypes", product); - } - } -} diff --git a/samples/samples-powershell/AddProductUnsupportedTypes/function.json b/samples/samples-powershell/AddProductUnsupportedTypes/function.json deleted file mode 100644 index 97d7511ec..000000000 --- a/samples/samples-powershell/AddProductUnsupportedTypes/function.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "bindings": [ - { - "authLevel": "function", - "name": "Request", - "direction": "in", - "type": "httpTrigger", - "methods": [ - "post" - ], - "route": "addproduct-unsupportedtypes" - }, - { - "name": "response", - "type": "http", - "direction": "out" - }, - { - "name": "product", - "type": "sql", - "direction": "out", - "commandText": "[dbo].[ProductsUnsupportedTypes]", - "connectionStringSetting": "SqlConnectionString" - } - ], - "disabled": false -} \ No newline at end of file diff --git a/samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 b/samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 deleted file mode 100644 index f48d3b6d6..000000000 --- a/samples/samples-powershell/AddProductUnsupportedTypes/run.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. - -using namespace System.Net - -# This output binding should throw an exception because the target table has a column of type -# TEXT, which is not supported. -param($Request, $TriggerMetadata) - -$req_body = $Request.Body - -Push-OutputBinding -Name product -Value $req_body - -Push-OutputBinding -Name response -Value ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $req_body -}) \ No newline at end of file diff --git a/src/SqlAsyncCollector.cs b/src/SqlAsyncCollector.cs index b7cdf1d69..2714d306f 100644 --- a/src/SqlAsyncCollector.cs +++ b/src/SqlAsyncCollector.cs @@ -237,8 +237,7 @@ private async Task UpsertRowsAsync(IList rows, SqlAttribute attribute, IConfi if (unsupportedColumns.Any()) { string message = $"The type(s) of the following column(s) are not supported: {string.Join(", ", unsupportedColumns.ToArray())}."; - var ex = new InvalidOperationException(message); - throw ex; + throw new InvalidOperationException(message); } IEnumerable bracketedColumnNamesFromItem = columnNamesFromItem diff --git a/test-outofproc/AddProductUnsupportedTypes.cs b/test-outofproc/AddProductUnsupportedTypes.cs index f4a06211f..971fd41d4 100644 --- a/test-outofproc/AddProductUnsupportedTypes.cs +++ b/test-outofproc/AddProductUnsupportedTypes.cs @@ -12,11 +12,10 @@ namespace DotnetIsolatedTests public static class AddProductUnsupportedTypes { /// - /// This output binding should fail since the target table has a column of type - /// TEXT which is not supported. + /// This output binding should fail since the target table has unsupported column types. /// [Function("AddProductUnsupportedTypes")] - [SqlOutput("dbo.ProductUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] + [SqlOutput("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] public static async Task RunAsync( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] HttpRequestData req) diff --git a/test/Common/ProductUnsupportedTypes.cs b/test/Common/ProductUnsupportedTypes.cs index cb0380399..242c3e6e0 100644 --- a/test/Common/ProductUnsupportedTypes.cs +++ b/test/Common/ProductUnsupportedTypes.cs @@ -8,5 +8,9 @@ public class ProductUnsupportedTypes public int ProductId { get; set; } public string Text { get; set; } + + public string Ntext { get; set; } + + public byte[] Image { get; set; } } } \ No newline at end of file diff --git a/test/Database/Tables/ProductsUnsupportedTypes.sql b/test/Database/Tables/ProductsUnsupportedTypes.sql index 9d6350a2e..85e555ae4 100644 --- a/test/Database/Tables/ProductsUnsupportedTypes.sql +++ b/test/Database/Tables/ProductsUnsupportedTypes.sql @@ -1,4 +1,6 @@ CREATE TABLE [ProductsUnsupportedTypes] ( [ProductId] [int] NOT NULL PRIMARY KEY, - [Text] [text] + [Text] [text], + [Ntext] [ntext], + [Image] [image] ) \ No newline at end of file diff --git a/test/Integration/SqlOutputBindingIntegrationTests.cs b/test/Integration/SqlOutputBindingIntegrationTests.cs index d54474492..d144ba52d 100644 --- a/test/Integration/SqlOutputBindingIntegrationTests.cs +++ b/test/Integration/SqlOutputBindingIntegrationTests.cs @@ -478,20 +478,27 @@ public void AddProductWithDifferentPropertiesTest(SupportedLanguages lang) /// [Theory] [SqlInlineData()] - public void AddProductWithUnsupportedTypes(SupportedLanguages lang) + public async Task AddProductUnsupportedTypesTest(SupportedLanguages lang) { - this.StartFunctionHost(nameof(AddProductWithUnsupportedTypes), lang); + var foundExpectedMessageSource = new TaskCompletionSource(); + this.StartFunctionHost(nameof(AddProductUnsupportedTypes), lang, true, (object sender, DataReceivedEventArgs e) => + { + if (e.Data.Contains("The type(s) of the following column(s) are not supported: Text, Ntext, Image.")) + { + foundExpectedMessageSource.SetResult(true); + } + }); var query = new Dictionary() { { "ProductId", 0 }, - { "Text", "test" } + { "Text", "test" }, + { "Ntext", "test" }, + { "Image", new byte[] { 1, 2, 3 } } }; - Assert.Equal(0, this.ExecuteScalar("SELECT COUNT(*) FROM dbo.ProductsUnsupportedTypes")); - Assert.Throws(() => this.SendOutputPostRequest(nameof(AddProductWithUnsupportedTypes), JsonConvert.SerializeObject(query)).Wait()); - // Nothing should have been inserted - Assert.Equal(0, this.ExecuteScalar("SELECT COUNT(*) FROM dbo.ProductsUnsupportedTypes")); + Assert.Throws(() => this.SendOutputPostRequest("addproduct-unsupportedtypes", JsonConvert.SerializeObject(query)).Wait()); + await foundExpectedMessageSource.Task.TimeoutAfter(TimeSpan.FromMilliseconds(2000), $"Timed out waiting for expected error message"); } } } diff --git a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs index 6edfd893b..1dd79f7da 100644 --- a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs +++ b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs @@ -8,8 +8,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration { public static class AddProductUnsupportedTypes { - // This output binding should throw an exception because the target table has a column of type - // TEXT, which is not supported. + // This output binding should throw an exception because the target table has unsupported column types. [FunctionName("AddProductUnsupportedTypes")] public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] diff --git a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java index 4c3ceb130..b4aa573b7 100644 --- a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java +++ b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java @@ -24,8 +24,7 @@ public class AddProductUnsupportedTypes { - // This output binding should throw an exception because the target table has a column of type - // TEXT, which is not supported. + // This output binding should throw an exception because the target table has unsupported column types. @FunctionName("AddProductUnsupportedTypes") public HttpResponseMessage run( @HttpTrigger( diff --git a/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java index ac570080e..541df85d1 100644 --- a/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java +++ b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java @@ -13,13 +13,19 @@ public class ProductUnsupportedTypes { private int ProductId; @JsonProperty("Text") private String Text; + @JsonProperty("Ntext") + private String Ntext; + @JsonProperty("Image") + private String Image; public ProductUnsupportedTypes() { } - public ProductUnsupportedTypes(int productId, String text) { + public ProductUnsupportedTypes(int productId, String text, String ntext, String image) { ProductId = productId; Text = text; + Ntext = ntext; + Image = image; } public int getProductId() { @@ -37,4 +43,20 @@ public String getText() { public void setText(String text) { Text = text; } + + public String getNtext() { + return Ntext; + } + + public void setNtext(String ntext) { + Ntext = ntext; + } + + public String getImage() { + return Image; + } + + public void setImage(String image) { + Image = image; + } } \ No newline at end of file diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/index.js b/test/Integration/test-js/AddProductUnsupportedTypes/index.js index ca8f349b6..f191edb01 100644 --- a/test/Integration/test-js/AddProductUnsupportedTypes/index.js +++ b/test/Integration/test-js/AddProductUnsupportedTypes/index.js @@ -1,8 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. -// This output binding should throw an exception because the target table has a column of type -// TEXT, which is not supported. +// This output binding should throw an exception because the target table has unsupported column types. module.exports = async function (context, req) { context.bindings.product = req.body; diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 index f48d3b6d6..1630f716b 100644 --- a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 +++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 @@ -3,8 +3,7 @@ using namespace System.Net -# This output binding should throw an exception because the target table has a column of type -# TEXT, which is not supported. +# This output binding should throw an exception because the target table has unsupported column types. param($Request, $TriggerMetadata) $req_body = $Request.Body diff --git a/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py index 030513921..a067da0ce 100644 --- a/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py +++ b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py @@ -5,8 +5,7 @@ import azure.functions as func def main(req: func.HttpRequest, product: func.Out[func.SqlRow]) -> func.HttpResponse: - """This output binding should throw an exception because the target table has a column of type - TEXT, which is not supported. + """This output binding should throw an exception because the target table has unsupported column types. """ body = json.loads(req.get_body()) From ebc79e41d6bf6feacf4260c5e1b8a3a6a17cf576 Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Mon, 6 Feb 2023 09:51:23 -0800 Subject: [PATCH 3/7] fix powershell ordering --- test-outofproc/AddProductUnsupportedTypes.cs | 17 +++++++++++------ test-outofproc/GlobalSuppressions.cs | 3 ++- test-outofproc/Product.cs | 4 ++++ test/GlobalSuppressions.cs | 3 ++- .../SqlOutputBindingIntegrationTests.cs | 11 ++--------- .../test-csharp/AddProductUnsupportedTypes.cs | 13 ++++++++++--- .../function/AddProductUnsupportedTypes.java | 11 +++++++---- .../AddProductUnsupportedTypes/function.json | 2 +- .../test-js/AddProductUnsupportedTypes/index.js | 7 ++++++- .../AddProductUnsupportedTypes/function.json | 2 +- .../AddProductUnsupportedTypes/run.ps1 | 9 +++++++-- .../AddProductUnsupportedTypes/__init__.py | 9 +++++++-- .../AddProductUnsupportedTypes/function.json | 2 +- .../Common/productunsupportedtypes.py | 12 ++++++++++++ 14 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 test/Integration/test-python/Common/productunsupportedtypes.py diff --git a/test-outofproc/AddProductUnsupportedTypes.cs b/test-outofproc/AddProductUnsupportedTypes.cs index 971fd41d4..8e79ed1a7 100644 --- a/test-outofproc/AddProductUnsupportedTypes.cs +++ b/test-outofproc/AddProductUnsupportedTypes.cs @@ -2,10 +2,9 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using Microsoft.Azure.Functions.Worker; -using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Azure.Functions.Worker.Extensions.Sql; using DotnetIsolatedTests.Common; -using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; namespace DotnetIsolatedTests { @@ -16,11 +15,17 @@ public static class AddProductUnsupportedTypes /// [Function("AddProductUnsupportedTypes")] [SqlOutput("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] - public static async Task RunAsync( - [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] - HttpRequestData req) + public static ProductUnsupportedTypes Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "addproduct-unsupportedtypes")] + HttpRequest req) { - ProductUnsupportedTypes product = await req.ReadFromJsonAsync(); + var product = new ProductUnsupportedTypes + { + ProductId = 1, + Text = "test", + Ntext = "test", + Image = new byte[] { 1, 2, 3 } + }; return product; } } diff --git a/test-outofproc/GlobalSuppressions.cs b/test-outofproc/GlobalSuppressions.cs index c83dffa97..98e12cbf1 100644 --- a/test-outofproc/GlobalSuppressions.cs +++ b/test-outofproc/GlobalSuppressions.cs @@ -14,4 +14,5 @@ [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductMissingColumnsExceptionFunction.Run(Microsoft.AspNetCore.Http.HttpRequest)~DotnetIsolatedTests.Common.ProductMissingColumns")] [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductsNoPartialUpsert.Run(Microsoft.AspNetCore.Http.HttpRequest)~System.Collections.Generic.List{DotnetIsolatedTests.Common.Product}")] [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.GetProductsColumnTypesSerialization.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{DotnetIsolatedTests.Common.ProductColumnTypes})~System.Collections.Generic.IEnumerable{DotnetIsolatedTests.Common.ProductColumnTypes}")] -[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductIncorrectCasing.Run(Microsoft.Azure.Functions.Worker.Http.HttpRequestData)~DotnetIsolatedTests.Common.ProductIncorrectCasing")] \ No newline at end of file +[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductIncorrectCasing.Run(Microsoft.Azure.Functions.Worker.Http.HttpRequestData)~DotnetIsolatedTests.Common.ProductIncorrectCasing")] +[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductUnsupportedTypes.Run(Microsoft.AspNetCore.Http.HttpRequest)~DotnetIsolatedTests.Common.ProductUnsupportedTypes")] \ No newline at end of file diff --git a/test-outofproc/Product.cs b/test-outofproc/Product.cs index a4b803288..0caa2c02d 100644 --- a/test-outofproc/Product.cs +++ b/test-outofproc/Product.cs @@ -194,5 +194,9 @@ public class ProductUnsupportedTypes public int ProductId { get; set; } public string Text { get; set; } + + public string Ntext { get; set; } + + public byte[] Image { get; set; } } } \ No newline at end of file diff --git a/test/GlobalSuppressions.cs b/test/GlobalSuppressions.cs index 72e1de225..0664243d7 100644 --- a/test/GlobalSuppressions.cs +++ b/test/GlobalSuppressions.cs @@ -19,4 +19,5 @@ [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.UnsupportedColumnTypesTrigger.Run(System.Collections.Generic.IReadOnlyList{Microsoft.Azure.WebJobs.Extensions.Sql.SqlChange{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.Product})")] [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProductsColumnTypesSerializationAsyncEnumerable.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IAsyncEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductColumnTypes},Microsoft.Extensions.Logging.ILogger)~System.Threading.Tasks.Task{Microsoft.AspNetCore.Mvc.IActionResult}")] [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProductsColumnTypesSerialization.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductColumnTypes},Microsoft.Extensions.Logging.ILogger)~Microsoft.AspNetCore.Mvc.IActionResult")] -[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.AddProductIncorrectCasing.Run(Microsoft.AspNetCore.Http.HttpRequest,Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductIncorrectCasing@)~Microsoft.AspNetCore.Mvc.IActionResult")] \ No newline at end of file +[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.AddProductIncorrectCasing.Run(Microsoft.AspNetCore.Http.HttpRequest,Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductIncorrectCasing@)~Microsoft.AspNetCore.Mvc.IActionResult")] +[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.AddProductUnsupportedTypes.Run(Microsoft.AspNetCore.Http.HttpRequest,Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductUnsupportedTypes@)~Microsoft.AspNetCore.Mvc.IActionResult")] \ No newline at end of file diff --git a/test/Integration/SqlOutputBindingIntegrationTests.cs b/test/Integration/SqlOutputBindingIntegrationTests.cs index d144ba52d..d54507606 100644 --- a/test/Integration/SqlOutputBindingIntegrationTests.cs +++ b/test/Integration/SqlOutputBindingIntegrationTests.cs @@ -478,6 +478,7 @@ public void AddProductWithDifferentPropertiesTest(SupportedLanguages lang) /// [Theory] [SqlInlineData()] + [UnsupportedLanguages(SupportedLanguages.OutOfProc)] public async Task AddProductUnsupportedTypesTest(SupportedLanguages lang) { var foundExpectedMessageSource = new TaskCompletionSource(); @@ -489,15 +490,7 @@ public async Task AddProductUnsupportedTypesTest(SupportedLanguages lang) } }); - var query = new Dictionary() - { - { "ProductId", 0 }, - { "Text", "test" }, - { "Ntext", "test" }, - { "Image", new byte[] { 1, 2, 3 } } - }; - - Assert.Throws(() => this.SendOutputPostRequest("addproduct-unsupportedtypes", JsonConvert.SerializeObject(query)).Wait()); + Assert.Throws(() => this.SendOutputGetRequest("addproduct-unsupportedtypes").Wait()); await foundExpectedMessageSource.Task.TimeoutAfter(TimeSpan.FromMilliseconds(2000), $"Timed out waiting for expected error message"); } } diff --git a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs index 1dd79f7da..d3ee06016 100644 --- a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs +++ b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common; @@ -11,11 +12,17 @@ public static class AddProductUnsupportedTypes // This output binding should throw an exception because the target table has unsupported column types. [FunctionName("AddProductUnsupportedTypes")] public static IActionResult Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "addproduct-unsupportedtypes")] - [FromBody] ProductUnsupportedTypes prod, + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "addproduct-unsupportedtypes")] + HttpRequest req, [Sql("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] out ProductUnsupportedTypes product) { - product = prod; + product = new ProductUnsupportedTypes() + { + ProductId = 1, + Text = "test", + Ntext = "test", + Image = new byte[] { 1, 2, 3 } + }; return new CreatedResult($"/api/addproduct-unsupportedtypes", product); } } diff --git a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java index b4aa573b7..493f09fbb 100644 --- a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java +++ b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java @@ -29,7 +29,7 @@ public class AddProductUnsupportedTypes { public HttpResponseMessage run( @HttpTrigger( name = "req", - methods = {HttpMethod.POST}, + methods = {HttpMethod.GET}, authLevel = AuthorizationLevel.ANONYMOUS, route = "addproduct-unsupportedtypes") HttpRequestMessage> request, @@ -39,9 +39,12 @@ public HttpResponseMessage run( connectionStringSetting = "SqlConnectionString") OutputBinding product) throws JsonMappingException, JsonProcessingException { - String json = request.getBody().get(); - ObjectMapper mapper = new ObjectMapper(); - ProductUnsupportedTypes p = mapper.readValue(json, ProductUnsupportedTypes.class); + ProductUnsupportedTypes p = new ProductUnsupportedTypes( + 0, + "test", + "test", + "dGVzdA==" + ); product.setValue(p); return request.createResponseBuilder(HttpStatus.OK).header("Content-Type", "application/json").body(product).build(); } diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/function.json b/test/Integration/test-js/AddProductUnsupportedTypes/function.json index 570bac155..e9f3de84a 100644 --- a/test/Integration/test-js/AddProductUnsupportedTypes/function.json +++ b/test/Integration/test-js/AddProductUnsupportedTypes/function.json @@ -6,7 +6,7 @@ "direction": "in", "type": "httpTrigger", "methods": [ - "post" + "get" ], "route": "addproduct-unsupportedtypes" }, diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/index.js b/test/Integration/test-js/AddProductUnsupportedTypes/index.js index f191edb01..3337b7cdb 100644 --- a/test/Integration/test-js/AddProductUnsupportedTypes/index.js +++ b/test/Integration/test-js/AddProductUnsupportedTypes/index.js @@ -3,7 +3,12 @@ // This output binding should throw an exception because the target table has unsupported column types. module.exports = async function (context, req) { - context.bindings.product = req.body; + context.bindings.product = { + ProductId: 0, + Text: "test", + Ntext: "test", + Image: "dGVzdA==" + } return { status: 201, diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json b/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json index 97d7511ec..741b973ad 100644 --- a/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json +++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json @@ -6,7 +6,7 @@ "direction": "in", "type": "httpTrigger", "methods": [ - "post" + "get" ], "route": "addproduct-unsupportedtypes" }, diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 index 1630f716b..a2a069e82 100644 --- a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 +++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 @@ -4,9 +4,14 @@ using namespace System.Net # This output binding should throw an exception because the target table has unsupported column types. -param($Request, $TriggerMetadata) +param($Request) -$req_body = $Request.Body +$req_body = [ordered]@{ + ProductId=0; + Text="test"; + Ntext="test"; + Image="dGVzdA=="; +} Push-OutputBinding -Name product -Value $req_body diff --git a/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py index a067da0ce..3f3a382eb 100644 --- a/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py +++ b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py @@ -3,13 +3,18 @@ import json import azure.functions as func +from Common.productunsupportedtypes import ProductUnsupportedTypes def main(req: func.HttpRequest, product: func.Out[func.SqlRow]) -> func.HttpResponse: """This output binding should throw an exception because the target table has unsupported column types. """ - body = json.loads(req.get_body()) - row = func.SqlRow.from_dict(body) + row = func.SqlRow(ProductUnsupportedTypes( + 0, + "test", + "test", + "dGVzdA==" + )) product.set(row) return func.HttpResponse( diff --git a/test/Integration/test-python/AddProductUnsupportedTypes/function.json b/test/Integration/test-python/AddProductUnsupportedTypes/function.json index 431df314e..1a3280294 100644 --- a/test/Integration/test-python/AddProductUnsupportedTypes/function.json +++ b/test/Integration/test-python/AddProductUnsupportedTypes/function.json @@ -7,7 +7,7 @@ "direction": "in", "type": "httpTrigger", "methods": [ - "post" + "get" ], "route": "addproduct-unsupportedtypes" }, diff --git a/test/Integration/test-python/Common/productunsupportedtypes.py b/test/Integration/test-python/Common/productunsupportedtypes.py new file mode 100644 index 000000000..cb349fd2d --- /dev/null +++ b/test/Integration/test-python/Common/productunsupportedtypes.py @@ -0,0 +1,12 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import collections + +class ProductUnsupportedTypes(collections.UserDict): + def __init__(self, productId, text, ntext, image): + super().__init__() + self['ProductId'] = productId + self['Text'] = text + self['Ntext'] = ntext + self['Image'] = image \ No newline at end of file From 99e61550e0c2876d30199b332e7e2362ce3d99cb Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Wed, 8 Feb 2023 07:56:16 -0800 Subject: [PATCH 4/7] Update src/SqlAsyncCollector.cs Co-authored-by: Charles Gagnon --- src/SqlAsyncCollector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SqlAsyncCollector.cs b/src/SqlAsyncCollector.cs index 2714d306f..c36994be8 100644 --- a/src/SqlAsyncCollector.cs +++ b/src/SqlAsyncCollector.cs @@ -236,7 +236,7 @@ private async Task UpsertRowsAsync(IList rows, SqlAttribute attribute, IConfi IEnumerable unsupportedColumns = columnNamesFromItem.Where(prop => IsUnsupportedType(prop, tableInfo.Columns)); if (unsupportedColumns.Any()) { - string message = $"The type(s) of the following column(s) are not supported: {string.Join(", ", unsupportedColumns.ToArray())}."; + string message = $"The type(s) of the following column(s) are not supported: {string.Join(", ", unsupportedColumns.ToArray())}. See https://github.com/Azure/azure-functions-sql-extension#output-bindings for more details."; throw new InvalidOperationException(message); } From 69ea651592e04cab583f7fd26a34374c000be8f3 Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Wed, 8 Feb 2023 09:08:08 -0800 Subject: [PATCH 5/7] update column names --- test-outofproc/AddProductUnsupportedTypes.cs | 6 +-- test-outofproc/Product.cs | 6 +-- test/Common/ProductUnsupportedTypes.cs | 6 +-- .../Tables/ProductsUnsupportedTypes.sql | 6 +-- .../SqlOutputBindingIntegrationTests.cs | 2 +- .../test-csharp/AddProductUnsupportedTypes.cs | 6 +-- .../function/AddProductUnsupportedTypes.java | 5 +-- .../Common/ProductUnsupportedTypes.java | 44 +++++++++---------- .../AddProductUnsupportedTypes/index.js | 6 +-- .../AddProductUnsupportedTypes/run.ps1 | 6 +-- .../Common/productunsupportedtypes.py | 8 ++-- 11 files changed, 49 insertions(+), 52 deletions(-) diff --git a/test-outofproc/AddProductUnsupportedTypes.cs b/test-outofproc/AddProductUnsupportedTypes.cs index 8e79ed1a7..5001e9f1a 100644 --- a/test-outofproc/AddProductUnsupportedTypes.cs +++ b/test-outofproc/AddProductUnsupportedTypes.cs @@ -22,9 +22,9 @@ public static ProductUnsupportedTypes Run( var product = new ProductUnsupportedTypes { ProductId = 1, - Text = "test", - Ntext = "test", - Image = new byte[] { 1, 2, 3 } + TextCol = "test", + NtextCol = "test", + ImageCol = new byte[] { 1, 2, 3 } }; return product; } diff --git a/test-outofproc/Product.cs b/test-outofproc/Product.cs index 0caa2c02d..789950ab3 100644 --- a/test-outofproc/Product.cs +++ b/test-outofproc/Product.cs @@ -193,10 +193,10 @@ public class ProductUnsupportedTypes { public int ProductId { get; set; } - public string Text { get; set; } + public string TextCol { get; set; } - public string Ntext { get; set; } + public string NtextCol { get; set; } - public byte[] Image { get; set; } + public byte[] ImageCol { get; set; } } } \ No newline at end of file diff --git a/test/Common/ProductUnsupportedTypes.cs b/test/Common/ProductUnsupportedTypes.cs index 242c3e6e0..c5fb39a5d 100644 --- a/test/Common/ProductUnsupportedTypes.cs +++ b/test/Common/ProductUnsupportedTypes.cs @@ -7,10 +7,10 @@ public class ProductUnsupportedTypes { public int ProductId { get; set; } - public string Text { get; set; } + public string TextCol { get; set; } - public string Ntext { get; set; } + public string NtextCol { get; set; } - public byte[] Image { get; set; } + public byte[] ImageCol { get; set; } } } \ No newline at end of file diff --git a/test/Database/Tables/ProductsUnsupportedTypes.sql b/test/Database/Tables/ProductsUnsupportedTypes.sql index 85e555ae4..8ce9b011c 100644 --- a/test/Database/Tables/ProductsUnsupportedTypes.sql +++ b/test/Database/Tables/ProductsUnsupportedTypes.sql @@ -1,6 +1,6 @@ CREATE TABLE [ProductsUnsupportedTypes] ( [ProductId] [int] NOT NULL PRIMARY KEY, - [Text] [text], - [Ntext] [ntext], - [Image] [image] + [TextCol] [text], + [NtextCol] [ntext], + [ImageCol] [image] ) \ No newline at end of file diff --git a/test/Integration/SqlOutputBindingIntegrationTests.cs b/test/Integration/SqlOutputBindingIntegrationTests.cs index d54507606..94a3d2f26 100644 --- a/test/Integration/SqlOutputBindingIntegrationTests.cs +++ b/test/Integration/SqlOutputBindingIntegrationTests.cs @@ -484,7 +484,7 @@ public async Task AddProductUnsupportedTypesTest(SupportedLanguages lang) var foundExpectedMessageSource = new TaskCompletionSource(); this.StartFunctionHost(nameof(AddProductUnsupportedTypes), lang, true, (object sender, DataReceivedEventArgs e) => { - if (e.Data.Contains("The type(s) of the following column(s) are not supported: Text, Ntext, Image.")) + if (e.Data.Contains("The type(s) of the following column(s) are not supported: TextCol, NtextCol, ImageCol. See https://github.com/Azure/azure-functions-sql-extension#output-bindings for more details.")) { foundExpectedMessageSource.SetResult(true); } diff --git a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs index d3ee06016..dc14674d6 100644 --- a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs +++ b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs @@ -19,9 +19,9 @@ public static IActionResult Run( product = new ProductUnsupportedTypes() { ProductId = 1, - Text = "test", - Ntext = "test", - Image = new byte[] { 1, 2, 3 } + TextCol = "test", + NtextCol = "test", + ImageCol = new byte[] { 1, 2, 3 } }; return new CreatedResult($"/api/addproduct-unsupportedtypes", product); } diff --git a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java index 493f09fbb..3be3e389d 100644 --- a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java +++ b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java @@ -15,9 +15,6 @@ import com.microsoft.azure.functions.annotation.FunctionName; import com.microsoft.azure.functions.annotation.HttpTrigger; import com.microsoft.azure.functions.sql.annotation.SQLOutput; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.function.Common.ProductUnsupportedTypes; import java.util.Optional; @@ -37,7 +34,7 @@ public HttpResponseMessage run( name = "product", commandText = "dbo.ProductsUnsupportedTypes", connectionStringSetting = "SqlConnectionString") - OutputBinding product) throws JsonMappingException, JsonProcessingException { + OutputBinding product) { ProductUnsupportedTypes p = new ProductUnsupportedTypes( 0, diff --git a/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java index 541df85d1..163c82336 100644 --- a/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java +++ b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java @@ -11,21 +11,21 @@ public class ProductUnsupportedTypes { @JsonProperty("ProductId") private int ProductId; - @JsonProperty("Text") - private String Text; - @JsonProperty("Ntext") - private String Ntext; - @JsonProperty("Image") - private String Image; + @JsonProperty("TextCol") + private String TextCol; + @JsonProperty("NtextCol") + private String NtextCol; + @JsonProperty("ImageCol") + private String ImageCol; public ProductUnsupportedTypes() { } - public ProductUnsupportedTypes(int productId, String text, String ntext, String image) { + public ProductUnsupportedTypes(int productId, String textCol, String ntextCol, String imageCol) { ProductId = productId; - Text = text; - Ntext = ntext; - Image = image; + TextCol = textCol; + NtextCol = ntextCol; + ImageCol = imageCol; } public int getProductId() { @@ -36,27 +36,27 @@ public void setProductId(int productId) { ProductId = productId; } - public String getText() { - return Text; + public String getTextCol() { + return TextCol; } - public void setText(String text) { - Text = text; + public void setTextCol(String textCol) { + TextCol = textCol; } - public String getNtext() { - return Ntext; + public String getNtextCol() { + return NtextCol; } - public void setNtext(String ntext) { - Ntext = ntext; + public void setNtextCol(String ntextCol) { + NtextCol = ntextCol; } - public String getImage() { - return Image; + public String getImageCol() { + return ImageCol; } - public void setImage(String image) { - Image = image; + public void setImageCol(String imageCol) { + ImageCol = imageCol; } } \ No newline at end of file diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/index.js b/test/Integration/test-js/AddProductUnsupportedTypes/index.js index 3337b7cdb..27fd65388 100644 --- a/test/Integration/test-js/AddProductUnsupportedTypes/index.js +++ b/test/Integration/test-js/AddProductUnsupportedTypes/index.js @@ -5,9 +5,9 @@ module.exports = async function (context, req) { context.bindings.product = { ProductId: 0, - Text: "test", - Ntext: "test", - Image: "dGVzdA==" + TextCol: "test", + NtextCol: "test", + ImageCol: "dGVzdA==" } return { diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 index a2a069e82..9794efb58 100644 --- a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 +++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 @@ -8,9 +8,9 @@ param($Request) $req_body = [ordered]@{ ProductId=0; - Text="test"; - Ntext="test"; - Image="dGVzdA=="; + TextCol="test"; + NtextCol="test"; + ImageCol="dGVzdA=="; } Push-OutputBinding -Name product -Value $req_body diff --git a/test/Integration/test-python/Common/productunsupportedtypes.py b/test/Integration/test-python/Common/productunsupportedtypes.py index cb349fd2d..5002c68c8 100644 --- a/test/Integration/test-python/Common/productunsupportedtypes.py +++ b/test/Integration/test-python/Common/productunsupportedtypes.py @@ -4,9 +4,9 @@ import collections class ProductUnsupportedTypes(collections.UserDict): - def __init__(self, productId, text, ntext, image): + def __init__(self, productId, textCol, ntextCol, imageCol): super().__init__() self['ProductId'] = productId - self['Text'] = text - self['Ntext'] = ntext - self['Image'] = image \ No newline at end of file + self['TextCol'] = textCol + self['NtextCol'] = ntextCol + self['ImageCol'] = imageCol \ No newline at end of file From 79aeb01dcef33c9aaf39281da790fd950de7aa00 Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Wed, 8 Feb 2023 09:28:31 -0800 Subject: [PATCH 6/7] fix tests --- test-outofproc/AddProductUnsupportedTypes.cs | 2 +- test/Integration/SqlOutputBindingIntegrationTests.cs | 2 +- test/Integration/test-csharp/AddProductUnsupportedTypes.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test-outofproc/AddProductUnsupportedTypes.cs b/test-outofproc/AddProductUnsupportedTypes.cs index 5001e9f1a..b6204f79f 100644 --- a/test-outofproc/AddProductUnsupportedTypes.cs +++ b/test-outofproc/AddProductUnsupportedTypes.cs @@ -14,7 +14,7 @@ public static class AddProductUnsupportedTypes /// This output binding should fail since the target table has unsupported column types. /// [Function("AddProductUnsupportedTypes")] - [SqlOutput("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] + [SqlOutput("dbo.ProductsUnsupportedTypes", "SqlConnectionString")] public static ProductUnsupportedTypes Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "addproduct-unsupportedtypes")] HttpRequest req) diff --git a/test/Integration/SqlOutputBindingIntegrationTests.cs b/test/Integration/SqlOutputBindingIntegrationTests.cs index 524827f53..fd4e27c9a 100644 --- a/test/Integration/SqlOutputBindingIntegrationTests.cs +++ b/test/Integration/SqlOutputBindingIntegrationTests.cs @@ -513,7 +513,7 @@ public async Task AddProductUnsupportedTypesTest(SupportedLanguages lang) var foundExpectedMessageSource = new TaskCompletionSource(); this.StartFunctionHost(nameof(AddProductUnsupportedTypes), lang, true, (object sender, DataReceivedEventArgs e) => { - if (e.Data.Contains("The type(s) of the following column(s) are not supported: Text, Ntext, Image. See https://github.com/Azure/azure-functions-sql-extension#output-bindings for more details.")) + if (e.Data.Contains("The type(s) of the following column(s) are not supported: TextCol, NtextCol, ImageCol. See https://github.com/Azure/azure-functions-sql-extension#output-bindings for more details.")) { foundExpectedMessageSource.SetResult(true); } diff --git a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs index dc14674d6..6f4b4ccbe 100644 --- a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs +++ b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs @@ -14,7 +14,7 @@ public static class AddProductUnsupportedTypes public static IActionResult Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "addproduct-unsupportedtypes")] HttpRequest req, - [Sql("dbo.ProductsUnsupportedTypes", ConnectionStringSetting = "SqlConnectionString")] out ProductUnsupportedTypes product) + [Sql("dbo.ProductsUnsupportedTypes", "SqlConnectionString")] out ProductUnsupportedTypes product) { product = new ProductUnsupportedTypes() { From 24a051c81a90cd1625a1c31687f4331288970944 Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Wed, 8 Feb 2023 09:47:48 -0800 Subject: [PATCH 7/7] simplify --- src/SqlAsyncCollector.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/SqlAsyncCollector.cs b/src/SqlAsyncCollector.cs index d6be3dbb8..fb4f7161b 100644 --- a/src/SqlAsyncCollector.cs +++ b/src/SqlAsyncCollector.cs @@ -57,7 +57,7 @@ public enum QueryType /// A user-defined POCO that represents a row of the user's table internal class SqlAsyncCollector : IAsyncCollector, IDisposable { - private static readonly string[] UnsupportedTypes = { "NTEXT", "TEXT", "IMAGE" }; + private static readonly string[] UnsupportedTypes = { "NTEXT(*)", "TEXT(*)", "IMAGE(*)" }; private const string RowDataParameter = "@rowData"; private const string ColumnName = "COLUMN_NAME"; private const string ColumnDefinition = "COLUMN_DEFINITION"; @@ -233,7 +233,7 @@ private async Task UpsertRowsAsync(IList rows, SqlAttribute attribute, IConfi } IEnumerable columnNamesFromItem = GetColumnNamesFromItem(rows.First()); - IEnumerable unsupportedColumns = columnNamesFromItem.Where(prop => IsUnsupportedType(prop, tableInfo.Columns)); + IEnumerable unsupportedColumns = columnNamesFromItem.Where(prop => UnsupportedTypes.Contains(tableInfo.Columns[prop], StringComparer.OrdinalIgnoreCase)); if (unsupportedColumns.Any()) { string message = $"The type(s) of the following column(s) are not supported: {string.Join(", ", unsupportedColumns.ToArray())}. See https://github.com/Azure/azure-functions-sql-extension#output-bindings for more details."; @@ -308,18 +308,6 @@ private async Task UpsertRowsAsync(IList rows, SqlAttribute attribute, IConfi } } - private static bool IsUnsupportedType(string property, IDictionary columns) - { - foreach (string unsupportedType in UnsupportedTypes) - { - if (columns[property].StartsWith(unsupportedType, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - return false; - } - /// /// Checks if any properties in T do not exist as columns in the table /// to upsert to and returns the extra property names in a List.