From 134d821b8658593c00f2456903731ca81edc4289 Mon Sep 17 00:00:00 2001 From: Zaid Ajaj Date: Fri, 11 Nov 2022 18:33:19 +0100 Subject: [PATCH] Add DictionaryInvokeArgs for dynamically constructing invoke input bag --- ...ucting-invoke-input-bag-of-properties.yaml | 4 ++ .../Resources/DictionaryInvokeArgsTests.cs | 47 +++++++++++++ sdk/dotnet/Pulumi/PublicAPI.Shipped.txt | 2 + .../Pulumi/Resources/DictionaryInvokeArgs.cs | 68 +++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 changelog/pending/20221111--sdk-dotnet--add-dictionaryinvokeargs-for-dynamically-constructing-invoke-input-bag-of-properties.yaml create mode 100644 sdk/dotnet/Pulumi.Tests/Resources/DictionaryInvokeArgsTests.cs create mode 100644 sdk/dotnet/Pulumi/Resources/DictionaryInvokeArgs.cs diff --git a/changelog/pending/20221111--sdk-dotnet--add-dictionaryinvokeargs-for-dynamically-constructing-invoke-input-bag-of-properties.yaml b/changelog/pending/20221111--sdk-dotnet--add-dictionaryinvokeargs-for-dynamically-constructing-invoke-input-bag-of-properties.yaml new file mode 100644 index 000000000000..43b36997c805 --- /dev/null +++ b/changelog/pending/20221111--sdk-dotnet--add-dictionaryinvokeargs-for-dynamically-constructing-invoke-input-bag-of-properties.yaml @@ -0,0 +1,4 @@ +changes: +- type: feat + scope: sdk/dotnet + description: Add DictionaryInvokeArgs for dynamically constructing invoke input bag of properties. diff --git a/sdk/dotnet/Pulumi.Tests/Resources/DictionaryInvokeArgsTests.cs b/sdk/dotnet/Pulumi.Tests/Resources/DictionaryInvokeArgsTests.cs new file mode 100644 index 000000000000..41fdb92c3a5e --- /dev/null +++ b/sdk/dotnet/Pulumi.Tests/Resources/DictionaryInvokeArgsTests.cs @@ -0,0 +1,47 @@ +// Copyright 2016-2021, Pulumi Corporation + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Xunit; + +namespace Pulumi.Tests.Resources +{ + public class DictionaryInvokeArgsTests + { + [Fact] + public void ConstructorValidValues() + { + try + { + var dict = new Dictionary + { + { "null", null }, + { "string", "foo" }, + { "int", 123 }, + { "dictionary", new Dictionary { {"foo", "bar"} }.ToImmutableDictionary() }, + { "output", Output.CreateSecret("secret") }, + }; + var dictionary = new DictionaryInvokeArgs(dict.ToImmutableDictionary()); + } + catch + { + Assert.True(false, "DictionaryInvokeArgs constructor should not throw an exception"); + } + } + + [Fact] + public void ConstructorInvalidValue() + { + var dict = new Dictionary + { + { "arbitrary", new { Foo = "bar" } }, + }; + + Assert.Throws(() => + { + new DictionaryInvokeArgs(dict.ToImmutableDictionary()); + }); + } + } +} diff --git a/sdk/dotnet/Pulumi/PublicAPI.Shipped.txt b/sdk/dotnet/Pulumi/PublicAPI.Shipped.txt index fa8c52b5998c..9355ea57b3df 100644 --- a/sdk/dotnet/Pulumi/PublicAPI.Shipped.txt +++ b/sdk/dotnet/Pulumi/PublicAPI.Shipped.txt @@ -83,6 +83,8 @@ Pulumi.CustomTimeouts.Update.get -> System.TimeSpan? Pulumi.CustomTimeouts.Update.set -> void Pulumi.DictionaryResourceArgs Pulumi.DictionaryResourceArgs.DictionaryResourceArgs(System.Collections.Immutable.ImmutableDictionary dictionary) -> void +Pulumi.DictionaryInvokeArgs +Pulumi.DictionaryInvokeArgs.DictionaryInvokeArgs(System.Collections.Immutable.ImmutableDictionary dictionary) -> void Pulumi.Deployment Pulumi.DeploymentInstance Pulumi.DeploymentInstance.Call(string token, Pulumi.CallArgs args, Pulumi.Resource self = null, Pulumi.CallOptions options = null) -> void diff --git a/sdk/dotnet/Pulumi/Resources/DictionaryInvokeArgs.cs b/sdk/dotnet/Pulumi/Resources/DictionaryInvokeArgs.cs new file mode 100644 index 000000000000..550304c556d4 --- /dev/null +++ b/sdk/dotnet/Pulumi/Resources/DictionaryInvokeArgs.cs @@ -0,0 +1,68 @@ +// Copyright 2016-2022, Pulumi Corporation + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi +{ + /// + /// A special type of with resource inputs represented + /// as a loosely-typed dictionary of objects. Normally, + /// should not be used by resource providers + /// since it's too low-level and provides low safety. Its target scenario are + /// resources with a very dynamic shape of inputs. + /// The input dictionary may only contain objects that are serializable by + /// Pulumi, i.e only the following types (or pulumi.Output of those types) are allowed: + /// + /// Primitive types: , , + /// , + /// , , or + /// + /// + /// + /// Generic collections of the above: + /// , + /// with keys, + /// + /// + public sealed class DictionaryInvokeArgs : InvokeArgs + { + private readonly ImmutableDictionary _dictionary; + + /// + /// Constructs an instance of from + /// a dictionary of input objects. + /// + /// The input dictionary. It may only contain objects + /// that are serializable by Pulumi. + public DictionaryInvokeArgs(ImmutableDictionary dictionary) + { + // Run a basic validation of types of values in the dictionary + var seenTypes = new HashSet(); + foreach (var value in dictionary.Values) + { + if (value == null) continue; + + var targetType = value.GetType(); + if (value is IOutput) + { + var type = value.GetType(); + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Output<>)) + { + targetType = type.GenericTypeArguments[0]; + } + } + + Converter.CheckTargetType(nameof(dictionary), targetType, seenTypes); + } + + _dictionary = dictionary; + } + + internal override Task> ToDictionaryAsync() + => Task.FromResult(_dictionary); + } +}