diff --git a/experiments/Azure.Experiments/Azure.Experiments/CreateOperation.cs b/experiments/Azure.Experiments/Azure.Experiments/CreateOperation.cs new file mode 100644 index 000000000000..16ad08e88be7 --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments/CreateOperation.cs @@ -0,0 +1,50 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.Azure.Experiments +{ + public sealed class CreateOperation + { + public IEnumerable Dependencies { get; } + + public CreateOperation(IEnumerable dependencies) + { + Dependencies = dependencies; + } + + public static CreateOperation Create(IState state, IResourceConfig config) + where Config : class + => new Visitor(state).Get(config); + + sealed class Visitor : IResourceConfigVisitor + { + public CreateOperation Get(IResourceConfig config) + => Map.GetOrAdd(config, _ => config.Apply(this)); + + public CreateOperation Visit(ResourceConfig config) where Config : class + { + var info = State.Get(config); + return info == null + ? new CreateOperation(config.Dependencies.Select(d => Get(d))) + : null; + } + + public CreateOperation Visit( + NestedResourceConfig config) + where Config : class + where ParentConfig : class + => Get(config.Parent); + + public Visitor(IState state) + { + State = state; + } + + IState State { get; } + + ConcurrentDictionary Map { get; } + = new ConcurrentDictionary(); + } + } +} diff --git a/experiments/Azure.Experiments/Azure.Experiments/StateLocation.cs b/experiments/Azure.Experiments/Azure.Experiments/StateLocation.cs new file mode 100644 index 000000000000..ad2e51d157bb --- /dev/null +++ b/experiments/Azure.Experiments/Azure.Experiments/StateLocation.cs @@ -0,0 +1,74 @@ +using Microsoft.Azure.Management.ResourceManager.Models; +using System.Linq; + +namespace Microsoft.Azure.Experiments +{ + public static class StateLocation + { + public static string GetLocation(this IState state, IResourceConfig config) + => config.Apply(new Visitor(state))?.Location; + + class DependencyLocation + { + public string Location { get; } + + public bool IsCompulsory { get; } + + public DependencyLocation(string location, bool isCompulsory) + { + Location = location; + IsCompulsory = isCompulsory; + } + } + + static DependencyLocation Merge(this DependencyLocation a, DependencyLocation b) + { + if (a == null) + { + return b; + } + if (b == null) + { + return a; + } + + if (a.IsCompulsory != b.IsCompulsory) + { + return a.IsCompulsory ? b : a; + } + + // a.IsCompulsory == b.IsCompulsory + return a.Location == b.Location ? a : new DependencyLocation(null, a.IsCompulsory); + } + + sealed class Visitor : IResourceConfigVisitor + { + public DependencyLocation Visit(ResourceConfig config) + where Config : class + { + var info = State.Get(config); + return info != null + ? new DependencyLocation( + config.Policy.GetLocation(info), + typeof(Config) != typeof(ResourceGroup)) + : config + .Dependencies + .Select(c => c.Apply(this)) + .Aggregate((DependencyLocation)null, Merge); + } + + public DependencyLocation Visit( + NestedResourceConfig config) + where Config : class + where ParentConfig : class + => config.Parent.Apply(this); + + public Visitor(IState state) + { + State = state; + } + + IState State { get; } + } + } +}